diff --git a/MagickCore/ImageMagick.h b/MagickCore/ImageMagick.h
new file mode 100644
index 0000000..622329c
--- /dev/null
+++ b/MagickCore/ImageMagick.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  Deprecated as of ImageMagick 6.2.3.
+
+  MagickCore Application Programming Interface declarations.
+*/
+
+#ifndef _MAGICKCORE_IMAGEMAGICK_DEPRECATED_H
+#define _MAGICKCORE_IMAGEMAGICK_DEPRECATED_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "magick/MagickCore.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/ImageMagick.ico b/MagickCore/ImageMagick.ico
new file mode 100644
index 0000000..09def8c
--- /dev/null
+++ b/MagickCore/ImageMagick.ico
Binary files differ
diff --git a/MagickCore/ImageMagick.pc b/MagickCore/ImageMagick.pc
new file mode 100644
index 0000000..d6922a9
--- /dev/null
+++ b/MagickCore/ImageMagick.pc
@@ -0,0 +1,10 @@
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/ImageMagick
+
+Name: ImageMagick
+Description: ImageMagick - Convert, Edit, and Compose Images
+Version: 6.7.1
+Libs: -L${libdir} -lMagickCore
+Cflags: -I${includedir} -fopenmp
diff --git a/MagickCore/ImageMagick.pc.in b/MagickCore/ImageMagick.pc.in
new file mode 100644
index 0000000..f584ef5
--- /dev/null
+++ b/MagickCore/ImageMagick.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/ImageMagick
+
+Name: ImageMagick
+Description: ImageMagick - Convert, Edit, and Compose Images
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lMagickCore
+Cflags: -I${includedir} @MAGICK_PCFLAGS@
diff --git a/MagickCore/ImageMagick.rc b/MagickCore/ImageMagick.rc
new file mode 100644
index 0000000..b1cfaf3
--- /dev/null
+++ b/MagickCore/ImageMagick.rc
@@ -0,0 +1,71 @@
+#include "winver.h"
+#define __WINDOWS__
+#include "magick-config.h"
+#include "version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+/////////////////////////////////////////////////////////////////////////////
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MagickLibVersionNumber
+ PRODUCTVERSION MagickLibVersionNumber
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "ProductName", "ImageMagick\0"
+            VALUE "FileDescription", "ImageMagick Studio library and utility programs\0"
+            VALUE "OriginalFilename", "ImageMagick\0"
+            VALUE "InternalName", "ImageMagick\0"
+            VALUE "FileVersion", MagickLibVersionText "\0"
+            VALUE "ProductVersion", MagickLibVersionText "\0"
+            VALUE "CompanyName", "ImageMagick Studio\0"
+            VALUE "LegalCopyright", MagickCopyright "\0"
+            VALUE "Comments", MagickVersion "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// IMAGEMAGICK
+//
+/////////////////////////////////////////////////////////////////////////////
+
+CODER.XML      IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\coder.xml"
+COLORS.XML     IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\colors.xml"
+CONFIGURE.XML     IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\configure.xml"
+DELEGATES.XML  IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\delegates.xml"
+ENGLISH.XML    IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\english.xml"
+LOCALE.XML     IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\locale.xml"
+LOG.XML        IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\log.xml"
+MAGIC.XML      IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\magic.xml"
+THRESHOLDS.XML  IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\thresholds.xml"
+TYPE.XML       IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\type.xml"
+TYPE-GHOSTSCRIPT.XML  IMAGEMAGICK DISCARDABLE "..\\VisualMagick\\bin\\type-ghostscript.xml"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+/////////////////////////////////////////////////////////////////////////////
+
+IDR_MAGICKICON          ICON    DISCARDABLE     "ImageMagick.ico"
diff --git a/MagickCore/Magick-config b/MagickCore/Magick-config
new file mode 100755
index 0000000..ea8b4c9
--- /dev/null
+++ b/MagickCore/Magick-config
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# Configure options script for re-calling MagickCore compilation options
+# required to use the MagickCore library.
+#
+
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/ImageMagick
+
+usage="\
+Usage: Magick-config [--cflags] [--cppflags] [--exec-prefix] [--ldflags] [--libs] [--prefix] [--version]"
+
+if test $# -eq 0; then
+      echo "${usage}" 1>&2
+      echo "Example: gcc \`Magick-config --cflags --cppflags\` -o core core.c \`Magick-config --ldflags --libs\`" 1>&2
+      exit 1
+fi
+
+while test $# -gt 0; do
+  case "$1" in
+    -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+    *) optarg= ;;
+  esac
+  case $1 in
+    --prefix=*)
+      prefix=$optarg
+      ;;
+    --prefix)
+      echo $prefix
+      ;;
+    --exec-prefix=*)
+      exec_prefix=$optarg
+      ;;
+    --exec-prefix)
+      echo $exec_prefix
+      ;;
+    --version)
+      echo '6.7.1 Q16 '
+      ;;
+    --cflags)
+      echo "-I${includedir} -fopenmp"
+      ;;
+    --cxxflags)
+      echo '-g -O2 -pthread'
+      ;;
+    --cppflags)
+      echo '-I/usr/local/include/ImageMagick'
+      ;;
+    --ldflags)
+      echo '-L/usr/local/lib '
+      ;;
+    --libs)
+      echo "-L${libdir} -lMagickCore -llcms2 -ltiff -lfreetype -ljasper -ljpeg -lpng -lfontconfig -lXext -lXt -lSM -lICE -lX11 -llzma -lbz2 -lxml2 -lgvc -lgraph -lcdt -lz -lm -lgomp -lpthread -lltdl"
+      ;;
+    *)
+      echo "${usage}" 1>&2
+      exit 1
+      ;;
+  esac
+  shift
+done
diff --git a/MagickCore/Magick-config.1 b/MagickCore/Magick-config.1
new file mode 100644
index 0000000..5c2bc2a
--- /dev/null
+++ b/MagickCore/Magick-config.1
@@ -0,0 +1,69 @@
+.ad l
+.nh
+.TH Magick-Config 1 "2 May 2002" "ImageMagick"
+.SH NAME
+Magick-config \- get information about the installed version of ImageMagick
+.SH SYNOPSIS
+.B Magick-config 
+.B [--cflags]
+.B [--cppflags]
+.B [--exec-prefix]
+.B [--ldflags]
+.B [--libs]
+.B [--prefix]
+.B [--version]
+.SH DESCRIPTION
+.B Magick-config
+prints the compiler and linker flags required to compile and link programs
+that use the
+.BR ImageMagick
+Application Programmer Interface.
+.SH EXAMPLES
+To print the version of the installed distribution of
+.BR ImageMagick ,
+use:
+
+.nf
+  Magick-config \-\-version
+.fi
+  
+To compile a program that calls the 
+.BR ImageMagick
+Application Programmer Interface, use:
+
+.nf
+  cc `Magick-config \-\-cflags \-\-cppflags \-\-ldflags \-\-libs` program.c
+.fi
+
+.SH OPTIONS
+.TP
+.B \-\-cflags
+Print the compiler flags that were used to compile 
+.BR libMagick .
+.TP
+.B \-\-cppflags
+Print the preprocessor flags that are needed to find the
+.B ImageMagick
+C include files and defines to ensure that the ImageMagick data structures match between
+your program and the installed libraries.
+.TP
+.B \-\-exec-prefix
+Print the directory under which target specific binaries and executables are installed.
+.TP
+.B \-\-ldflags
+Print the linker flags that are needed to link with the
+.B ImageMagick
+library.
+.TP
+.B \-\-libs
+Print the linker flags that are needed to link a program with
+.BR libMagick .
+.TP
+.B \-\-version
+Print the version of the
+.B ImageMagick
+distribution to standard output.
+.SH LICENSE
+See http://www.imagemagick.org/script/license.php.
+.SH AUTHORS
+John Cristy, ImageMagick Studio LLC
diff --git a/MagickCore/MagickCore-config.1 b/MagickCore/MagickCore-config.1
new file mode 100644
index 0000000..f58e957
--- /dev/null
+++ b/MagickCore/MagickCore-config.1
@@ -0,0 +1,69 @@
+.ad l
+.nh
+.TH MagickCore-Config 1 "2 May 2002" "ImageMagick"
+.SH NAME
+MagickCore-config \- get information about the installed version of ImageMagick
+.SH SYNOPSIS
+.B MagickCore-config 
+.B [--cflags]
+.B [--cppflags]
+.B [--exec-prefix]
+.B [--ldflags]
+.B [--libs]
+.B [--prefix]
+.B [--version]
+.SH DESCRIPTION
+.B MagickCore-config
+prints the compiler and linker flags required to compile and link programs
+that use the
+.BR ImageMagick
+Application Programmer Interface.
+.SH EXAMPLES
+To print the version of the installed distribution of
+.BR ImageMagick ,
+use:
+
+.nf
+  MagickCore-config \-\-version
+.fi
+  
+To compile a program that calls the 
+.BR ImageMagick
+Application Programmer Interface, use:
+
+.nf
+  cc `MagickCore-config \-\-cflags \-\-cppflags \-\-ldflags \-\-libs` program.c
+.fi
+
+.SH OPTIONS
+.TP
+.B \-\-cflags
+Print the compiler flags that were used to compile 
+.BR libMagick .
+.TP
+.B \-\-cppflags
+Print the preprocessor flags that are needed to find the
+.B ImageMagick
+C include files and defines to ensure that the ImageMagick data structures match between
+your program and the installed libraries.
+.TP
+.B \-\-exec-prefix
+Print the directory under which target specific binaries and executables are installed.
+.TP
+.B \-\-ldflags
+Print the linker flags that are needed to link with the
+.B ImageMagick
+library.
+.TP
+.B \-\-libs
+Print the linker flags that are needed to link a program with
+.BR libMagick .
+.TP
+.B \-\-version
+Print the version of the
+.B ImageMagick
+distribution to standard output.
+.SH LICENSE
+See http://www.imagemagick.org/script/license.php.
+.SH AUTHORS
+John Cristy, ImageMagick Studio LLC
diff --git a/MagickCore/MagickCore-config.in b/MagickCore/MagickCore-config.in
new file mode 100644
index 0000000..6020f8b
--- /dev/null
+++ b/MagickCore/MagickCore-config.in
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Configure options script for re-calling MagickCore compilation options
+# required to use the MagickCore library.
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/ImageMagick
+
+usage="\
+Usage: MagickCore-config [--cflags] [--cppflags] [--exec-prefix] [--ldflags] [--libs] [--prefix] [--version]"
+
+if test $# -eq 0; then
+      echo "${usage}" 1>&2
+      echo "Example: gcc \`MagickCore-config --cflags --cppflags\` -o core core.c \`Magick-config --ldflags --libs\`" 1>&2
+      exit 1
+fi
+
+while test $# -gt 0; do
+  case "$1" in
+    -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+    *) optarg= ;;
+  esac
+  case $1 in
+    --prefix=*)
+      prefix=$optarg
+      ;;
+    --prefix)
+      echo $prefix
+      ;;
+    --exec-prefix=*)
+      exec_prefix=$optarg
+      ;;
+    --exec-prefix)
+      echo $exec_prefix
+      ;;
+    --version)
+      echo '@PACKAGE_VERSION@ Q@QUANTUM_DEPTH@ @MAGICK_HDRI@'
+      ;;
+    --cflags)
+      echo "-I${includedir} @MAGICK_PCFLAGS@"
+      ;;
+    --cxxflags)
+      echo '@MAGICK_CXXFLAGS@'
+      ;;
+    --cppflags)
+      echo '@MAGICK_CPPFLAGS@'
+      ;;
+    --ldflags)
+      echo '@MAGICK_LDFLAGS@'
+      ;;
+    --libs)
+      echo "-L${libdir} @MAGICK_LIBS@"
+      ;;
+    --coder-path)
+      echo "@CODER_PATH@"
+      ;;
+    --filter-path)
+      echo "@FILTER_PATH@"
+      ;;
+    *)
+      echo "${usage}" 1>&2
+      exit 1
+      ;;
+  esac
+  shift
+done
diff --git a/MagickCore/MagickCore.h b/MagickCore/MagickCore.h
new file mode 100644
index 0000000..1cf4ed3
--- /dev/null
+++ b/MagickCore/MagickCore.h
@@ -0,0 +1,214 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore Application Programming Interface declarations.
+*/
+
+#ifndef _MAGICKCORE_CORE_H
+#define _MAGICKCORE_CORE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if !defined(_MAGICKCORE_CONFIG_H)
+# define _MAGICKCORE_CONFIG_H
+# if !defined(vms) && !defined(macintosh)
+#  include "MagickCore/magick-config.h"
+# else
+#  include "magick-config.h"
+# endif
+#if defined(_magickcore_const) && !defined(const)
+# define const _magickcore_const
+#endif
+#if defined(_magickcore_inline) && !defined(inline)
+# define inline _magickcore_inline
+#endif
+#if defined(_magickcore_restrict) && !defined(restrict)
+# define restrict  _magickcore_restrict
+#endif
+# if defined(__cplusplus) || defined(c_plusplus)
+#  undef inline
+# endif
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#if defined(WIN32) || defined(WIN64)
+#  define MAGICKCORE_WINDOWS_SUPPORT
+#else
+#  define MAGICKCORE_POSIX_SUPPORT
+#endif 
+
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__CYGWIN__) && !defined(__MINGW32__)
+# if defined(_MT) && defined(_DLL) && !defined(_MAGICKDLL_) && !defined(_LIB) && !defined(MAGICK_STATIC_LINK)
+#  define _MAGICKDLL_
+# endif
+# if defined(_MAGICKDLL_)
+#  if defined(_VISUALC_)
+#   pragma warning( disable: 4273 )  /* Disable the dll linkage warnings */
+#  endif
+#  if !defined(_MAGICKLIB_)
+#   define MagickExport  __declspec(dllimport)
+#   if defined(_VISUALC_)
+#    pragma message( "Magick lib DLL import interface" )
+#   endif
+#  else
+#   define MagickExport  __declspec(dllexport)
+#   if defined(_VISUALC_)
+#    pragma message( "Magick lib DLL export interface" )
+#   endif
+#  endif
+# else
+#  define MagickExport
+#  if defined(_VISUALC_)
+#   pragma message( "Magick lib static interface" )
+#  endif
+# endif
+
+# if defined(_DLL) && !defined(_LIB)
+#  define ModuleExport  __declspec(dllexport)
+#  if defined(_VISUALC_)
+#   pragma message( "Magick module DLL export interface" )
+#  endif
+# else
+#  define ModuleExport
+#  if defined(_VISUALC_)
+#   pragma message( "Magick module static interface" )
+#  endif
+
+# endif
+# define MagickGlobal __declspec(thread)
+# if defined(_VISUALC_)
+#  pragma warning(disable : 4018)
+#  pragma warning(disable : 4244)
+#  pragma warning(disable : 4142)
+#  pragma warning(disable : 4800)
+#  pragma warning(disable : 4786)
+#  pragma warning(disable : 4996)
+# endif
+#else
+# define MagickExport
+# define ModuleExport
+# define MagickGlobal
+#endif
+
+#if !defined(MaxTextExtent)
+#  define MaxTextExtent  4096
+#endif
+#define MagickSignature  0xabacadabUL
+
+#if !defined(magick_attribute)
+#  if !defined(__GNUC__)
+#    define magick_attribute(x)  /* nothing */
+#  else
+#    define magick_attribute  __attribute__
+#  endif
+#endif
+
+#if defined(MAGICKCORE_NAMESPACE_PREFIX)
+# include "MagickCore/methods.h"
+#endif
+#include "MagickCore/magick-type.h"
+#include "MagickCore/accelerate.h"
+#include "MagickCore/animate.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/cipher.h"
+#include "MagickCore/client.h"
+#include "MagickCore/coder.h"
+#include "MagickCore/color.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/compare.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/compress.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/display.h"
+#include "MagickCore/distort.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/feature.h"
+#include "MagickCore/fourier.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/identify.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-view.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/matrix.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/mime.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/morphology.h"
+#include "MagickCore/option.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/prepress.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/signature.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/token.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/type.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#include "MagickCore/xml-tree.h"
+#include "MagickCore/xwindow.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/MagickCore.pc.in b/MagickCore/MagickCore.pc.in
new file mode 100644
index 0000000..6b062d7
--- /dev/null
+++ b/MagickCore/MagickCore.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/ImageMagick
+
+Name: MagickCore
+Description: MagickCore - C API for ImageMagick
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lMagickCore
+Cflags: -I${includedir} @MAGICK_PCFLAGS@
diff --git a/MagickCore/Make.com b/MagickCore/Make.com
new file mode 100644
index 0000000..62aee94
--- /dev/null
+++ b/MagickCore/Make.com
@@ -0,0 +1,181 @@
+$!
+$! Make ImageMagick image utilities for VMS.
+$!
+$ define/nolog MAGICK [-.magick]
+$ define/nolog WAND [-.wand]
+$ copy config.h_vms magick-config.h
+$ copy xwdfile.h_vms xwdfile.h
+$
+$if (f$trnlnm("X11") .eqs. "") then define/nolog X11 decw$include:
+$compile_options="/nodebug/optimize"
+$if (f$search("sys$system:decc$compiler.exe") .nes. "") 
+$then     ! VAX with DEC C
+$  compile_options="/decc/nodebug/optimize/warning=(disable=rightshiftovr)"
+$else     ! VAX with VAX C
+$define/nolog lnk$library sys$library:vaxcrtl
+$define/nolog sys sys$share
+$endif
+$if (f$getsyi("HW_MODEL") .gt. 1023)
+$then     ! Alpha with DEC C
+$  define/nolog sys decc$library_include
+$  compile_options="/nodebug/optimize/prefix=all/warning=(disable=rightshiftovr)/name=(as_is,short)/float=ieee
+$endif
+$
+$write sys$output "Making Magick..."
+$call Make accelerate.c
+$call Make animate.c
+$call Make annotate.c
+$call Make artifact.c
+$call Make attribute.c
+$call Make blob.c
+$call Make cache.c
+$call Make cache-view.c
+$call Make cipher.c
+$call Make client.c
+$call Make coder.c
+$call Make color.c
+$call Make colormap.c
+$call Make colorspace.c
+$call Make compare.c
+$call Make composite.c
+$call Make compress.c
+$call Make configure.c
+$call Make constitute.c
+$call Make decorate.c
+$call Make delegate.c
+$call Make deprecate.c
+$call Make display.c
+$call Make distort.c
+$call Make draw.c
+$call Make effect.c
+$call Make enhance.c
+$call Make exception.c
+$call Make feature.c
+$call Make fourier.c
+$call Make fx.c
+$call Make gem.c
+$call Make geometry.c
+$call Make hashmap.c
+$call Make histogram.c
+$call Make identify.c
+$call Make image.c
+$call Make image-view.c
+$call Make layer.c
+$call Make list.c
+$call Make locale.c
+$call Make log.c
+$call Make magic.c
+$call Make magick.c
+$call Make matrix.c
+$call Make memory.c
+$call Make mime.c
+$call Make module.c
+$call Make monitor.c
+$call Make montage.c
+$call Make morphology.c
+$call Make option.c
+$call Make paint.c
+$call Make pixel.c
+$call Make policy.c
+$call Make prepress.c
+$call Make property.c
+$call Make PreRvIcccm.c
+$call Make profile.c
+$call Make quantize.c
+$call Make quantum.c
+$call Make quantum-export.c
+$call Make quantum-import.c
+$call Make random.c
+$call Make registry.c
+$call Make resample.c
+$call Make resize.c
+$call Make resource.c
+$call Make segment.c
+$call Make semaphore.c
+$call Make shear.c
+$call Make signature.c
+$call Make splay-tree.c
+$call Make static.c
+$call Make statistic.c
+$call Make stream.c
+$call Make string.c
+$call Make thread.c
+$call Make timer.c
+$call Make token.c
+$call Make transform.c
+$call Make threshold.c
+$call Make type.c
+$call Make utility.c
+$call Make version.c
+$call Make vms.c
+$call Make widget.c
+$call Make xml-tree.c
+$call Make xwindow.c
+$ set default [-.filters]
+$ call Make analyze.c
+$ set default [-.wand]
+$ call Make drawing-wand.c
+$ call Make pixel-wand.c
+$ call Make wand-view.c
+$ call Make conjure.c
+$ call Make convert.c
+$ call Make import.c
+$ call Make mogrify.c
+$ copy animate.c animate-wand.c
+$ call make animate-wand.c
+$ copy compare.c compare-wand.c
+$ call make compare-wand.c
+$ copy composite.c composite-wand.c
+$ call make composite-wand.c
+$ copy display.c display-wand.c
+$ call make display-wand.c
+$ copy identify.c identify-wand.c
+$ call make identify-wand.c
+$ copy montage.c montage-wand.c
+$ call make montage-wand.c
+$ set default [-.magick]
+$ deass magick
+$ deass wand
+$library/create libMagick.olb -
+  accelerate, animate, annotate, artifact, attribute, blob, cache, cache-view, -
+  cipher, client, coder, color, colormap, colorspace, compare, composite, -
+  compress, configure, constitute, decorate, delegate, deprecate, display, -
+  distort, draw, effect, enhance, exception, feature, fourier, fx, gem, -
+  geometry, hashmap, histogram, identify, image, image-view, layer, list, -
+  locale, log, magic, magick, matrix, memory, mime, module, monitor, montage, -
+  morphology, option, paint, pixel, PreRvIcccm, profile, quantize, quantum, -
+  quantum-export, quantum-import,random, registry, resample, resize, resource, -
+  segment, semaphore, shear, signature, splay-tree, static, stream, string, -
+  thread, timer, token, transform, threshold, type, utility, version, vms, -
+  widget, xwindow, statistic, policy, prepress, property, xml-tree, -
+	[-.filters]analyze,[-.wand]drawing-wand, pixel-wand, wand-view, conjure, -
+  convert,import, mogrify, animate-wand, compare-wand, composite-wand, -
+  display-wand,identify-wand,montage-wand
+$exit
+$
+$Make: subroutine
+$!
+$! Primitive MMS hack for DCL.
+$!
+$if (p1 .eqs. "") then exit
+$source_file=f$search(f$parse(p1,".c"))
+$if (source_file .nes. "")
+$then
+$  object_file=f$parse(source_file,,,"name")+".obj"
+$  object_file=f$search( object_file )
+$  if (object_file .nes. "")
+$  then
+$    object_time=f$file_attribute(object_file,"cdt")
+$    source_time=f$file_attribute(source_file,"cdt")
+$    if (f$cvtime(object_time) .lts. f$cvtime(source_time)) then -
+$      object_file=""
+$  endif
+$  if (object_file .eqs. "")
+$  then
+$    write sys$output "Compiling ",p1
+$    cc'compile_options'/include_directory=([-],[-.magick],[-.jpeg],[-.png], -
+       [-.tiff],[-.ttf],[-.zlib]) 'source_file'  
+$  endif
+$endif
+$exit
+$endsubroutine
diff --git a/MagickCore/Makefile.am b/MagickCore/Makefile.am
new file mode 100644
index 0000000..e4b326c
--- /dev/null
+++ b/MagickCore/Makefile.am
@@ -0,0 +1,429 @@
+#  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+#  dedicated to making software imaging solutions freely available.
+#
+#  You may not use this file except in compliance with the License.  You may
+#  obtain a copy of the License at
+#
+#    http://www.imagemagick.org/script/license.php
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  Makefile for building the MagickCore API.
+# 
+
+MagickCoreincdir = $(topincludedir)/MagickCore
+
+# Headers which are installed
+MagickCoreinc_HEADERS = \
+	$(MAGICKCORE_INCLUDE_HDRS)
+
+MAGICKCORE_BIN_SCRPTS = \
+  MagickCore/MagickCore-config
+
+MAGICKCORE_PKGCONFIG = \
+  MagickCore/ImageMagick.pc \
+  MagickCore/MagickCore.pc
+
+OSX_GCOV_LDFLAG = @OSX_GCOV_LDFLAG@
+
+MAGICKCORE_MANS = \
+  MagickCore/MagickCore-config.1
+
+MAGICKCORE_LIBS = MagickCore/libMagickCore.la
+
+if WITH_MODULES
+MagickCore_libMagickCore_la_SOURCES = $(MAGICKCORE_BASE_SRCS) $(MAGICKCORE_PLATFORM_SRCS)
+MagickCore_libMagickCore_la_LIBADD = $(MAGICK_DEP_LIBS) $(MAGICK_LIBLTDL)
+else
+MagickCore_libMagickCore_la_SOURCES = $(MAGICKCORE_BASE_SRCS) $(MAGICKCORE_PLATFORM_SRCS) $(MAGICKCORE_CODER_SRCS) $(MAGICKCORE_FILTER_SRCS)
+MagickCore_libMagickCore_la_LIBADD = $(MAGICK_DEP_LIBS) $(MAGICK_LIBLTDL)
+endif # WITH_MODULES
+MagickCore_libMagickCore_la_CPPFLAGS = -I$(top_builddir)/ltdl -I$(top_srcdir)/ltdl $(LIBRARY_EXTRA_CPPFLAGS)
+MagickCore_libMagickCore_la_LDFLAGS = -no-undefined -export-symbols-regex ".*" \
+  $(OSX_GCOV_LDFLAG) -version-info \
+  $(MAGICK_LIBRARY_CURRENT):$(MAGICK_LIBRARY_REVISION):$(MAGICK_LIBRARY_AGE)
+MagickCore_libMagickCore_la_DEPENDENCIES = $(MAGICKCORE_LTDLDEPS)
+
+# Library base sources
+MAGICKCORE_BASE_SRCS = \
+	MagickCore/MagickCore.h \
+	MagickCore/accelerate.c \
+	MagickCore/accelerate.h \
+	MagickCore/animate.c \
+	MagickCore/animate.h \
+	MagickCore/animate-private.h \
+	MagickCore/annotate.c \
+	MagickCore/annotate.h \
+	MagickCore/artifact.c \
+	MagickCore/artifact.h \
+	MagickCore/attribute.c \
+	MagickCore/attribute.h \
+	MagickCore/blob.c \
+	MagickCore/blob.h \
+	MagickCore/blob-private.h \
+	MagickCore/cache.c \
+	MagickCore/cache.h \
+	MagickCore/cache-private.h \
+	MagickCore/cache-view.c \
+	MagickCore/cache-view.h \
+	MagickCore/cipher.c \
+	MagickCore/cipher.h \
+	MagickCore/client.c \
+	MagickCore/client.h \
+	MagickCore/coder.c \
+	MagickCore/coder.h \
+	MagickCore/color.c \
+	MagickCore/color.h \
+	MagickCore/color-private.h \
+	MagickCore/colormap.c \
+	MagickCore/colormap.h \
+	MagickCore/colormap-private.h \
+	MagickCore/colorspace.c \
+	MagickCore/colorspace.h \
+	MagickCore/colorspace-private.h \
+	MagickCore/compare.c \
+	MagickCore/compare.h \
+	MagickCore/composite.c \
+	MagickCore/composite.h \
+	MagickCore/composite-private.h \
+	MagickCore/compress.c \
+	MagickCore/compress.h \
+	MagickCore/configure.c \
+	MagickCore/configure.h \
+	MagickCore/constitute.c \
+	MagickCore/constitute.h \
+	MagickCore/decorate.c \
+	MagickCore/decorate.h \
+	MagickCore/delegate.c \
+	MagickCore/delegate.h \
+	MagickCore/delegate-private.h \
+	MagickCore/deprecate.c \
+	MagickCore/deprecate.h \
+	MagickCore/display.c \
+	MagickCore/display.h \
+	MagickCore/display-private.h \
+	MagickCore/distort.c \
+	MagickCore/distort.h \
+	MagickCore/draw.c \
+	MagickCore/draw.h \
+	MagickCore/draw-private.h \
+	MagickCore/effect.c \
+	MagickCore/effect.h \
+	MagickCore/enhance.c \
+	MagickCore/enhance.h \
+	MagickCore/exception.c \
+	MagickCore/exception.h \
+	MagickCore/exception-private.h \
+	MagickCore/feature.c \
+	MagickCore/feature.h \
+	MagickCore/fourier.c \
+	MagickCore/fourier.h \
+	MagickCore/fx.c \
+	MagickCore/fx.h \
+	MagickCore/fx-private.h \
+	MagickCore/gem.c \
+	MagickCore/gem.h \
+	MagickCore/geometry.c \
+	MagickCore/geometry.h \
+	MagickCore/hashmap.c \
+	MagickCore/hashmap.h \
+	MagickCore/histogram.c \
+	MagickCore/histogram.h \
+	MagickCore/identify.c \
+	MagickCore/identify.h \
+	MagickCore/image.c \
+	MagickCore/image.h \
+	MagickCore/image-private.h \
+	MagickCore/image-view.c \
+	MagickCore/image-view.h \
+	MagickCore/layer.c \
+	MagickCore/layer.h \
+	MagickCore/list.c \
+	MagickCore/list.h \
+	MagickCore/locale.c \
+	MagickCore/locale_.h \
+	MagickCore/log.c \
+	MagickCore/log.h \
+	MagickCore/mac.h \
+	MagickCore/magic.c \
+	MagickCore/magic.h \
+	MagickCore/magick.c \
+	MagickCore/magick-config.h \
+	MagickCore/magick-type.h \
+	MagickCore/magick.h \
+	MagickCore/matrix.c \
+	MagickCore/matrix.h \
+	MagickCore/memory.c \
+	MagickCore/memory_.h \
+	MagickCore/methods.h \
+	MagickCore/mime.c \
+	MagickCore/mime.h \
+	MagickCore/module.c \
+	MagickCore/module.h \
+	MagickCore/monitor.c \
+	MagickCore/monitor.h \
+	MagickCore/monitor-private.h \
+	MagickCore/montage.c \
+	MagickCore/montage.h \
+	MagickCore/morphology.c \
+	MagickCore/morphology.h \
+	MagickCore/morphology-private.h \
+	MagickCore/nt-base.h \
+	MagickCore/nt-feature.h \
+	MagickCore/option.c \
+	MagickCore/option.h \
+	MagickCore/paint.c \
+	MagickCore/paint.h \
+	MagickCore/pixel.c \
+	MagickCore/pixel.h \
+	MagickCore/pixel-accessor.h \
+	MagickCore/policy.c \
+	MagickCore/policy.h \
+	MagickCore/PreRvIcccm.c \
+	MagickCore/PreRvIcccm.h \
+	MagickCore/prepress.c \
+	MagickCore/prepress.h \
+	MagickCore/property.c \
+	MagickCore/property.h \
+	MagickCore/profile.c \
+	MagickCore/profile.h \
+	MagickCore/quantize.c \
+	MagickCore/quantize.h \
+	MagickCore/quantum.c \
+	MagickCore/quantum.h \
+	MagickCore/quantum-export.c \
+	MagickCore/quantum-import.c \
+	MagickCore/quantum-private.h \
+	MagickCore/random.c \
+	MagickCore/random_.h \
+	MagickCore/random-private.h \
+	MagickCore/registry.c \
+	MagickCore/registry.h \
+	MagickCore/resample.c \
+	MagickCore/resample.h \
+	MagickCore/resample-private.h \
+	MagickCore/resize.c \
+	MagickCore/resize.h \
+	MagickCore/resize-private.h \
+	MagickCore/resource.c \
+	MagickCore/resource_.h \
+	MagickCore/segment.c \
+	MagickCore/segment.h \
+	MagickCore/semaphore.c \
+	MagickCore/semaphore.h \
+	MagickCore/semaphore-private.h \
+	MagickCore/shear.c \
+	MagickCore/shear.h \
+	MagickCore/signature.c \
+	MagickCore/signature.h \
+	MagickCore/signature-private.h \
+	MagickCore/splay-tree.c \
+	MagickCore/splay-tree.h \
+	MagickCore/static.c \
+	MagickCore/static.h \
+	MagickCore/statistic.c \
+	MagickCore/statistic.h \
+	MagickCore/stream.c \
+	MagickCore/stream.h \
+	MagickCore/stream-private.h \
+	MagickCore/string.c \
+	MagickCore/string_.h \
+	MagickCore/string-private.h \
+	MagickCore/studio.h \
+	MagickCore/thread.c \
+	MagickCore/thread_.h \
+	MagickCore/thread-private.h \
+	MagickCore/timer.c \
+	MagickCore/timer.h \
+	MagickCore/token.c \
+	MagickCore/token.h \
+	MagickCore/token-private.h \
+	MagickCore/transform.c \
+	MagickCore/transform.h \
+	MagickCore/threshold.c \
+	MagickCore/threshold.h \
+	MagickCore/type.c \
+	MagickCore/type.h \
+	MagickCore/utility.c \
+	MagickCore/utility.h \
+	MagickCore/version.c \
+	MagickCore/version.h \
+	MagickCore/vms.h \
+	MagickCore/widget.c \
+	MagickCore/widget.h \
+	MagickCore/xml-tree.c \
+	MagickCore/xml-tree.h \
+	MagickCore/xwindow.c \
+	MagickCore/xwindow.h 
+
+if WIN32_NATIVE_BUILD
+MAGICKCORE_PLATFORM_SRCS = \
+	MagickCore/nt-base.c \
+	MagickCore/nt-base.h \
+	MagickCore/nt-feature.c \
+	MagickCore/nt-feature.h
+else
+if CYGWIN_BUILD
+MAGICKCORE_PLATFORM_SRCS = \
+	MagickCore/nt-feature.c \
+	MagickCore/nt-feature.h
+else
+MAGICKCORE_PLATFORM_SRCS =
+endif # if CYGWIN_BUILD
+endif # if WIN32_NATIVE_BUILD
+
+MAGICKCORE_INCLUDE_HDRS = \
+	MagickCore/MagickCore.h \
+	MagickCore/PreRvIcccm.h \
+	MagickCore/accelerate.h \
+	MagickCore/animate.h \
+	MagickCore/annotate.h \
+	MagickCore/artifact.h \
+	MagickCore/attribute.h \
+	MagickCore/blob.h \
+	MagickCore/cache.h \
+	MagickCore/cache-view.h \
+	MagickCore/cipher.h \
+	MagickCore/client.h \
+	MagickCore/coder.h \
+	MagickCore/color.h \
+	MagickCore/colormap.h \
+	MagickCore/colorspace.h \
+	MagickCore/compare.h \
+	MagickCore/composite.h \
+	MagickCore/compress.h \
+	MagickCore/configure.h \
+	MagickCore/constitute.h \
+	MagickCore/decorate.h \
+	MagickCore/delegate.h \
+	MagickCore/deprecate.h \
+	MagickCore/display.h \
+	MagickCore/distort.h \
+	MagickCore/draw.h \
+	MagickCore/effect.h \
+	MagickCore/enhance.h \
+	MagickCore/exception.h \
+	MagickCore/feature.h \
+	MagickCore/fourier.h \
+	MagickCore/fx.h \
+	MagickCore/gem.h \
+	MagickCore/geometry.h \
+	MagickCore/hashmap.h \
+	MagickCore/histogram.h \
+	MagickCore/identify.h \
+	MagickCore/image.h \
+	MagickCore/image-view.h \
+	MagickCore/layer.h \
+	MagickCore/list.h \
+	MagickCore/locale_.h \
+	MagickCore/log.h \
+	MagickCore/magic.h \
+	MagickCore/magick.h \
+	MagickCore/magick-config.h \
+	MagickCore/magick-type.h \
+	MagickCore/matrix.h \
+	MagickCore/memory_.h \
+	MagickCore/methods.h \
+	MagickCore/mime.h \
+	MagickCore/module.h \
+	MagickCore/monitor.h \
+	MagickCore/montage.h \
+	MagickCore/morphology.h \
+	MagickCore/option.h \
+	MagickCore/paint.h \
+	MagickCore/pixel.h \
+	MagickCore/pixel-accessor.h \
+	MagickCore/policy.h \
+	MagickCore/prepress.h \
+	MagickCore/profile.h \
+	MagickCore/property.h \
+	MagickCore/quantize.h \
+	MagickCore/quantum.h \
+	MagickCore/random_.h \
+	MagickCore/registry.h \
+	MagickCore/resample.h \
+	MagickCore/resize.h \
+	MagickCore/resource_.h \
+	MagickCore/segment.h \
+	MagickCore/semaphore.h \
+	MagickCore/shear.h \
+	MagickCore/signature.h \
+	MagickCore/splay-tree.h \
+	MagickCore/statistic.h \
+	MagickCore/stream.h \
+	MagickCore/string_.h \
+	MagickCore/timer.h \
+	MagickCore/token.h \
+	MagickCore/transform.h \
+	MagickCore/threshold.h \
+	MagickCore/type.h \
+	MagickCore/utility.h \
+	MagickCore/version.h \
+	MagickCore/widget.h \
+	MagickCore/xml-tree.h \
+	MagickCore/xwindow.h
+
+MAGICKCORE_NOINST_HDRS = \
+	MagickCore/animate-private.h \
+	MagickCore/blob-private.h \
+	MagickCore/cache-private.h \
+	MagickCore/color-private.h \
+	MagickCore/colormap-private.h \
+	MagickCore/colorspace-private.h \
+	MagickCore/composite-private.h \
+	MagickCore/delegate-private.h \
+	MagickCore/display-private.h \
+	MagickCore/draw-private.h \
+	MagickCore/exception-private.h \
+	MagickCore/fx-private.h \
+	MagickCore/image-private.h \
+	MagickCore/mac.h \
+	MagickCore/mime-private.h \
+	MagickCore/monitor-private.h \
+	MagickCore/morphology-private.h \
+	MagickCore/nt-base.h \
+	MagickCore/nt-feature.h \
+	MagickCore/quantum-private.h \
+	MagickCore/random-private.h \
+	MagickCore/resample-private.h \
+	MagickCore/resize-private.h \
+	MagickCore/semaphore-private.h \
+	MagickCore/signature-private.h \
+	MagickCore/static.h \
+	MagickCore/stream-private.h \
+	MagickCore/string-private.h \
+	MagickCore/studio.h \
+	MagickCore/thread_.h \
+	MagickCore/thread-private.h \
+	MagickCore/token-private.h \
+	MagickCore/xwindow-private.h \
+	MagickCore/vms.h
+
+MAGICKCORE_EXTRA_DIST = \
+	MagickCore/MagickCore-config.in \
+	$(MAGICKCORE_MANS) \
+	MagickCore/ImageMagick.pc.in \
+	MagickCore/MagickCore.pc.in \
+	MagickCore/Make.com \
+	MagickCore/config.h_vms \
+	MagickCore/mac.c \
+	MagickCore/nt-base.c \
+	MagickCore/nt-feature.c \
+	MagickCore/vms.c \
+	MagickCore/xwdfile.h_vms 
+
+# Install magick-config.h
+MAGICKCORE_INSTALL_DATA_LOCAL_TARGETS = MagickCore-install-data-local
+MagickCore-install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(MagickCoreincdir)
+	$(INSTALL_HEADER) MagickCore/magick-config.h $(DESTDIR)$(MagickCoreincdir)/magick-config.h
+
+# Uninstall magick-config.h
+MAGICKCORE_UNINSTALL_LOCAL_TARGETS = MagickCore-uninstall-local
+MagickCore-uninstall-local:
+	rm -f $(DESTDIR)$(MagickCoreincdir)/magick-config.h
+
diff --git a/MagickCore/PreRvIcccm.c b/MagickCore/PreRvIcccm.c
new file mode 100644
index 0000000..6ca0ad6
--- /dev/null
+++ b/MagickCore/PreRvIcccm.c
@@ -0,0 +1,347 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      IIIII   CCCC   CCCC   CCCC  M   M                      %
+%                        I    C      C      C      MM MM                      %
+%                        I    C      C      C      M M M                      %
+%                        I    C      C      C      M   M                      %
+%                      IIIII   CCCC   CCCC   CCCC  M   M                      %
+%                                                                             %
+%                     MagickCore X11 Compatibility Methods                    %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                December 1994                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+#include "MagickCore/studio.h"
+#if defined(MAGICKCORE_X11_DELEGATE)
+#include "MagickCore/xwindow-private.h"
+
+#if defined(PRE_R6_ICCCM)
+/*
+  Compatibility methods for pre X11R6 ICCCM.
+*/
+Status XInitImage(XImage *ximage)
+{
+  Display
+    display;
+
+  ScreenFormat
+    screen_format;
+
+  XImage
+    *created_ximage,
+    target_ximage;
+
+  /*
+    Initialize the X image.
+  */
+  screen_format.depth=ximage->depth;
+  screen_format.bits_per_pixel=(int) ximage->bits_per_pixel;
+  display.byte_order=ximage->byte_order;
+  display.bitmap_unit=ximage->bitmap_unit;
+  display.bitmap_bit_order=ximage->bitmap_bit_order;
+  display.pixmap_format=(&screen_format);
+  display.nformats=1;
+  created_ximage=XCreateImage(&display,(Visual *) NULL,ximage->depth,
+    ximage->format,ximage->xoffset,(char *) NULL,ximage->width,ximage->height,
+    ximage->bitmap_pad,ximage->bytes_per_line);
+  if (created_ximage == (XImage *) NULL)
+    return(0);
+  target_ximage=(*ximage);
+  *ximage=(*created_ximage);
+  created_ximage->data=(char *) NULL;
+  XDestroyImage(created_ximage);
+  ximage->red_mask=target_ximage.red_mask;
+  ximage->green_mask=target_ximage.green_mask;
+  ximage->blue_mask=target_ximage.blue_mask;
+  return(1);
+}
+#endif
+
+#if defined(PRE_R5_ICCCM)
+/*
+  Compatibility methods for pre X11R5 ICCCM.
+*/
+void XrmCombineDatabase(XrmDatabase source,XrmDatabase *target,
+  Bool override)
+{
+  XrmMergeDatabases(source,target);
+}
+
+Status XrmCombineFileDatabase(const char *filename,XrmDatabase *target,
+  Bool override)
+{
+  XrmDatabase
+    *combined_database,
+    source;
+
+  source=XrmGetFileDatabase(filename);
+  if (override == MagickFalse)
+    XrmMergeDatabases(source,target);
+  return(1);
+}
+
+XrmDatabase XrmGetDatabase(Display *display)
+{
+  return(display->db);
+}
+
+char *XSetLocaleModifiers(char *modifiers)
+{
+  return((char *) NULL);
+}
+
+Bool XSupportsLocale()
+{
+  return(0);
+}
+#endif
+
+#if defined(PRE_R4_ICCCM)
+/*
+  Compatibility methods for pre X11R4 ICCCM.
+*/
+XClassHint *XAllocClassHint)
+{
+  return((XClassHint *) AcquireMagickMemory(sizeof(XClassHint)));
+}
+
+XIconSize *XAllocIconSize)
+{
+  return((XIconSize *) AcquireMagickMemory(sizeof(XIconSize)));
+}
+
+XSizeHints *XAllocSizeHints)
+{
+  return((XSizeHints *) AcquireMagickMemory(sizeof(XSizeHints)));
+}
+
+Status XReconfigureWMWindow(Display *display,Window window,int screen_number,
+  unsigned int value_mask,XWindowChanges *values)
+{
+  return(XConfigureWindow(display,window,value_mask,values));
+}
+
+XStandardColormap *XAllocStandardColormap)
+{
+  return((XStandardColormap *) AcquireMagickMemory(sizeof(XStandardColormap)));
+}
+
+XWMHints *XAllocWMHints)
+{
+  return((XWMHints *) AcquireMagickMemory(sizeof(XWMHints)));
+}
+
+Status XGetGCValues(Display *display,GC gc,size_t mask,
+  XGCValues *values)
+{
+  return(MagickTrue);
+}
+
+Status XGetRGBColormaps(Display *display,Window window,
+  XStandardColormap **colormap,int *count,Atom property)
+{
+  *count=1;
+  return(XGetStandardColormap(display,window,*colormap,property));
+}
+
+Status XGetWMColormapWindows(Display *display,Window window,
+  Window **colormap_windows,int *number_windows)
+{
+  Atom
+    actual_type,
+    *data,
+    property;
+
+  int
+    actual_format,
+    status;
+
+  size_t
+    leftover,
+    number_items;
+
+  property=XInternAtom(display,"WM_COLORMAP_WINDOWS",MagickFalse);
+  if (property == None)
+    return(MagickFalse);
+  /*
+    Get the window property.
+  */
+  *data=(Atom) NULL;
+  status=XGetWindowProperty(display,window,property,0L,1000000L,MagickFalse,
+    XA_WINDOW,&actual_type,&actual_format,&number_items,&leftover,
+    (unsigned char **) &data);
+  if (status != Success)
+    return(MagickFalse);
+  if ((actual_type != XA_WINDOW) || (actual_format != 32))
+    {
+      if (data != (Atom *) NULL)
+        XFree((char *) data);
+      return(MagickFalse);
+    }
+  *colormap_windows=(Window *) data;
+  *number_windows=(int) number_items;
+  return(MagickTrue);
+}
+
+Status XGetWMName(Display *display,Window window,XTextProperty *text_property)
+{
+  char
+    *window_name;
+
+  if (XFetchName(display,window,&window_name) == 0)
+    return(MagickFalse);
+  text_property->value=(unsigned char *) window_name;
+  text_property->encoding=XA_STRING;
+  text_property->format=8;
+  text_property->nitems=strlen(window_name);
+  return(MagickTrue);
+}
+
+char *XResourceManagerString(Display *display)
+{
+  return(display->xdefaults);
+}
+
+void XrmDestroyDatabase(XrmDatabase database)
+{
+}
+
+void XSetWMIconName(Display *display,Window window,XTextProperty *property)
+{
+  XSetIconName(display,window,property->value);
+}
+
+void XSetWMName(Display *display,Window window,XTextProperty *property)
+{
+  XStoreName(display,window,property->value);
+}
+
+void XSetWMProperties(Display *display,Window window,
+  XTextProperty *window_name,XTextProperty *icon_name,char **argv,
+  int argc,XSizeHints *size_hints,XWMHints *manager_hints,
+  XClassHint *class_hint)
+{
+  XSetStandardProperties(display,window,window_name->value,icon_name->value,
+    None,argv,argc,size_hints);
+  XSetWMHints(display,window,manager_hints);
+  XSetClassHint(display,window,class_hint);
+}
+
+Status XSetWMProtocols(Display *display,Window window,Atom *protocols,
+  int count)
+{
+  Atom
+    wm_protocols;
+
+  wm_protocols=XInternAtom(display,"WM_PROTOCOLS",MagickFalse);
+  XChangeProperty(display,window,wm_protocols,XA_ATOM,32,PropModeReplace,
+    (unsigned char *) protocols,count);
+  return(MagickTrue);
+}
+
+int XStringListToTextProperty(char **argv,int argc,XTextProperty *property)
+{
+  register int
+    i;
+
+  register unsigned int
+    number_bytes;
+
+  XTextProperty
+     protocol;
+
+  number_bytes=0;
+  for (i=0; i < (ssize_t) argc; i++)
+    number_bytes+=(unsigned int) ((argv[i] ? strlen(argv[i]) : 0)+1);
+  protocol.encoding=XA_STRING;
+  protocol.format=8;
+  protocol.nitems=0;
+  if (number_bytes)
+    protocol.nitems=number_bytes-1;
+  protocol.value=NULL;
+  if (number_bytes <= 0)
+    {
+      protocol.value=(unsigned char *) AcquireQuantumMemory(1UL,
+        sizeof(*protocol.value));
+      if (protocol.value == MagickFalse)
+        return(MagickFalse);
+      *protocol.value='\0';
+    }
+  else
+    {
+      register char
+        *buffer;
+
+      buffer=(char *) AcquireQuantumMemory(number_bytes,sizeof(*buffer));
+      if (buffer == (char *) NULL)
+        return(MagickFalse);
+      protocol.value=(unsigned char *) buffer;
+      for (i=0; i < (ssize_t) argc; i++)
+      {
+        char
+          *argument;
+
+        argument=argv[i];
+        if (argument == MagickFalse)
+          *buffer++='\0';
+        else
+          {
+            (void) CopyMagickString(buffer,argument,MaxTextExtent);
+            buffer+=(strlen(argument)+1);
+          }
+      }
+    }
+  *property=protocol;
+  return(MagickTrue);
+}
+
+VisualID XVisualIDFromVisual(Visual *visual)
+{
+  return(visual->visualid);
+}
+
+Status XWithdrawWindow(Display *display,Window window,int screen)
+{
+  return(XUnmapWindow(display,window));
+}
+
+int XWMGeometry(Display *display,int screen,char *user_geometry,
+  char *default_geometry,unsigned int border_width,XSizeHints *size_hints,
+  int *x,int *y,int *width,int *height,int *gravity)
+{
+  int
+    status;
+
+  status=XGeometry(display,screen,user_geometry,default_geometry,border_width,
+    0,0,0,0,x,y,width,height);
+  *gravity=NorthWestGravity;
+  return(status);
+}
+#endif
+
+#endif
diff --git a/MagickCore/PreRvIcccm.h b/MagickCore/PreRvIcccm.h
new file mode 100644
index 0000000..f2b89f3
--- /dev/null
+++ b/MagickCore/PreRvIcccm.h
@@ -0,0 +1,115 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore X11 compatibility methods.
+*/
+#ifndef _MAGICKCORE_PRER5ICCCM_H
+#define _MAGICKCORE_PRER5ICCCM_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(PRE_R6_ICCCM)
+/*
+  Compatability defines for pre X11R6 ICCCM.
+*/
+#define XK_KP_Home              0xFF95
+#define XK_KP_Left              0xFF96
+#define XK_KP_Up                0xFF97
+#define XK_KP_Right             0xFF98
+#define XK_KP_Down              0xFF99
+#define XK_KP_Prior             0xFF9A
+#define XK_KP_Page_Up           0xFF9A
+#define XK_KP_Next              0xFF9B
+#define XK_KP_Page_Down         0xFF9B
+#define XK_KP_End               0xFF9C
+#define XK_KP_Delete            0xFF9F
+
+extern MagickExport Status
+  XInitImage(XImage *ximage);
+#endif
+
+#if defined(PRE_R5_ICCCM)
+extern MagickExport XrmDatabase
+  XrmGetDatabase();
+#endif
+
+#if defined(PRE_R4_ICCCM)
+#if defined(vms)
+#define XMaxRequestSize(display)  16384
+#endif
+
+#define WithdrawnState  0
+
+typedef struct _XTextProperty
+{
+  unsigned char
+    *value;
+
+  Atom
+    encoding;
+
+  int
+    format;
+
+  size_t
+    nitems;
+} XTextProperty;
+
+char
+  *XResourceManagerString();
+
+extern MagickExport int
+  XWMGeometry();
+
+extern MagickExport Status
+  XGetRGBColormaps(),
+  XGetWMName(),
+  XReconfigureWMWindow(),
+  XSetWMProtocols(),
+  XWithdrawWindow();
+
+extern MagickExport XClassHint
+  *XAllocClassHint();
+
+extern MagickExport XIconSize
+  *XAllocIconSize();
+
+extern MagickExport XSizeHints
+  *XAllocSizeHints();
+
+extern MagickExport XStandardColormap
+  *XAllocStandardColormap();
+
+extern MagickExport XWMHints
+  *XAllocWMHints();
+
+extern MagickExport VisualID
+  XVisualIDFromVisual();
+
+extern MagickExport void
+  XrmDestroyDatabase(),
+  XSetWMIconName(),
+  XSetWMName(),
+  XSetWMProperties();
+#else
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/accelerate.c b/MagickCore/accelerate.c
new file mode 100644
index 0000000..ceb0521
--- /dev/null
+++ b/MagickCore/accelerate.c
@@ -0,0 +1,670 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     AAA     CCCC    CCCC  EEEEE  L      EEEEE  RRRR    AAA   TTTTT  EEEEE   %
+%    A   A   C       C      E      L      E      R   R  A   A    T    E       %
+%    AAAAA   C       C      EEE    L      EEE    RRRR   AAAAA    T    EEE     %
+%    A   A   C       C      E      L      E      R R    A   A    T    E       %
+%    A   A    CCCC    CCCC  EEEEE  LLLLL  EEEEE  R  R   A   A    T    EEEEE   %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Acceleration Methods                       %
+%                                                                             %
+%                              Software Design                                %
+%                               John Cristy                                   %
+%                               January 2010                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Morphology is the the application of various kernals, of any size and even
+% shape, to a image in various ways (typically binary, but not always).
+%
+% Convolution (weighted sum or average) is just one specific type of
+% accelerate. Just one that is very common for image bluring and sharpening
+% effects.  Not only 2D Gaussian blurring, but also 2-pass 1D Blurring.
+%
+% This module provides not only a general accelerate function, and the ability
+% to apply more advanced or iterative morphologies, but also functions for the
+% generation of many different types of kernel arrays from user supplied
+% arguments. Prehaps even the generation of a kernel from a small image.
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/accelerate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/accelerate.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/prepress.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A c c e l e r a t e C o n v o l v e I m a g e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AccelerateConvolveImage() applies a custom convolution kernel to the image.
+%  It is accelerated by taking advantage of speed-ups offered by executing in
+%  concert across heterogeneous platforms consisting of CPUs, GPUs, and other
+%  processors.
+%
+%  The format of the AccelerateConvolveImage method is:
+%
+%      Image *AccelerateConvolveImage(const Image *image,
+%        const KernelInfo *kernel,Image *convolve_image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o kernel: the convolution kernel.
+%
+%    o convole_image: the convoleed image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(MAGICKCORE_OPENCL_SUPPORT)
+
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+#define CLOptions "-DMAGICKCORE_HDRI_SUPPORT=1 -DCLQuantum=float " \
+  "-DCLPixelType=float4 -DQuantumRange=%g -DMagickEpsilon=%g"
+#define CLPixelPacket  cl_float4
+#else
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+#define CLOptions "-DCLQuantum=uchar -DCLPixelType=uchar4 " \
+  "-DQuantumRange=%g -DMagickEpsilon=%g"
+#define CLPixelPacket  cl_uchar4
+#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
+#define CLOptions "-DCLQuantum=ushort -DCLPixelType=ushort4 " \
+  "-DQuantumRange=%g -DMagickEpsilon=%g"
+#define CLPixelPacket  cl_ushort4
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+#define CLOptions "-DCLQuantum=uint -DCLPixelType=uint4 " \
+  "-DQuantumRange=%g -DMagickEpsilon=%g"
+#define CLPixelPacket  cl_uint4
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+#define CLOptions "-DCLQuantum=ussize_t -DCLPixelType=ussize_t4 " \
+  "-DQuantumRange=%g -DMagickEpsilon=%g"
+#define CLPixelPacket  cl_ulong4
+#endif
+#endif
+
+typedef struct _ConvolveInfo
+{
+  cl_context
+    context;
+
+  cl_device_id
+    *devices;
+
+  cl_command_queue
+    command_queue;
+
+  cl_kernel
+    kernel;
+
+  cl_program
+    program;
+
+  cl_mem
+    pixels,
+    convolve_pixels;
+
+  cl_ulong
+    width,
+    height;
+
+  cl_bool
+    matte;
+
+  cl_mem
+    filter;
+} ConvolveInfo;
+
+static char
+  *ConvolveKernel =
+    "static inline long ClampToCanvas(const long offset,const unsigned long range)\n"
+    "{\n"
+    "  if (offset < 0L)\n"
+    "    return(0L);\n"
+    "  if (offset >= range)\n"
+    "    return((long) (range-1L));\n"
+    "  return(offset);\n"
+    "}\n"
+    "\n"
+    "static inline CLQuantum ClampToQuantum(const double value)\n"
+    "{\n"
+    "#if defined(MAGICKCORE_HDRI_SUPPORT)\n"
+    "  return((CLQuantum) value)\n"
+    "#else\n"
+    "  if (value < 0.0)\n"
+    "    return((CLQuantum) 0);\n"
+    "  if (value >= (double) QuantumRange)\n"
+    "    return((CLQuantum) QuantumRange);\n"
+    "  return((CLQuantum) (value+0.5));\n"
+    "#endif\n"
+    "}\n"
+    "\n"
+    "__kernel void Convolve(const __global CLPixelType *input,\n"
+    "  __constant double *filter,const unsigned long width,const unsigned long height,\n"
+    "  const bool matte,__global CLPixelType *output)\n"
+    "{\n"
+    "  const unsigned long columns = get_global_size(0);\n"
+    "  const unsigned long rows = get_global_size(1);\n"
+    "\n"
+    "  const long x = get_global_id(0);\n"
+    "  const long y = get_global_id(1);\n"
+    "\n"
+    "  const double scale = (1.0/QuantumRange);\n"
+    "  const long mid_width = (width-1)/2;\n"
+    "  const long mid_height = (height-1)/2;\n"
+    "  double4 sum = { 0.0, 0.0, 0.0, 0.0 };\n"
+    "  double gamma = 0.0;\n"
+    "  register unsigned long i = 0;\n"
+    "\n"
+    "  int method = 0;\n"
+    "  if (matte != false)\n"
+    "    method=1;\n"
+    "  if ((x >= width) && (x < (columns-width-1)) &&\n"
+    "      (y >= height) && (y < (rows-height-1)))\n"
+    "    {\n"
+    "      method=2;\n"
+    "      if (matte != false)\n"
+    "        method=3;\n"
+    "    }\n"
+    "  switch (method)\n"
+    "  {\n"
+    "    case 0:\n"
+    "    {\n"
+    "      for (long v=(-mid_height); v <= mid_height; v++)\n"
+    "      {\n"
+    "        for (long u=(-mid_width); u <= mid_width; u++)\n"
+    "        {\n"
+    "          const long index=ClampToCanvas(y+v,rows)*columns+\n"
+    "            ClampToCanvas(x+u,columns);\n"
+    "          sum.x+=filter[i]*input[index].x;\n"
+    "          sum.y+=filter[i]*input[index].y;\n"
+    "          sum.z+=filter[i]*input[index].z;\n"
+    "          gamma+=filter[i];\n"
+    "          i++;\n"
+    "        }\n"
+    "      }\n"
+    "      break;\n"
+    "    }\n"
+    "    case 1:\n"
+    "    {\n"
+    "      for (long v=(-mid_height); v <= mid_height; v++)\n"
+    "      {\n"
+    "        for (long u=(-mid_width); u <= mid_width; u++)\n"
+    "        {\n"
+    "          const unsigned long index=ClampToCanvas(y+v,rows)*columns+\n"
+    "            ClampToCanvas(x+u,columns);\n"
+    "          const double alpha=scale*input[index].w;\n"
+    "          sum.x+=alpha*filter[i]*input[index].x;\n"
+    "          sum.y+=alpha*filter[i]*input[index].y;\n"
+    "          sum.z+=alpha*filter[i]*input[index].z;\n"
+    "          sum.w+=filter[i]*input[index].w;\n"
+    "          gamma+=alpha*filter[i];\n"
+    "          i++;\n"
+    "        }\n"
+    "      }\n"
+    "      break;\n"
+    "    }\n"
+    "    case 2:\n"
+    "    {\n"
+    "      for (long v=(-mid_height); v <= mid_height; v++)\n"
+    "      {\n"
+    "        for (long u=(-mid_width); u <= mid_width; u++)\n"
+    "        {\n"
+    "          const unsigned long index=(y+v)*columns+(x+u);\n"
+    "          sum.x+=filter[i]*input[index].x;\n"
+    "          sum.y+=filter[i]*input[index].y;\n"
+    "          sum.z+=filter[i]*input[index].z;\n"
+    "          gamma+=filter[i];\n"
+    "          i++;\n"
+    "        }\n"
+    "      }\n"
+    "      break;\n"
+    "    }\n"
+    "    case 3:\n"
+    "    {\n"
+    "      for (long v=(-mid_height); v <= mid_height; v++)\n"
+    "      {\n"
+    "        for (long u=(-mid_width); u <= mid_width; u++)\n"
+    "        {\n"
+    "          const unsigned long index=(y+v)*columns+(x+u);\n"
+    "          const double alpha=scale*input[index].w;\n"
+    "          sum.x+=alpha*filter[i]*input[index].x;\n"
+    "          sum.y+=alpha*filter[i]*input[index].y;\n"
+    "          sum.z+=alpha*filter[i]*input[index].z;\n"
+    "          sum.w+=filter[i]*input[index].w;\n"
+    "          gamma+=alpha*filter[i];\n"
+    "          i++;\n"
+    "        }\n"
+    "      }\n"
+    "      break;\n"
+    "    }\n"
+    "  }\n"
+    "  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);\n"
+    "  const unsigned long index = y*columns+x;\n"
+    "  output[index].x=ClampToQuantum(gamma*sum.x);\n"
+    "  output[index].y=ClampToQuantum(gamma*sum.y);\n"
+    "  output[index].z=ClampToQuantum(gamma*sum.z);\n"
+    "  if (matte == false)\n"
+    "    output[index].w=input[index].w;\n"
+    "  else\n"
+    "    output[index].w=ClampToQuantum(sum.w);\n"
+    "}\n";
+
+static void ConvolveNotify(const char *message,const void *data,size_t length,
+  void *user_context)
+{
+  ExceptionInfo
+    *exception;
+
+  (void) data;
+  (void) length;
+  exception=(ExceptionInfo *) user_context;
+  (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
+    "DelegateFailed","`%s'",message);
+}
+
+static MagickBooleanType BindConvolveParameters(ConvolveInfo *convolve_info,
+  const Image *image,const void *pixels,double *filter,
+  const size_t width,const size_t height,void *convolve_pixels)
+{
+  cl_int
+    status;
+
+  register cl_uint
+    i;
+
+  size_t
+    length;
+
+  /*
+    Allocate OpenCL buffers.
+  */
+  length=image->columns*image->rows;
+  convolve_info->pixels=clCreateBuffer(convolve_info->context,(cl_mem_flags)
+    (CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR),length*sizeof(CLPixelPacket),
+    (void *) pixels,&status);
+  if ((convolve_info->pixels == (cl_mem) NULL) || (status != CL_SUCCESS))
+    return(MagickFalse);
+  length=width*height;
+  convolve_info->filter=clCreateBuffer(convolve_info->context,(cl_mem_flags)
+    (CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR),length*sizeof(cl_double),filter,
+    &status);
+  if ((convolve_info->filter == (cl_mem) NULL) || (status != CL_SUCCESS))
+    return(MagickFalse);
+  length=image->columns*image->rows;
+  convolve_info->convolve_pixels=clCreateBuffer(convolve_info->context,
+    (cl_mem_flags) (CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR),length*
+    sizeof(CLPixelPacket),convolve_pixels,&status);
+  if ((convolve_info->convolve_pixels == (cl_mem) NULL) ||
+      (status != CL_SUCCESS))
+    return(MagickFalse);
+  /*
+    Bind OpenCL buffers.
+  */
+  i=0;
+  status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_mem),(void *)
+    &convolve_info->pixels);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_mem),(void *)
+    &convolve_info->filter);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  convolve_info->width=(cl_ulong) width;
+  status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_ulong),(void *)
+    &convolve_info->width);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  convolve_info->height=(cl_ulong) height;
+  status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_ulong),(void *)
+    &convolve_info->height);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  convolve_info->matte=(cl_bool) image->matte;
+  status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_bool),(void *)
+    &convolve_info->matte);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  status=clSetKernelArg(convolve_info->kernel,i++,sizeof(cl_mem),(void *)
+    &convolve_info->convolve_pixels);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  status=clFinish(convolve_info->command_queue);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static void DestroyConvolveBuffers(ConvolveInfo *convolve_info)
+{
+  cl_int
+    status;
+
+  if (convolve_info->convolve_pixels != (cl_mem) NULL)
+    status=clReleaseMemObject(convolve_info->convolve_pixels);
+  if (convolve_info->pixels != (cl_mem) NULL)
+    status=clReleaseMemObject(convolve_info->pixels);
+  if (convolve_info->filter != (cl_mem) NULL)
+    status=clReleaseMemObject(convolve_info->filter);
+}
+
+static ConvolveInfo *DestroyConvolveInfo(ConvolveInfo *convolve_info)
+{
+  cl_int
+    status;
+
+  if (convolve_info->kernel != (cl_kernel) NULL)
+    status=clReleaseKernel(convolve_info->kernel);
+  if (convolve_info->program != (cl_program) NULL)
+    status=clReleaseProgram(convolve_info->program);
+  if (convolve_info->command_queue != (cl_command_queue) NULL)
+    status=clReleaseCommandQueue(convolve_info->command_queue);
+  if (convolve_info->context != (cl_context) NULL)
+    status=clReleaseContext(convolve_info->context);
+  convolve_info=(ConvolveInfo *) RelinquishMagickMemory(convolve_info);
+  return(convolve_info);
+}
+
+static MagickBooleanType EnqueueConvolveKernel(ConvolveInfo *convolve_info,
+  const Image *image,const void *pixels,double *filter,
+  const size_t width,const size_t height,void *convolve_pixels)
+{
+  cl_int
+    status;
+
+  size_t
+    global_work_size[2],
+    length;
+
+  length=image->columns*image->rows;
+  status=clEnqueueWriteBuffer(convolve_info->command_queue,
+    convolve_info->pixels,CL_TRUE,0,length*sizeof(CLPixelPacket),pixels,0,NULL,
+    NULL);
+  length=width*height;
+  status=clEnqueueWriteBuffer(convolve_info->command_queue,
+    convolve_info->filter,CL_TRUE,0,length*sizeof(cl_double),filter,0,NULL,
+    NULL);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  global_work_size[0]=image->columns;
+  global_work_size[1]=image->rows;
+  status=clEnqueueNDRangeKernel(convolve_info->command_queue,
+    convolve_info->kernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  length=image->columns*image->rows;
+  status=clEnqueueReadBuffer(convolve_info->command_queue,
+    convolve_info->convolve_pixels,CL_TRUE,0,length*sizeof(CLPixelPacket),
+    convolve_pixels,0,NULL,NULL);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  status=clFinish(convolve_info->command_queue);
+  if (status != CL_SUCCESS)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static ConvolveInfo *GetConvolveInfo(const Image *image,const char *name,
+  const char *source,ExceptionInfo *exception)
+{
+  char
+    options[MaxTextExtent];
+
+  cl_int
+    status;
+
+  ConvolveInfo
+    *convolve_info;
+
+  size_t
+    length,
+    lengths[] = { strlen(source) };
+
+  /*
+    Create OpenCL info.
+  */
+  convolve_info=(ConvolveInfo *) AcquireMagickMemory(sizeof(*convolve_info));
+  if (convolve_info == (ConvolveInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return((ConvolveInfo *) NULL);
+    }
+  (void) ResetMagickMemory(convolve_info,0,sizeof(*convolve_info));
+  /*
+    Create OpenCL context.
+  */
+  convolve_info->context=clCreateContextFromType((cl_context_properties *)
+    NULL,(cl_device_type) CL_DEVICE_TYPE_GPU,ConvolveNotify,exception,&status);
+  if ((convolve_info->context == (cl_context) NULL) || (status != CL_SUCCESS))
+    convolve_info->context=clCreateContextFromType((cl_context_properties *)
+      NULL,(cl_device_type) CL_DEVICE_TYPE_CPU,ConvolveNotify,exception,
+      &status);
+  if ((convolve_info->context == (cl_context) NULL) || (status != CL_SUCCESS))
+    convolve_info->context=clCreateContextFromType((cl_context_properties *)
+      NULL,(cl_device_type) CL_DEVICE_TYPE_DEFAULT,ConvolveNotify,exception,
+      &status);
+  if ((convolve_info->context == (cl_context) NULL) || (status != CL_SUCCESS))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
+        "failed to create OpenCL context","`%s' (%d)",image->filename,status);
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  /*
+    Detect OpenCL devices.
+  */
+  status=clGetContextInfo(convolve_info->context,CL_CONTEXT_DEVICES,0,NULL,
+    &length);
+  if ((status != CL_SUCCESS) || (length == 0))
+    {
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  convolve_info->devices=(cl_device_id *) AcquireMagickMemory(length);
+  if (convolve_info->devices == (cl_device_id *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  status=clGetContextInfo(convolve_info->context,CL_CONTEXT_DEVICES,length,
+    convolve_info->devices,NULL);
+  if (status != CL_SUCCESS)
+    {
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  /*
+    Create OpenCL command queue.
+  */
+  convolve_info->command_queue=clCreateCommandQueue(convolve_info->context,
+    convolve_info->devices[0],0,&status);
+  if ((convolve_info->command_queue == (cl_command_queue) NULL) ||
+      (status != CL_SUCCESS))
+    {
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  /*
+    Build OpenCL program.
+  */
+  convolve_info->program=clCreateProgramWithSource(convolve_info->context,1,
+    &source,lengths,&status);
+  if ((convolve_info->program == (cl_program) NULL) || (status != CL_SUCCESS))
+    {
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  (void) FormatLocaleString(options,MaxTextExtent,CLOptions,(double)
+    QuantumRange,MagickEpsilon);
+  status=clBuildProgram(convolve_info->program,1,convolve_info->devices,options,
+    NULL,NULL);
+  if ((convolve_info->program == (cl_program) NULL) || (status != CL_SUCCESS))
+    {
+      char
+        *log;
+
+      status=clGetProgramBuildInfo(convolve_info->program,
+        convolve_info->devices[0],CL_PROGRAM_BUILD_LOG,0,NULL,&length);
+      log=(char *) AcquireMagickMemory(length);
+      if (log == (char *) NULL)
+        {
+          convolve_info=DestroyConvolveInfo(convolve_info);
+          return((ConvolveInfo *) NULL);
+        }
+      status=clGetProgramBuildInfo(convolve_info->program,
+        convolve_info->devices[0],CL_PROGRAM_BUILD_LOG,length,log,&length);
+      (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
+        "failed to build OpenCL program","`%s' (%s)",image->filename,log);
+      log=DestroyString(log);
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  /*
+    Get a kernel object.
+  */
+  convolve_info->kernel=clCreateKernel(convolve_info->program,name,&status);
+  if ((convolve_info->kernel == (cl_kernel) NULL) || (status != CL_SUCCESS))
+    {
+      convolve_info=DestroyConvolveInfo(convolve_info);
+      return((ConvolveInfo *) NULL);
+    }
+  return(convolve_info);
+}
+
+#endif
+
+MagickExport MagickBooleanType AccelerateConvolveImage(const Image *image,
+  const KernelInfo *kernel,Image *convolve_image,ExceptionInfo *exception)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(kernel != (KernelInfo *) NULL);
+  assert(kernel->signature == MagickSignature);
+  assert(convolve_image != (Image *) NULL);
+  assert(convolve_image->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((image->storage_class != DirectClass) || 
+      (image->colorspace == CMYKColorspace))
+  if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod) &&
+      (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod))
+    return(MagickFalse);
+#if !defined(MAGICKCORE_OPENCL_SUPPORT)
+  return(MagickFalse);
+#else
+  {
+    const void
+      *pixels;
+
+    ConvolveInfo
+      *convolve_info;
+
+    MagickBooleanType
+      status;
+
+    MagickSizeType
+      length;
+
+    void
+      *convolve_pixels;
+
+    convolve_info=GetConvolveInfo(image,"Convolve",ConvolveKernel,exception);
+    if (convolve_info == (ConvolveInfo *) NULL)
+      return(MagickFalse);
+    pixels=AcquirePixelCachePixels(image,&length,exception);
+    if (pixels == (const void *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+          "UnableToReadPixelCache","`%s'",image->filename);
+        convolve_info=DestroyConvolveInfo(convolve_info);
+        return(MagickFalse);
+      }
+    convolve_pixels=GetPixelCachePixels(convolve_image,&length,exception);
+    if (convolve_pixels == (void *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+          "UnableToReadPixelCache","`%s'",image->filename);
+        convolve_info=DestroyConvolveInfo(convolve_info);
+        return(MagickFalse);
+      }
+    status=BindConvolveParameters(convolve_info,image,pixels,kernel->values,
+      kernel->width,kernel->height,convolve_pixels);
+    if (status == MagickFalse)
+      {
+        DestroyConvolveBuffers(convolve_info);
+        convolve_info=DestroyConvolveInfo(convolve_info);
+        return(MagickFalse);
+      }
+    status=EnqueueConvolveKernel(convolve_info,image,pixels,kernel->values,
+      kernel->width,kernel->height,convolve_pixels);
+    if (status == MagickFalse)
+      {
+        DestroyConvolveBuffers(convolve_info);
+        convolve_info=DestroyConvolveInfo(convolve_info);
+        return(MagickFalse);
+      }
+    DestroyConvolveBuffers(convolve_info);
+    convolve_info=DestroyConvolveInfo(convolve_info);
+    return(MagickTrue);
+  }
+#endif
+}
diff --git a/MagickCore/accelerate.h b/MagickCore/accelerate.h
new file mode 100644
index 0000000..89151d4
--- /dev/null
+++ b/MagickCore/accelerate.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore acceleration methods.
+*/
+#ifndef _MAGICKCORE_ACCELERATE_H
+#define _MAGICKCORE_ACCELERATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/morphology.h>
+
+extern MagickExport MagickBooleanType
+  AccelerateConvolveImage(const Image *,const KernelInfo *,Image *,
+    ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/animate-private.h b/MagickCore/animate-private.h
new file mode 100644
index 0000000..ac69c54
--- /dev/null
+++ b/MagickCore/animate-private.h
@@ -0,0 +1,39 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private methods to interactively animate an image sequence.
+*/
+#ifndef _MAGICKCORE_ANIMATE_PRIVATE_H
+#define _MAGICKCORE_ANIMATE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+#include "MagickCore/xwindow-private.h"
+
+extern MagickExport Image
+  *XAnimateImages(Display *,XResourceInfo *,char **,const int,Image *);
+
+extern MagickExport void
+  XAnimateBackgroundImage(Display *,XResourceInfo *,Image *);
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/animate.c b/MagickCore/animate.c
new file mode 100644
index 0000000..7d42366
--- /dev/null
+++ b/MagickCore/animate.c
@@ -0,0 +1,3022 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE               %
+%               A   A  NN  N    I    MM MM  A   A    T    E                   %
+%               AAAAA  N N N    I    M M M  AAAAA    T    EEE                 %
+%               A   A  N  NN    I    M   M  A   A    T    E                   %
+%               A   A  N   N  IIIII  M   M  A   A    T    EEEEE               %
+%                                                                             %
+%                                                                             %
+%              Methods to Interactively Animate an Image Sequence             %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                                July 1992                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/animate.h"
+#include "MagickCore/animate-private.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#include "MagickCore/widget.h"
+#include "MagickCore/xwindow-private.h"
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+/*
+  Animate state declarations.
+*/
+#define AutoReverseAnimationState 0x0004
+#define ForwardAnimationState 0x0008
+#define HighlightState  0x0010
+#define PlayAnimationState 0x0020
+#define RepeatAnimationState 0x0040
+#define StepAnimationState 0x0080
+
+/*
+  Static declarations.
+*/
+static const char
+  *AnimateHelp[]=
+  {
+    "BUTTONS",
+    "",
+    "  Press any button to map or unmap the Command widget.",
+    "",
+    "COMMAND WIDGET",
+    "  The Command widget lists a number of sub-menus and commands.",
+    "  They are",
+    "",
+    "    Animate",
+    "      Open...",
+    "      Save...",
+    "      Play",
+    "      Step",
+    "      Repeat",
+    "      Auto Reverse",
+    "    Speed",
+    "      Slower",
+    "      Faster",
+    "    Direction",
+    "      Forward",
+    "      Reverse",
+    "      Help",
+    "        Overview",
+    "        Browse Documentation",
+    "        About Animate",
+    "    Image Info",
+    "    Quit",
+    "",
+    "  Menu items with a indented triangle have a sub-menu.  They",
+    "  are represented above as the indented items.  To access a",
+    "  sub-menu item, move the pointer to the appropriate menu and",
+    "  press a button and drag.  When you find the desired sub-menu",
+    "  item, release the button and the command is executed.  Move",
+    "  the pointer away from the sub-menu if you decide not to",
+    "  execute a particular command.",
+    "",
+    "KEYBOARD ACCELERATORS",
+    "  Accelerators are one or two key presses that effect a",
+    "  particular command.  The keyboard accelerators that",
+    "  animate(1) understands is:",
+    "",
+    "  Ctl+O  Press to open an image from a file.",
+    "",
+    "  space  Press to display the next image in the sequence.",
+    "",
+    "  <      Press to speed-up the display of the images.  Refer to",
+    "         -delay for more information.",
+    "",
+    "  >      Press to slow the display of the images.  Refer to",
+    "         -delay for more information.",
+    "",
+    "  F1     Press to display helpful information about animate(1).",
+    "",
+    "  Find   Press to browse documentation about ImageMagick.",
+    "",
+    "  ?      Press to display information about the image.  Press",
+    "         any key or button to erase the information.",
+    "",
+    "         This information is printed: image name;  image size;",
+    "         and the total number of unique colors in the image.",
+    "",
+    "  Ctl-q  Press to discard all images and exit program.",
+    (char *) NULL
+  };
+
+/*
+  Constant declarations.
+*/
+static const char
+  *PageSizes[]=
+  {
+    "Letter",
+    "Tabloid",
+    "Ledger",
+    "Legal",
+    "Statement",
+    "Executive",
+    "A3",
+    "A4",
+    "A5",
+    "B4",
+    "B5",
+    "Folio",
+    "Quarto",
+    "10x14",
+    (char *) NULL
+  };
+
+static const unsigned char
+  HighlightBitmap[8] =
+  {
+    (unsigned char) 0xaa,
+    (unsigned char) 0x55,
+    (unsigned char) 0xaa,
+    (unsigned char) 0x55,
+    (unsigned char) 0xaa,
+    (unsigned char) 0x55,
+    (unsigned char) 0xaa,
+    (unsigned char) 0x55
+  },
+  ShadowBitmap[8] =
+  {
+    (unsigned char) 0x00,
+    (unsigned char) 0x00,
+    (unsigned char) 0x00,
+    (unsigned char) 0x00,
+    (unsigned char) 0x00,
+    (unsigned char) 0x00,
+    (unsigned char) 0x00,
+    (unsigned char) 0x00
+  };
+
+/*
+  Enumeration declarations.
+*/
+typedef enum
+{
+  OpenCommand,
+  SaveCommand,
+  PlayCommand,
+  StepCommand,
+  RepeatCommand,
+  AutoReverseCommand,
+  SlowerCommand,
+  FasterCommand,
+  ForwardCommand,
+  ReverseCommand,
+  HelpCommand,
+  BrowseDocumentationCommand,
+  VersionCommand,
+  InfoCommand,
+  QuitCommand,
+  StepBackwardCommand,
+  StepForwardCommand,
+  NullCommand
+} CommandType;
+
+/*
+  Stipples.
+*/
+#define HighlightWidth  8
+#define HighlightHeight  8
+#define ShadowWidth  8
+#define ShadowHeight  8
+
+/*
+  Forward declarations.
+*/
+static Image
+  *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
+    Image **,MagickStatusType *);
+
+static MagickBooleanType
+  XSaveImage(Display *,XResourceInfo *,XWindows *,Image *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A n i m a t e I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AnimateImages() repeatedly displays an image sequence to any X window
+%  screen.  It returns a value other than 0 if successful.  Check the
+%  exception member of image to determine the reason for any failure.
+%
+%  The format of the AnimateImages method is:
+%
+%      MagickBooleanType AnimateImages(const ImageInfo *image_info,
+%        Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
+  Image *images)
+{
+  char
+    *argv[1];
+
+  Display
+    *display;
+
+  MagickStatusType
+    status;
+
+  XrmDatabase
+    resource_database;
+
+  XResourceInfo
+    resource_info;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  display=XOpenDisplay(image_info->server_name);
+  if (display == (Display *) NULL)
+    {
+      (void) ThrowMagickException(&images->exception,GetMagickModule(),
+        XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
+        image_info->server_name));
+      return(MagickFalse);
+    }
+  if (images->exception.severity != UndefinedException)
+    CatchException(&images->exception);
+  (void) XSetErrorHandler(XError);
+  resource_database=XGetResourceDatabase(display,GetClientName());
+  (void) ResetMagickMemory(&resource_info,0,sizeof(XResourceInfo));
+  XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
+  if (image_info->page != (char *) NULL)
+    resource_info.image_geometry=AcquireString(image_info->page);
+  resource_info.immutable=MagickTrue;
+  argv[0]=AcquireString(GetClientName());
+  (void) XAnimateImages(display,&resource_info,argv,1,images);
+  argv[0]=DestroyString(argv[0]);
+  (void) XCloseDisplay(display);
+  XDestroyResourceInfo(&resource_info);
+  status=images->exception.severity == UndefinedException ?
+    MagickTrue : MagickFalse;
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a g i c k C o m m a n d                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMagickCommand() makes a transform to the image or Image window as specified
+%  by a user menu button or keyboard command.
+%
+%  The format of the XMagickCommand method is:
+%
+%      Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
+%        XWindows *windows,const CommandType command_type,Image **image,
+%        MagickStatusType *state)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image;  XMagickCommand
+%      may transform the image and return a new image pointer.
+%
+%    o state: Specifies a MagickStatusType;  XMagickCommand may return a
+%      modified state.
+%
+%
+*/
+static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
+  XWindows *windows,const CommandType command_type,Image **image,
+  MagickStatusType *state)
+{
+  Image
+    *nexus;
+
+  MagickBooleanType
+    proceed;
+
+  MagickStatusType
+    status;
+
+  XTextProperty
+    window_name;
+
+  /*
+    Process user command.
+  */
+  nexus=NewImageList();
+  switch (command_type)
+  {
+    case OpenCommand:
+    {
+      char
+        **filelist;
+
+      ExceptionInfo
+        *exception;
+
+      Image
+        *images,
+        *next;
+
+      ImageInfo
+        *read_info;
+
+      int
+        number_files;
+
+      register int
+        i;
+
+      static char
+        filenames[MaxTextExtent] = "*";
+
+      if (resource_info->immutable != MagickFalse)
+        break;
+      /*
+        Request file name from user.
+      */
+      XFileBrowserWidget(display,windows,"Animate",filenames);
+      if (*filenames == '\0')
+        return((Image *) NULL);
+      /*
+        Expand the filenames.
+      */
+      filelist=(char **) AcquireMagickMemory(sizeof(char *));
+      if (filelist == (char **) NULL)
+        {
+          ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
+            filenames);
+          return((Image *) NULL);
+        }
+      number_files=1;
+      filelist[0]=filenames;
+      status=ExpandFilenames(&number_files,&filelist);
+      if ((status == MagickFalse) || (number_files == 0))
+        {
+          if (number_files == 0)
+            {
+              ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
+             return((Image *) NULL);
+            }
+          ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
+            filenames);
+          return((Image *) NULL);
+        }
+      read_info=CloneImageInfo(resource_info->image_info);
+      exception=AcquireExceptionInfo();
+      images=NewImageList();
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      for (i=0; i < number_files; i++)
+      {
+        (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
+        filelist[i]=DestroyString(filelist[i]);
+        *read_info->magick='\0';
+        next=ReadImage(read_info,exception);
+        CatchException(exception);
+        if (next != (Image *) NULL)
+          AppendImageToList(&images,next);
+        if (number_files <= 5)
+          continue;
+        proceed=SetImageProgress(images,LoadImageTag,i,(MagickSizeType)
+          number_files);
+        if (proceed == MagickFalse)
+          break;
+      }
+      filelist=(char **) RelinquishMagickMemory(filelist);
+      exception=DestroyExceptionInfo(exception);
+      read_info=DestroyImageInfo(read_info);
+      if (images == (Image *) NULL)
+        {
+          XSetCursorState(display,windows,MagickFalse);
+          ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
+          return((Image *) NULL);
+        }
+      nexus=GetFirstImageInList(images);
+      *state|=ExitState;
+      break;
+    }
+    case PlayCommand:
+    {
+      char
+        basename[MaxTextExtent];
+
+      int
+        status;
+
+      /*
+        Window name is the base of the filename.
+      */
+      *state|=PlayAnimationState;
+      *state&=(~AutoReverseAnimationState);
+      GetPathComponent((*image)->magick_filename,BasePath,basename);
+      (void) FormatLocaleString(windows->image.name,MaxTextExtent,
+        "%s: %s",MagickPackageName,basename);
+      if (resource_info->title != (char *) NULL)
+        {
+          char
+            *title;
+
+          title=InterpretImageProperties(resource_info->image_info,*image,
+            resource_info->title);
+          (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
+          title=DestroyString(title);
+        }
+      status=XStringListToTextProperty(&windows->image.name,1,&window_name);
+      if (status == 0)
+        break;
+      XSetWMName(display,windows->image.id,&window_name);
+      (void) XFree((void *) window_name.value);
+      break;
+    }
+    case StepCommand:
+    case StepBackwardCommand:
+    case StepForwardCommand:
+    {
+      *state|=StepAnimationState;
+      *state&=(~PlayAnimationState);
+      if (command_type == StepBackwardCommand)
+        *state&=(~ForwardAnimationState);
+      if (command_type == StepForwardCommand)
+        *state|=ForwardAnimationState;
+      if (resource_info->title != (char *) NULL)
+        break;
+      break;
+    }
+    case RepeatCommand:
+    {
+      *state|=RepeatAnimationState;
+      *state&=(~AutoReverseAnimationState);
+      *state|=PlayAnimationState;
+      break;
+    }
+    case AutoReverseCommand:
+    {
+      *state|=AutoReverseAnimationState;
+      *state&=(~RepeatAnimationState);
+      *state|=PlayAnimationState;
+      break;
+    }
+    case SaveCommand:
+    {
+      /*
+        Save image.
+      */
+      status=XSaveImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to write X image:",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case SlowerCommand:
+    {
+      resource_info->delay++;
+      break;
+    }
+    case FasterCommand:
+    {
+      if (resource_info->delay == 0)
+        break;
+      resource_info->delay--;
+      break;
+    }
+    case ForwardCommand:
+    {
+      *state=ForwardAnimationState;
+      *state&=(~AutoReverseAnimationState);
+      break;
+    }
+    case ReverseCommand:
+    {
+      *state&=(~ForwardAnimationState);
+      *state&=(~AutoReverseAnimationState);
+      break;
+    }
+    case InfoCommand:
+    {
+      XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image);
+      break;
+    }
+    case HelpCommand:
+    {
+      /*
+        User requested help.
+      */
+      XTextViewWidget(display,resource_info,windows,MagickFalse,
+        "Help Viewer - Animate",AnimateHelp);
+      break;
+    }
+    case BrowseDocumentationCommand:
+    {
+      Atom
+        mozilla_atom;
+
+      Window
+        mozilla_window,
+        root_window;
+
+      /*
+        Browse the ImageMagick documentation.
+      */
+      root_window=XRootWindow(display,XDefaultScreen(display));
+      mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
+      mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
+      if (mozilla_window != (Window) NULL)
+        {
+          char
+            command[MaxTextExtent],
+            *url;
+
+          /*
+            Display documentation using Netscape remote control.
+          */
+          url=GetMagickHomeURL();
+          (void) FormatLocaleString(command,MaxTextExtent,
+            "openurl(%s,new-tab)",url);
+          url=DestroyString(url);
+          mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
+          (void) XChangeProperty(display,mozilla_window,mozilla_atom,
+            XA_STRING,8,PropModeReplace,(unsigned char *) command,
+            (int) strlen(command));
+          XSetCursorState(display,windows,MagickFalse);
+          break;
+        }
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      status=InvokeDelegate(resource_info->image_info,*image,"browse",
+        (char *) NULL,&(*image)->exception);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to browse documentation",
+          (char *) NULL);
+      XDelay(display,1500);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case VersionCommand:
+    {
+      XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
+        GetMagickCopyright());
+      break;
+    }
+    case QuitCommand:
+    {
+      /*
+        exit program
+      */
+      if (resource_info->confirm_exit == MagickFalse)
+        XClientMessage(display,windows->image.id,windows->im_protocols,
+          windows->im_exit,CurrentTime);
+      else
+        {
+          int
+            status;
+
+          /*
+            Confirm program exit.
+          */
+          status=XConfirmWidget(display,windows,"Do you really want to exit",
+            resource_info->client_name);
+          if (status != 0)
+            XClientMessage(display,windows->image.id,windows->im_protocols,
+              windows->im_exit,CurrentTime);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  return(nexus);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X A n i m a t e B a c k g r o u n d I m a g e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XAnimateBackgroundImage() animates an image sequence in the background of
+%  a window.
+%
+%  The format of the XAnimateBackgroundImage method is:
+%
+%      void XAnimateBackgroundImage(Display *display,
+%        XResourceInfo *resource_info,Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o images: the image list.
+%
+*/
+
+static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int SceneCompare(const void *x,const void *y)
+{
+  const Image
+    **image_1,
+    **image_2;
+
+  image_1=(const Image **) x;
+  image_2=(const Image **) y;
+  return((int) ((*image_1)->scene-(*image_2)->scene));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport void XAnimateBackgroundImage(Display *display,
+  XResourceInfo *resource_info,Image *images)
+{
+  char
+    geometry[MaxTextExtent],
+    visual_type[MaxTextExtent];
+
+  Image
+    *coalesce_image,
+    *display_image,
+    **image_list;
+
+  int
+    scene;
+
+  MagickStatusType
+    status;
+
+  RectangleInfo
+    geometry_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_scenes;
+
+  static XPixelInfo
+    pixel;
+
+  static XStandardColormap
+    *map_info;
+
+  static XVisualInfo
+    *visual_info = (XVisualInfo *) NULL;
+
+  static XWindowInfo
+    window_info;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    delay;
+
+  Window
+    root_window;
+
+  XEvent
+    event;
+
+  XGCValues
+    context_values;
+
+  XResourceInfo
+    resources;
+
+  XWindowAttributes
+    window_attributes;
+
+  /*
+    Determine target window.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  resources=(*resource_info);
+  window_info.id=(Window) NULL;
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  if (LocaleCompare(resources.window_id,"root") == 0)
+    window_info.id=root_window;
+  else
+    {
+      if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
+        window_info.id=XWindowByID(display,root_window,
+          (Window) strtol((char *) resources.window_id,(char **) NULL,0));
+      if (window_info.id == (Window) NULL)
+        window_info.id=
+          XWindowByName(display,root_window,resources.window_id);
+    }
+  if (window_info.id == (Window) NULL)
+    {
+      ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
+        resources.window_id);
+      return;
+    }
+  /*
+    Determine window visual id.
+  */
+  window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
+  window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
+  (void) CopyMagickString(visual_type,"default",MaxTextExtent);
+  status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ?
+    MagickTrue : MagickFalse;
+  if (status != MagickFalse)
+    (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
+      XVisualIDFromVisual(window_attributes.visual));
+  if (visual_info == (XVisualInfo *) NULL)
+    {
+      /*
+        Allocate standard colormap.
+      */
+      map_info=XAllocStandardColormap();
+      if (map_info == (XStandardColormap *) NULL)
+        ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
+          images->filename);
+      map_info->colormap=(Colormap) NULL;
+      pixel.pixels=(unsigned long *) NULL;
+      /*
+        Initialize visual info.
+      */
+      resources.map_type=(char *) NULL;
+      resources.visual_type=visual_type;
+      visual_info=XBestVisualInfo(display,map_info,&resources);
+      if (visual_info == (XVisualInfo *) NULL)
+        ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
+          images->filename);
+      /*
+        Initialize window info.
+      */
+      window_info.ximage=(XImage *) NULL;
+      window_info.matte_image=(XImage *) NULL;
+      window_info.pixmap=(Pixmap) NULL;
+      window_info.matte_pixmap=(Pixmap) NULL;
+    }
+  /*
+    Free previous root colors.
+  */
+  if (window_info.id == root_window)
+    XDestroyWindowColors(display,root_window);
+  coalesce_image=CoalesceImages(images,&images->exception);
+  if (coalesce_image == (Image *) NULL)
+    ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
+      images->filename);
+  images=coalesce_image;
+  if (resources.map_type == (char *) NULL)
+    if ((visual_info->klass != TrueColor) &&
+        (visual_info->klass != DirectColor))
+      {
+        Image
+          *next;
+
+        /*
+          Determine if the sequence of images has the identical colormap.
+        */
+        for (next=images; next != (Image *) NULL; )
+        {
+          next->matte=MagickFalse;
+          if ((next->storage_class == DirectClass) ||
+              (next->colors != images->colors) ||
+              (next->colors > (size_t) visual_info->colormap_size))
+            break;
+          for (i=0; i < (ssize_t) images->colors; i++)
+            if (IsPixelPacketEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
+              break;
+          if (i < (ssize_t) images->colors)
+            break;
+          next=GetNextImageInList(next);
+        }
+        if (next != (Image *) NULL)
+          (void) RemapImages(resources.quantize_info,images,(Image *) NULL);
+      }
+  /*
+    Sort images by increasing scene number.
+  */
+  number_scenes=GetImageListLength(images);
+  image_list=ImageListToArray(images,&images->exception);
+  if (image_list == (Image **) NULL)
+    ThrowXWindowFatalException(ResourceLimitFatalError,
+      "MemoryAllocationFailed",images->filename);
+  for (i=0; i < (ssize_t) number_scenes; i++)
+    if (image_list[i]->scene == 0)
+      break;
+  if (i == (ssize_t) number_scenes)
+    qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
+  /*
+    Initialize Standard Colormap.
+  */
+  resources.colormap=SharedColormap;
+  display_image=image_list[0];
+  for (scene=0; scene < (int) number_scenes; scene++)
+  {
+    if ((resource_info->map_type != (char *) NULL) ||
+        (visual_info->klass == TrueColor) ||
+        (visual_info->klass == DirectColor))
+      (void) SetImageType(image_list[scene],image_list[scene]->matte ==
+        MagickFalse ? TrueColorType : TrueColorMatteType);
+    if ((display_image->columns < image_list[scene]->columns) &&
+        (display_image->rows < image_list[scene]->rows))
+      display_image=image_list[scene];
+  }
+  if ((resource_info->map_type != (char *) NULL) ||
+      (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor))
+    (void) SetImageType(display_image,display_image->matte == MagickFalse ?
+      TrueColorType : TrueColorMatteType);
+  XMakeStandardColormap(display,visual_info,&resources,display_image,map_info,
+    &pixel);
+  /*
+    Graphic context superclass.
+  */
+  context_values.background=pixel.background_color.pixel;
+  context_values.foreground=pixel.foreground_color.pixel;
+  pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long)
+    (GCBackground | GCForeground),&context_values);
+  if (pixel.annotate_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      images->filename);
+  /*
+    Initialize Image window attributes.
+  */
+  XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
+    &resources,&window_info);
+  /*
+    Create the X image.
+  */
+  window_info.width=(unsigned int) image_list[0]->columns;
+  window_info.height=(unsigned int) image_list[0]->rows;
+  if ((image_list[0]->columns != window_info.width) ||
+      (image_list[0]->rows != window_info.height))
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      image_list[0]->filename);
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
+    window_attributes.width,window_attributes.height);
+  geometry_info.width=window_info.width;
+  geometry_info.height=window_info.height;
+  geometry_info.x=(ssize_t) window_info.x;
+  geometry_info.y=(ssize_t) window_info.y;
+  (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
+    &geometry_info.width,&geometry_info.height);
+  window_info.width=(unsigned int) geometry_info.width;
+  window_info.height=(unsigned int) geometry_info.height;
+  window_info.x=(int) geometry_info.x;
+  window_info.y=(int) geometry_info.y;
+  status=XMakeImage(display,&resources,&window_info,image_list[0],
+    window_info.width,window_info.height);
+  if (status == MagickFalse)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      images->filename);
+  window_info.x=0;
+  window_info.y=0;
+  if (display_image->debug != MagickFalse)
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "Image: %s[%.20g] %.20gx%.20g ",image_list[0]->filename,(double)
+        image_list[0]->scene,(double) image_list[0]->columns,(double)
+        image_list[0]->rows);
+      if (image_list[0]->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
+          image_list[0]->colors);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
+        image_list[0]->magick);
+    }
+  /*
+    Adjust image dimensions as specified by backdrop or geometry options.
+  */
+  width=window_info.width;
+  height=window_info.height;
+  if (resources.backdrop != MagickFalse)
+    {
+      /*
+        Center image on window.
+      */
+      window_info.x=(int) (window_attributes.width/2)-
+        (window_info.ximage->width/2);
+      window_info.y=(int) (window_attributes.height/2)-
+        (window_info.ximage->height/2);
+      width=(unsigned int) window_attributes.width;
+      height=(unsigned int) window_attributes.height;
+    }
+  if (resources.image_geometry != (char *) NULL)
+    {
+      char
+        default_geometry[MaxTextExtent];
+
+      int
+        flags,
+        gravity;
+
+      XSizeHints
+        *size_hints;
+
+      /*
+        User specified geometry.
+      */
+      size_hints=XAllocSizeHints();
+      if (size_hints == (XSizeHints *) NULL)
+        ThrowXWindowFatalException(ResourceLimitFatalError,
+          "MemoryAllocationFailed",images->filename);
+      size_hints->flags=0L;
+      (void) FormatLocaleString(default_geometry,MaxTextExtent,"%ux%u",width,
+        height);
+      flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
+        default_geometry,window_info.border_width,size_hints,&window_info.x,
+        &window_info.y,(int *) &width,(int *) &height,&gravity);
+      if (((flags & (XValue | YValue))) != 0)
+        {
+          width=(unsigned int) window_attributes.width;
+          height=(unsigned int) window_attributes.height;
+        }
+      (void) XFree((void *) size_hints);
+    }
+  /*
+    Create the X pixmap.
+  */
+  window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
+    (unsigned int) height,window_info.depth);
+  if (window_info.pixmap == (Pixmap) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
+      images->filename);
+  /*
+    Display pixmap on the window.
+  */
+  if (((unsigned int) width > window_info.width) ||
+      ((unsigned int) height > window_info.height))
+    (void) XFillRectangle(display,window_info.pixmap,
+      window_info.annotate_context,0,0,(unsigned int) width,
+      (unsigned int) height);
+  (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
+    window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
+    window_info.height);
+  (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
+  (void) XClearWindow(display,window_info.id);
+  /*
+    Initialize image pixmaps structure.
+  */
+  window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
+    sizeof(*window_info.pixmaps));
+  window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
+    sizeof(*window_info.matte_pixmaps));
+  if ((window_info.pixmaps == (Pixmap *) NULL) ||
+      (window_info.matte_pixmaps == (Pixmap *) NULL))
+    ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
+      images->filename);
+  window_info.pixmaps[0]=window_info.pixmap;
+  window_info.matte_pixmaps[0]=window_info.pixmap;
+  for (scene=1; scene < (int) number_scenes; scene++)
+  {
+    unsigned int
+      columns,
+      rows;
+
+    /*
+      Create X image.
+    */
+    window_info.pixmap=(Pixmap) NULL;
+    window_info.matte_pixmap=(Pixmap) NULL;
+    if ((resources.map_type != (char *) NULL) ||
+        (visual_info->klass == TrueColor) ||
+        (visual_info->klass == DirectColor))
+      if (image_list[scene]->storage_class == PseudoClass)
+        XGetPixelInfo(display,visual_info,map_info,&resources,
+          image_list[scene],window_info.pixel_info);
+    columns=(unsigned int) image_list[scene]->columns;
+    rows=(unsigned int) image_list[scene]->rows;
+    if ((image_list[scene]->columns != columns) ||
+        (image_list[scene]->rows != rows))
+      ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+        image_list[scene]->filename);
+    status=XMakeImage(display,&resources,&window_info,image_list[scene],
+      columns,rows);
+    if (status == MagickFalse)
+      ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+        images->filename);
+    if (display_image->debug != MagickFalse)
+      {
+        (void) LogMagickEvent(X11Event,GetMagickModule(),
+          "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
+          image_list[scene]->filename,(double) columns,(double) rows);
+        if (image_list[scene]->colors != 0)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
+            image_list[scene]->colors);
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
+          image_list[scene]->magick);
+      }
+    /*
+      Create the X pixmap.
+    */
+    window_info.pixmap=XCreatePixmap(display,window_info.id,width,height,
+      window_info.depth);
+    if (window_info.pixmap == (Pixmap) NULL)
+      ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
+        images->filename);
+    /*
+      Display pixmap on the window.
+    */
+    if ((width > window_info.width) || (height > window_info.height))
+      (void) XFillRectangle(display,window_info.pixmap,
+        window_info.annotate_context,0,0,width,height);
+    (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
+      window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
+      window_info.height);
+    (void) XSetWindowBackgroundPixmap(display,window_info.id,
+      window_info.pixmap);
+    (void) XClearWindow(display,window_info.id);
+    window_info.pixmaps[scene]=window_info.pixmap;
+    window_info.matte_pixmaps[scene]=window_info.matte_pixmap;
+    if (image_list[scene]->matte)
+      (void) XClearWindow(display,window_info.id);
+    delay=1000*image_list[scene]->delay/MagickMax(
+      image_list[scene]->ticks_per_second,1L);
+    XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
+  }
+  window_info.pixel_info=(&pixel);
+  /*
+    Display pixmap on the window.
+  */
+  (void) XSelectInput(display,window_info.id,SubstructureNotifyMask);
+  event.type=Expose;
+  do
+  {
+    for (scene=0; scene < (int) number_scenes; scene++)
+    {
+      if (XEventsQueued(display,QueuedAfterFlush) > 0)
+        {
+          (void) XNextEvent(display,&event);
+          if (event.type == DestroyNotify)
+            break;
+        }
+      window_info.pixmap=window_info.pixmaps[scene];
+      window_info.matte_pixmap=window_info.matte_pixmaps[scene];
+      (void) XSetWindowBackgroundPixmap(display,window_info.id,
+        window_info.pixmap);
+      (void) XClearWindow(display,window_info.id);
+      (void) XSync(display,MagickFalse);
+      delay=1000*image_list[scene]->delay/MagickMax(
+        image_list[scene]->ticks_per_second,1L);
+      XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
+    }
+  } while (event.type != DestroyNotify);
+  (void) XSync(display,MagickFalse);
+  image_list=(Image **) RelinquishMagickMemory(image_list);
+  images=DestroyImageList(images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X A n i m a t e I m a g e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XAnimateImages() displays an image via X11.
+%
+%  The format of the XAnimateImages method is:
+%
+%      Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
+%        char **argv,const int argc,Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o argv: Specifies the application's argument list.
+%
+%    o argc: Specifies the number of arguments.
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *XAnimateImages(Display *display,
+  XResourceInfo *resource_info,char **argv,const int argc,Image *images)
+{
+#define MagickMenus  4
+#define MaXWindows  8
+#define MagickTitle  "Commands"
+
+  static const char
+    *CommandMenu[]=
+    {
+      "Animate",
+      "Speed",
+      "Direction",
+      "Help",
+      "Image Info",
+      "Quit",
+      (char *) NULL
+    },
+    *AnimateMenu[]=
+    {
+      "Open...",
+      "Play",
+      "Step",
+      "Repeat",
+      "Auto Reverse",
+      "Save...",
+      (char *) NULL
+    },
+    *SpeedMenu[]=
+    {
+      "Faster",
+      "Slower",
+      (char *) NULL
+    },
+    *DirectionMenu[]=
+    {
+      "Forward",
+      "Reverse",
+      (char *) NULL
+    },
+    *HelpMenu[]=
+    {
+      "Overview",
+      "Browse Documentation",
+      "About Animate",
+      (char *) NULL
+    };
+
+  static const char
+    **Menus[MagickMenus]=
+    {
+      AnimateMenu,
+      SpeedMenu,
+      DirectionMenu,
+      HelpMenu
+    };
+
+  static const CommandType
+    CommandMenus[]=
+    {
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      InfoCommand,
+      QuitCommand
+    },
+    CommandTypes[]=
+    {
+      OpenCommand,
+      PlayCommand,
+      StepCommand,
+      RepeatCommand,
+      AutoReverseCommand,
+      SaveCommand
+    },
+    SpeedCommands[]=
+    {
+      FasterCommand,
+      SlowerCommand
+    },
+    DirectionCommands[]=
+    {
+      ForwardCommand,
+      ReverseCommand
+    },
+    HelpCommands[]=
+    {
+      HelpCommand,
+      BrowseDocumentationCommand,
+      VersionCommand
+    };
+
+  static const CommandType
+    *Commands[MagickMenus]=
+    {
+      CommandTypes,
+      SpeedCommands,
+      DirectionCommands,
+      HelpCommands
+    };
+
+  char
+    command[MaxTextExtent],
+    *directory,
+    geometry[MaxTextExtent],
+    resource_name[MaxTextExtent];
+
+  CommandType
+    command_type;
+
+  Image
+    *coalesce_image,
+    *display_image,
+    *image,
+    **image_list,
+    *nexus;
+
+  int
+    status;
+
+  KeySym
+    key_symbol;
+
+  MagickStatusType
+    context_mask,
+    state;
+
+  RectangleInfo
+    geometry_info;
+
+  register char
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    first_scene,
+    iterations,
+    scene;
+
+  static char
+    working_directory[MaxTextExtent];
+
+  static size_t
+    number_windows;
+
+  static XWindowInfo
+    *magick_windows[MaXWindows];
+
+  time_t
+    timestamp;
+
+  size_t
+    delay,
+    number_scenes;
+
+  WarningHandler
+    warning_handler;
+
+  Window
+    root_window;
+
+  XClassHint
+    *class_hints;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XGCValues
+    context_values;
+
+  XPixelInfo
+    *icon_pixel,
+    *pixel;
+
+  XResourceInfo
+    *icon_resources;
+
+  XStandardColormap
+    *icon_map,
+    *map_info;
+
+  XTextProperty
+    window_name;
+
+  XVisualInfo
+    *icon_visual,
+    *visual_info;
+
+  XWindowChanges
+    window_changes;
+
+  XWindows
+    *windows;
+
+  XWMHints
+    *manager_hints;
+
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  warning_handler=(WarningHandler) NULL;
+  windows=XSetWindows((XWindows *) ~0);
+  if (windows != (XWindows *) NULL)
+    {
+      int
+        status;
+
+      status=chdir(working_directory);
+      if (status == -1)
+        (void) ThrowMagickException(&images->exception,GetMagickModule(),
+          FileOpenError,"UnableToOpenFile","%s",working_directory);
+      warning_handler=resource_info->display_warnings ?
+        SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
+      warning_handler=resource_info->display_warnings ?
+        SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
+    }
+  else
+    {
+      register Image
+        *p;
+
+      /*
+        Initialize window structure.
+      */
+      for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+      {
+        if (p->storage_class == DirectClass)
+          {
+            resource_info->colors=0;
+            break;
+          }
+        if (p->colors > resource_info->colors)
+          resource_info->colors=p->colors;
+      }
+      windows=XSetWindows(XInitializeWindows(display,resource_info));
+      if (windows == (XWindows *) NULL)
+        ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
+          images->filename);
+      /*
+        Initialize window id's.
+      */
+      number_windows=0;
+      magick_windows[number_windows++]=(&windows->icon);
+      magick_windows[number_windows++]=(&windows->backdrop);
+      magick_windows[number_windows++]=(&windows->image);
+      magick_windows[number_windows++]=(&windows->info);
+      magick_windows[number_windows++]=(&windows->command);
+      magick_windows[number_windows++]=(&windows->widget);
+      magick_windows[number_windows++]=(&windows->popup);
+      for (i=0; i < (ssize_t) number_windows; i++)
+        magick_windows[i]->id=(Window) NULL;
+    }
+  /*
+    Initialize font info.
+  */
+  if (windows->font_info != (XFontStruct *) NULL)
+    (void) XFreeFont(display,windows->font_info);
+  windows->font_info=XBestFont(display,resource_info,MagickFalse);
+  if (windows->font_info == (XFontStruct *) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
+      resource_info->font);
+  /*
+    Initialize Standard Colormap.
+  */
+  map_info=windows->map_info;
+  icon_map=windows->icon_map;
+  visual_info=windows->visual_info;
+  icon_visual=windows->icon_visual;
+  pixel=windows->pixel_info;
+  icon_pixel=windows->icon_pixel;
+  font_info=windows->font_info;
+  icon_resources=windows->icon_resources;
+  class_hints=windows->class_hints;
+  manager_hints=windows->manager_hints;
+  root_window=XRootWindow(display,visual_info->screen);
+  coalesce_image=CoalesceImages(images,&images->exception);
+  if (coalesce_image == (Image *) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
+      images->filename);
+  images=coalesce_image;
+  if (resource_info->map_type == (char *) NULL)
+    if ((visual_info->klass != TrueColor) &&
+        (visual_info->klass != DirectColor))
+      {
+        Image
+          *next;
+
+        /*
+          Determine if the sequence of images has the identical colormap.
+        */
+        for (next=images; next != (Image *) NULL; )
+        {
+          next->matte=MagickFalse;
+          if ((next->storage_class == DirectClass) ||
+              (next->colors != images->colors) ||
+              (next->colors > (size_t) visual_info->colormap_size))
+            break;
+          for (i=0; i < (ssize_t) images->colors; i++)
+            if (IsPixelPacketEquivalent(next->colormap+i,images->colormap+i) == MagickFalse)
+              break;
+          if (i < (ssize_t) images->colors)
+            break;
+          next=GetNextImageInList(next);
+        }
+        if (next != (Image *) NULL)
+          (void) RemapImages(resource_info->quantize_info,images,
+            (Image *) NULL);
+      }
+  /*
+    Sort images by increasing scene number.
+  */
+  number_scenes=GetImageListLength(images);
+  image_list=ImageListToArray(images,&images->exception);
+  if (image_list == (Image **) NULL)
+    ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
+      images->filename);
+  for (scene=0; scene < (ssize_t) number_scenes; scene++)
+    if (image_list[scene]->scene == 0)
+      break;
+  if (scene == (ssize_t) number_scenes)
+    qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
+  /*
+    Initialize Standard Colormap.
+  */
+  nexus=NewImageList();
+  display_image=image_list[0];
+  for (scene=0; scene < (ssize_t) number_scenes; scene++)
+  {
+    if ((resource_info->map_type != (char *) NULL) ||
+        (visual_info->klass == TrueColor) ||
+        (visual_info->klass == DirectColor))
+      (void) SetImageType(image_list[scene],image_list[scene]->matte ==
+        MagickFalse ? TrueColorType : TrueColorMatteType);
+    if ((display_image->columns < image_list[scene]->columns) &&
+        (display_image->rows < image_list[scene]->rows))
+      display_image=image_list[scene];
+  }
+  if (display_image->debug != MagickFalse)
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,(double)
+        display_image->scene,(double) display_image->columns,(double)
+        display_image->rows);
+      if (display_image->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
+          display_image->colors);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
+        display_image->magick);
+    }
+  XMakeStandardColormap(display,visual_info,resource_info,display_image,
+    map_info,pixel);
+  /*
+    Initialize graphic context.
+  */
+  windows->context.id=(Window) NULL;
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->context);
+  (void) CloneString(&class_hints->res_name,resource_info->client_name);
+  (void) CloneString(&class_hints->res_class,resource_info->client_name);
+  class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
+  manager_hints->flags=InputHint | StateHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=WithdrawnState;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->context);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (context)",windows->context.id);
+  context_values.background=pixel->background_color.pixel;
+  context_values.font=font_info->fid;
+  context_values.foreground=pixel->foreground_color.pixel;
+  context_values.graphics_exposures=MagickFalse;
+  context_mask=(MagickStatusType)
+    (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
+  if (pixel->annotate_context != (GC) NULL)
+    (void) XFreeGC(display,pixel->annotate_context);
+  pixel->annotate_context=
+    XCreateGC(display,windows->context.id,context_mask,&context_values);
+  if (pixel->annotate_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      images->filename);
+  context_values.background=pixel->depth_color.pixel;
+  if (pixel->widget_context != (GC) NULL)
+    (void) XFreeGC(display,pixel->widget_context);
+  pixel->widget_context=
+    XCreateGC(display,windows->context.id,context_mask,&context_values);
+  if (pixel->widget_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      images->filename);
+  context_values.background=pixel->foreground_color.pixel;
+  context_values.foreground=pixel->background_color.pixel;
+  context_values.plane_mask=
+    context_values.background ^ context_values.foreground;
+  if (pixel->highlight_context != (GC) NULL)
+    (void) XFreeGC(display,pixel->highlight_context);
+  pixel->highlight_context=XCreateGC(display,windows->context.id,
+    (size_t) (context_mask | GCPlaneMask),&context_values);
+  if (pixel->highlight_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      images->filename);
+  (void) XDestroyWindow(display,windows->context.id);
+  /*
+    Initialize icon window.
+  */
+  XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
+    icon_resources,&windows->icon);
+  windows->icon.geometry=resource_info->icon_geometry;
+  XBestIconSize(display,&windows->icon,display_image);
+  windows->icon.attributes.colormap=
+    XDefaultColormap(display,icon_visual->screen);
+  windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=IconicState;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->icon);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
+      windows->icon.id);
+  /*
+    Initialize graphic context for icon window.
+  */
+  if (icon_pixel->annotate_context != (GC) NULL)
+    (void) XFreeGC(display,icon_pixel->annotate_context);
+  context_values.background=icon_pixel->background_color.pixel;
+  context_values.foreground=icon_pixel->foreground_color.pixel;
+  icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
+    (size_t) (GCBackground | GCForeground),&context_values);
+  if (icon_pixel->annotate_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      images->filename);
+  windows->icon.annotate_context=icon_pixel->annotate_context;
+  /*
+    Initialize Image window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->image);
+  windows->image.shape=MagickTrue;  /* non-rectangular shape hint */
+  if (resource_info->use_shared_memory == MagickFalse)
+    windows->image.shared_memory=MagickFalse;
+  if (resource_info->title != (char *) NULL)
+    {
+      char
+        *title;
+
+      title=InterpretImageProperties(resource_info->image_info,display_image,
+        resource_info->title);
+      (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
+      (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
+      title=DestroyString(title);
+    }
+  else
+    {
+      char
+        filename[MaxTextExtent];
+
+      /*
+        Window name is the base of the filename.
+      */
+      GetPathComponent(display_image->magick_filename,TailPath,filename);
+      (void) FormatLocaleString(windows->image.name,MaxTextExtent,
+        "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,(double)
+        display_image->scene,(double) number_scenes);
+      (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
+    }
+  if (resource_info->immutable != MagickFalse)
+    windows->image.immutable=MagickTrue;
+  windows->image.shape=MagickTrue;
+  windows->image.geometry=resource_info->image_geometry;
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
+    XDisplayWidth(display,visual_info->screen),
+    XDisplayHeight(display,visual_info->screen));
+  geometry_info.width=display_image->columns;
+  geometry_info.height=display_image->rows;
+  geometry_info.x=0;
+  geometry_info.y=0;
+  (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
+    &geometry_info.width,&geometry_info.height);
+  windows->image.width=(unsigned int) geometry_info.width;
+  windows->image.height=(unsigned int) geometry_info.height;
+  windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
+    KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
+    PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->backdrop);
+  if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
+    {
+      /*
+        Initialize backdrop window.
+      */
+      windows->backdrop.x=0;
+      windows->backdrop.y=0;
+      (void) CloneString(&windows->backdrop.name,"ImageMagick Backdrop");
+      windows->backdrop.flags=(size_t) (USSize | USPosition);
+      windows->backdrop.width=(unsigned int)
+        XDisplayWidth(display,visual_info->screen);
+      windows->backdrop.height=(unsigned int)
+        XDisplayHeight(display,visual_info->screen);
+      windows->backdrop.border_width=0;
+      windows->backdrop.immutable=MagickTrue;
+      windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
+        ButtonReleaseMask;
+      windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
+        StructureNotifyMask;
+      manager_hints->flags=IconWindowHint | InputHint | StateHint;
+      manager_hints->icon_window=windows->icon.id;
+      manager_hints->input=MagickTrue;
+      manager_hints->initial_state=
+        resource_info->iconic ? IconicState : NormalState;
+      XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+        &windows->backdrop);
+      if (display_image->debug != MagickFalse)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),
+          "Window id: 0x%lx (backdrop)",windows->backdrop.id);
+      (void) XMapWindow(display,windows->backdrop.id);
+      (void) XClearWindow(display,windows->backdrop.id);
+      if (windows->image.id != (Window) NULL)
+        {
+          (void) XDestroyWindow(display,windows->image.id);
+          windows->image.id=(Window) NULL;
+        }
+      /*
+        Position image in the center the backdrop.
+      */
+      windows->image.flags|=USPosition;
+      windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
+        (windows->image.width/2);
+      windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
+        (windows->image.height/2);
+    }
+  manager_hints->flags=IconWindowHint | InputHint | StateHint;
+  manager_hints->icon_window=windows->icon.id;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=
+    resource_info->iconic ? IconicState : NormalState;
+  if (windows->group_leader.id != (Window) NULL)
+    {
+      /*
+        Follow the leader.
+      */
+      manager_hints->flags|=(MagickStatusType) WindowGroupHint;
+      manager_hints->window_group=windows->group_leader.id;
+      (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
+      if (display_image->debug != MagickFalse)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),
+          "Window id: 0x%lx (group leader)",windows->group_leader.id);
+    }
+  XMakeWindow(display,
+    (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
+    argv,argc,class_hints,manager_hints,&windows->image);
+  (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
+    XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
+  if (windows->group_leader.id != (Window) NULL)
+    (void) XSetTransientForHint(display,windows->image.id,
+      windows->group_leader.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
+      windows->image.id);
+  /*
+    Initialize Info widget.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->info);
+  (void) CloneString(&windows->info.name,"Info");
+  (void) CloneString(&windows->info.icon_name,"Info");
+  windows->info.border_width=1;
+  windows->info.x=2;
+  windows->info.y=2;
+  windows->info.flags|=PPosition;
+  windows->info.attributes.win_gravity=UnmapGravity;
+  windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
+    StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
+    &windows->info);
+  windows->info.highlight_stipple=XCreateBitmapFromData(display,
+    windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
+  windows->info.shadow_stipple=XCreateBitmapFromData(display,
+    windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
+  if (windows->image.mapped)
+    (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
+      windows->info.id);
+  /*
+    Initialize Command widget.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->command);
+  windows->command.data=MagickMenus;
+  (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
+  (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
+    resource_info->client_name);
+  windows->command.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  (void) CloneString(&windows->command.name,MagickTitle);
+  windows->command.border_width=0;
+  windows->command.flags|=PPosition;
+  windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
+    OwnerGrabButtonMask | StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->command);
+  windows->command.highlight_stipple=XCreateBitmapFromData(display,
+    windows->command.id,(char *) HighlightBitmap,HighlightWidth,
+    HighlightHeight);
+  windows->command.shadow_stipple=XCreateBitmapFromData(display,
+    windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (command)",windows->command.id);
+  /*
+    Initialize Widget window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->widget);
+  (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
+    resource_info->client_name);
+  windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  windows->widget.border_width=0;
+  windows->widget.flags|=PPosition;
+  windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
+    KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
+    StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->widget);
+  windows->widget.highlight_stipple=XCreateBitmapFromData(display,
+    windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
+  windows->widget.shadow_stipple=XCreateBitmapFromData(display,
+    windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (widget)",windows->widget.id);
+  /*
+    Initialize popup window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->popup);
+  windows->popup.border_width=0;
+  windows->popup.flags|=PPosition;
+  windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
+    KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->popup);
+  windows->popup.highlight_stipple=XCreateBitmapFromData(display,
+    windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
+  windows->popup.shadow_stipple=XCreateBitmapFromData(display,
+    windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (pop up)",windows->popup.id);
+  /*
+    Set out progress and warning handlers.
+  */
+  if (warning_handler == (WarningHandler) NULL)
+    {
+      warning_handler=resource_info->display_warnings ?
+        SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
+      warning_handler=resource_info->display_warnings ?
+        SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
+    }
+  /*
+    Initialize X image structure.
+  */
+  windows->image.x=0;
+  windows->image.y=0;
+  /*
+    Initialize image pixmaps structure.
+  */
+  window_changes.width=(int) windows->image.width;
+  window_changes.height=(int) windows->image.height;
+  (void) XReconfigureWMWindow(display,windows->image.id,windows->command.screen,
+    (unsigned int) (CWWidth | CWHeight),&window_changes);
+  windows->image.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
+    sizeof(*windows->image.pixmaps));
+  windows->image.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
+    sizeof(*windows->image.pixmaps));
+  if ((windows->image.pixmaps == (Pixmap *) NULL) ||
+      (windows->image.matte_pixmaps == (Pixmap *) NULL))
+    ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
+      images->filename);
+  if ((windows->image.mapped == MagickFalse) ||
+      (windows->backdrop.id != (Window) NULL))
+    (void) XMapWindow(display,windows->image.id);
+  XSetCursorState(display,windows,MagickTrue);
+  for (scene=0; scene < (ssize_t) number_scenes; scene++)
+  {
+    unsigned int
+      columns,
+      rows;
+
+    /*
+      Create X image.
+    */
+    (void) TransformImageColorspace(image_list[scene],RGBColorspace);
+    windows->image.pixmap=(Pixmap) NULL;
+    windows->image.matte_pixmap=(Pixmap) NULL;
+    if ((resource_info->map_type != (char *) NULL) ||
+        (visual_info->klass == TrueColor) ||
+        (visual_info->klass == DirectColor))
+      if (image_list[scene]->storage_class == PseudoClass)
+        XGetPixelInfo(display,visual_info,map_info,resource_info,
+          image_list[scene],windows->image.pixel_info);
+    columns=(unsigned int) image_list[scene]->columns;
+    rows=(unsigned int) image_list[scene]->rows;
+    if ((image_list[scene]->columns != columns) ||
+        (image_list[scene]->rows != rows))
+      ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+        image_list[scene]->filename);
+    status=XMakeImage(display,resource_info,&windows->image,image_list[scene],
+      columns,rows);
+    if (status == MagickFalse)
+      ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+        images->filename);
+    if (image_list[scene]->debug != MagickFalse)
+      {
+        (void) LogMagickEvent(X11Event,GetMagickModule(),
+          "Image: [%.20g] %s %.20gx%.20g ",(double) image_list[scene]->scene,
+          image_list[scene]->filename,(double) columns,(double) rows);
+        if (image_list[scene]->colors != 0)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
+            image_list[scene]->colors);
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
+          image_list[scene]->magick);
+      }
+    /*
+      Window name is the base of the filename.
+    */
+    if (resource_info->title != (char *) NULL)
+      {
+        char
+          *title;
+
+        title=InterpretImageProperties(resource_info->image_info,
+          image_list[scene],resource_info->title);
+        (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
+        title=DestroyString(title);
+      }
+    else
+      {
+        p=image_list[scene]->magick_filename+
+          strlen(image_list[scene]->magick_filename)-1;
+        while ((p > image_list[scene]->magick_filename) && (*(p-1) != '/'))
+          p--;
+        (void) FormatLocaleString(windows->image.name,MaxTextExtent,
+          "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double) scene+1,
+          (double) number_scenes);
+      }
+    status=XStringListToTextProperty(&windows->image.name,1,&window_name);
+    if (status != Success)
+      {
+        XSetWMName(display,windows->image.id,&window_name);
+        (void) XFree((void *) window_name.value);
+      }
+    windows->image.pixmaps[scene]=windows->image.pixmap;
+    windows->image.matte_pixmaps[scene]=windows->image.matte_pixmap;
+    if (scene == 0)
+      {
+        event.xexpose.x=0;
+        event.xexpose.y=0;
+        event.xexpose.width=(int) image_list[scene]->columns;
+        event.xexpose.height=(int) image_list[scene]->rows;
+        XRefreshWindow(display,&windows->image,&event);
+        (void) XSync(display,MagickFalse);
+    }
+  }
+  XSetCursorState(display,windows,MagickFalse);
+  if (windows->command.mapped)
+    (void) XMapRaised(display,windows->command.id);
+  /*
+    Respond to events.
+  */
+  nexus=NewImageList();
+  scene=0;
+  first_scene=0;
+  iterations=0;
+  image=image_list[0];
+  state=(MagickStatusType) (ForwardAnimationState | RepeatAnimationState);
+  (void) XMagickCommand(display,resource_info,windows,PlayCommand,&images,
+    &state);
+  do
+  {
+    if (XEventsQueued(display,QueuedAfterFlush) == 0)
+      if ((state & PlayAnimationState) || (state & StepAnimationState))
+        {
+          MagickBooleanType
+            pause;
+
+          pause=MagickFalse;
+          delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
+          XDelay(display,resource_info->delay*(delay == 0 ? 10 : delay));
+          if (state & ForwardAnimationState)
+            {
+              /*
+                Forward animation:  increment scene number.
+              */
+              if (scene < ((ssize_t) number_scenes-1))
+                scene++;
+              else
+                {
+                  iterations++;
+                  if (iterations == (ssize_t) image_list[0]->iterations)
+                    {
+                      iterations=0;
+                      state|=ExitState;
+                    }
+                  if ((state & AutoReverseAnimationState) != 0)
+                    {
+                      state&=(~ForwardAnimationState);
+                      scene--;
+                    }
+                  else
+                    {
+                      if ((state & RepeatAnimationState) == 0)
+                        state&=(~PlayAnimationState);
+                      scene=first_scene;
+                      pause=MagickTrue;
+                    }
+                }
+            }
+          else
+            {
+              /*
+                Reverse animation:  decrement scene number.
+              */
+              if (scene > first_scene)
+                scene--;
+              else
+                {
+                  iterations++;
+                  if (iterations == (ssize_t) image_list[0]->iterations)
+                    {
+                      iterations=0;
+                      state&=(~RepeatAnimationState);
+                    }
+                  if (state & AutoReverseAnimationState)
+                    {
+                      state|=ForwardAnimationState;
+                      scene=first_scene;
+                      pause=MagickTrue;
+                    }
+                  else
+                    {
+                      if ((state & RepeatAnimationState) == MagickFalse)
+                        state&=(~PlayAnimationState);
+                      scene=(ssize_t) number_scenes-1;
+                    }
+                }
+            }
+          scene=MagickMax(scene,0);
+          image=image_list[scene];
+          if ((image != (Image *) NULL) && (image->start_loop != 0))
+            first_scene=scene;
+          if ((state & StepAnimationState) ||
+              (resource_info->title != (char *) NULL))
+            {
+              /*
+                Update window title.
+              */
+              p=image_list[scene]->filename+
+                strlen(image_list[scene]->filename)-1;
+              while ((p > image_list[scene]->filename) && (*(p-1) != '/'))
+                p--;
+              (void) FormatLocaleString(windows->image.name,MaxTextExtent,
+                "%s: %s[%.20g of %.20g]",MagickPackageName,p,(double)
+                scene+1,(double) number_scenes);
+              if (resource_info->title != (char *) NULL)
+                {
+                  char
+                    *title;
+
+                  title=InterpretImageProperties(resource_info->image_info,
+                    image,resource_info->title);
+                  (void) CopyMagickString(windows->image.name,title,
+                    MaxTextExtent);
+                  title=DestroyString(title);
+                }
+              status=XStringListToTextProperty(&windows->image.name,1,
+                &window_name);
+              if (status != Success)
+                {
+                  XSetWMName(display,windows->image.id,&window_name);
+                  (void) XFree((void *) window_name.value);
+                }
+            }
+          /*
+            Copy X pixmap to Image window.
+          */
+          XGetPixelInfo(display,visual_info,map_info,resource_info,
+            image_list[scene],windows->image.pixel_info);
+          windows->image.ximage->width=(int) image->columns;
+          windows->image.ximage->height=(int) image->rows;
+          windows->image.pixmap=windows->image.pixmaps[scene];
+          windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
+          event.xexpose.x=0;
+          event.xexpose.y=0;
+          event.xexpose.width=(int) image->columns;
+          event.xexpose.height=(int) image->rows;
+          if ((state & ExitState) == 0)
+            {
+              XRefreshWindow(display,&windows->image,&event);
+              (void) XSync(display,MagickFalse);
+            }
+          state&=(~StepAnimationState);
+          if (pause != MagickFalse)
+            for (i=0; i < (ssize_t) resource_info->pause; i++)
+            {
+              int
+                status;
+
+              status=XCheckTypedWindowEvent(display,windows->image.id,KeyPress,
+                &event);
+              if (status != 0)
+                {
+                  int
+                    length;
+
+                  length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
+                    sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+                  *(command+length)='\0';
+                  if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
+                    {
+                      XClientMessage(display,windows->image.id,
+                        windows->im_protocols,windows->im_exit,CurrentTime);
+                      break;
+                    }
+                }
+              (void) sleep(1);
+            }
+          continue;
+        }
+    /*
+      Handle a window event.
+    */
+    timestamp=time((time_t *) NULL);
+    (void) XNextEvent(display,&event);
+    if (windows->image.stasis == MagickFalse)
+      windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
+        MagickTrue : MagickFalse;
+    if (event.xany.window == windows->command.id)
+      {
+        int
+          id;
+
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,CommandMenu,&event);
+        if (id < 0)
+          continue;
+        (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
+        command_type=CommandMenus[id];
+        if (id < MagickMenus)
+          {
+            int
+              entry;
+
+            /*
+              Select a command from a pop-up menu.
+            */
+            entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
+              command);
+            if (entry < 0)
+              continue;
+            (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
+            command_type=Commands[id][entry];
+          }
+        if (command_type != NullCommand)
+          nexus=XMagickCommand(display,resource_info,windows,
+            command_type,&image,&state);
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        if ((event.xbutton.button == Button3) &&
+            (event.xbutton.state & Mod1Mask))
+          {
+            /*
+              Convert Alt-Button3 to Button2.
+            */
+            event.xbutton.button=Button2;
+            event.xbutton.state&=(~Mod1Mask);
+          }
+        if (event.xbutton.window == windows->backdrop.id)
+          {
+            (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
+              event.xbutton.time);
+            break;
+          }
+        if (event.xbutton.window == windows->image.id)
+          {
+            if (resource_info->immutable != MagickFalse)
+              {
+                state|=ExitState;
+                break;
+              }
+            /*
+              Map/unmap Command widget.
+            */
+            if (windows->command.mapped)
+              (void) XWithdrawWindow(display,windows->command.id,
+                windows->command.screen);
+            else
+              {
+                (void) XCommandWidget(display,windows,CommandMenu,
+                  (XEvent *) NULL);
+                (void) XMapRaised(display,windows->command.id);
+              }
+          }
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        break;
+      }
+      case ClientMessage:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Client Message: 0x%lx 0x%lx %d 0x%lx",(unsigned long)
+            event.xclient.window,(unsigned long) event.xclient.message_type,
+            event.xclient.format,(unsigned long) event.xclient.data.l[0]);
+        if (event.xclient.message_type == windows->im_protocols)
+          {
+            if (*event.xclient.data.l == (long) windows->im_update_colormap)
+              {
+                /*
+                  Update graphic context and window colormap.
+                */
+                for (i=0; i < (ssize_t) number_windows; i++)
+                {
+                  if (magick_windows[i]->id == windows->icon.id)
+                    continue;
+                  context_values.background=pixel->background_color.pixel;
+                  context_values.foreground=pixel->foreground_color.pixel;
+                  (void) XChangeGC(display,magick_windows[i]->annotate_context,
+                    context_mask,&context_values);
+                  (void) XChangeGC(display,magick_windows[i]->widget_context,
+                    context_mask,&context_values);
+                  context_values.background=pixel->foreground_color.pixel;
+                  context_values.foreground=pixel->background_color.pixel;
+                  context_values.plane_mask=
+                    context_values.background ^ context_values.foreground;
+                  (void) XChangeGC(display,magick_windows[i]->highlight_context,
+                    (size_t) (context_mask | GCPlaneMask),
+                    &context_values);
+                  magick_windows[i]->attributes.background_pixel=
+                    pixel->background_color.pixel;
+                  magick_windows[i]->attributes.border_pixel=
+                    pixel->border_color.pixel;
+                  magick_windows[i]->attributes.colormap=map_info->colormap;
+                  (void) XChangeWindowAttributes(display,magick_windows[i]->id,
+                    (unsigned long) magick_windows[i]->mask,
+                    &magick_windows[i]->attributes);
+                }
+                if (windows->backdrop.id != (Window) NULL)
+                  (void) XInstallColormap(display,map_info->colormap);
+                break;
+              }
+            if (*event.xclient.data.l == (long) windows->im_exit)
+              {
+                state|=ExitState;
+                break;
+              }
+            break;
+          }
+        if (event.xclient.message_type == windows->dnd_protocols)
+          {
+            Atom
+              selection,
+              type;
+
+            int
+              format,
+              status;
+
+            unsigned char
+              *data;
+
+            unsigned long
+              after,
+              length;
+
+            /*
+              Display image named by the Drag-and-Drop selection.
+            */
+            if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
+              break;
+            selection=XInternAtom(display,"DndSelection",MagickFalse);
+            status=XGetWindowProperty(display,root_window,selection,0L,2047L,
+              MagickFalse,(Atom) AnyPropertyType,&type,&format,&length,&after,
+              &data);
+            if ((status != Success) || (length == 0))
+              break;
+            if (*event.xclient.data.l == 2)
+              {
+                /*
+                  Offix DND.
+                */
+                (void) CopyMagickString(resource_info->image_info->filename,
+                  (char *) data,MaxTextExtent);
+              }
+            else
+              {
+                /*
+                  XDND.
+                */
+                if (LocaleNCompare((char *) data,"file:",5) != 0)
+                  {
+                    (void) XFree((void *) data);
+                    break;
+                  }
+                (void) CopyMagickString(resource_info->image_info->filename,
+                  ((char *) data)+5,MaxTextExtent);
+              }
+            nexus=ReadImage(resource_info->image_info,&image->exception);
+            CatchException(&image->exception);
+            if (nexus != (Image *) NULL)
+              state|=ExitState;
+            (void) XFree((void *) data);
+            break;
+          }
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (long) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (long) windows->wm_delete_window)
+          break;
+        (void) XWithdrawWindow(display,event.xclient.window,
+          visual_info->screen);
+        if (event.xclient.window == windows->image.id)
+          {
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
+            event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
+            event.xconfigure.y,event.xconfigure.send_event);
+        if (event.xconfigure.window == windows->image.id)
+          {
+            if (event.xconfigure.send_event != 0)
+              {
+                XWindowChanges
+                  window_changes;
+
+                /*
+                  Position the transient windows relative of the Image window.
+                */
+                if (windows->command.geometry == (char *) NULL)
+                  if (windows->command.mapped == MagickFalse)
+                    {
+                       windows->command.x=
+                          event.xconfigure.x-windows->command.width-25;
+                        windows->command.y=event.xconfigure.y;
+                        XConstrainWindowPosition(display,&windows->command);
+                        window_changes.x=windows->command.x;
+                        window_changes.y=windows->command.y;
+                        (void) XReconfigureWMWindow(display,windows->command.id,
+                          windows->command.screen,(unsigned int) (CWX | CWY),
+                          &window_changes);
+                    }
+                if (windows->widget.geometry == (char *) NULL)
+                  if (windows->widget.mapped == MagickFalse)
+                    {
+                      windows->widget.x=
+                        event.xconfigure.x+event.xconfigure.width/10;
+                      windows->widget.y=
+                        event.xconfigure.y+event.xconfigure.height/10;
+                      XConstrainWindowPosition(display,&windows->widget);
+                      window_changes.x=windows->widget.x;
+                      window_changes.y=windows->widget.y;
+                      (void) XReconfigureWMWindow(display,windows->widget.id,
+                        windows->widget.screen,(unsigned int) (CWX | CWY),
+                        &window_changes);
+                    }
+              }
+            /*
+              Image window has a new configuration.
+            */
+            windows->image.width=(unsigned int) event.xconfigure.width;
+            windows->image.height=(unsigned int) event.xconfigure.height;
+            break;
+          }
+        if (event.xconfigure.window == windows->icon.id)
+          {
+            /*
+              Icon window has a new configuration.
+            */
+            windows->icon.width=(unsigned int) event.xconfigure.width;
+            windows->icon.height=(unsigned int) event.xconfigure.height;
+            break;
+          }
+        break;
+      }
+      case DestroyNotify:
+      {
+        /*
+          Group leader has exited.
+        */
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Destroy Notify: 0x%lx",event.xdestroywindow.window);
+        if (event.xdestroywindow.window == windows->group_leader.id)
+          {
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case EnterNotify:
+      {
+        /*
+          Selectively install colormap.
+        */
+        if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
+          if (event.xcrossing.mode != NotifyUngrab)
+            XInstallColormap(display,map_info->colormap);
+        break;
+      }
+      case Expose:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
+            event.xexpose.width,event.xexpose.height,event.xexpose.x,
+            event.xexpose.y);
+        /*
+          Repaint windows that are now exposed.
+        */
+        if (event.xexpose.window == windows->image.id)
+          {
+            windows->image.pixmap=windows->image.pixmaps[scene];
+            windows->image.matte_pixmap=windows->image.matte_pixmaps[scene];
+            XRefreshWindow(display,&windows->image,&event);
+            break;
+          }
+        if (event.xexpose.window == windows->icon.id)
+          if (event.xexpose.count == 0)
+            {
+              XRefreshWindow(display,&windows->icon,&event);
+              break;
+            }
+        break;
+      }
+      case KeyPress:
+      {
+        static int
+          length;
+
+        /*
+          Respond to a user key press.
+        */
+        length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Key press: 0x%lx (%c)",(unsigned long) key_symbol,*command);
+        command_type=NullCommand;
+        switch (key_symbol)
+        {
+          case XK_o:
+          {
+            if ((event.xkey.state & ControlMask) == MagickFalse)
+              break;
+            command_type=OpenCommand;
+            break;
+          }
+          case XK_BackSpace:
+          {
+            command_type=StepBackwardCommand;
+            break;
+          }
+          case XK_space:
+          {
+            command_type=StepForwardCommand;
+            break;
+          }
+          case XK_less:
+          {
+            command_type=FasterCommand;
+            break;
+          }
+          case XK_greater:
+          {
+            command_type=SlowerCommand;
+            break;
+          }
+          case XK_F1:
+          {
+            command_type=HelpCommand;
+            break;
+          }
+          case XK_Find:
+          {
+            command_type=BrowseDocumentationCommand;
+            break;
+          }
+          case XK_question:
+          {
+            command_type=InfoCommand;
+            break;
+          }
+          case XK_q:
+          case XK_Escape:
+          {
+            command_type=QuitCommand;
+            break;
+          }
+          default:
+            break;
+        }
+        if (command_type != NullCommand)
+          nexus=XMagickCommand(display,resource_info,windows,
+            command_type,&image,&state);
+        break;
+      }
+      case KeyRelease:
+      {
+        /*
+          Respond to a user key release.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
+        break;
+      }
+      case LeaveNotify:
+      {
+        /*
+          Selectively uninstall colormap.
+        */
+        if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
+          if (event.xcrossing.mode != NotifyUngrab)
+            XUninstallColormap(display,map_info->colormap);
+        break;
+      }
+      case MapNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
+            event.xmap.window);
+        if (event.xmap.window == windows->backdrop.id)
+          {
+            (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
+              CurrentTime);
+            windows->backdrop.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->image.id)
+          {
+            if (windows->backdrop.id != (Window) NULL)
+              (void) XInstallColormap(display,map_info->colormap);
+            if (LocaleCompare(image_list[0]->magick,"LOGO") == 0)
+              {
+                if (LocaleCompare(display_image->filename,"LOGO") == 0)
+                  nexus=XMagickCommand(display,resource_info,windows,
+                    OpenCommand,&image,&state);
+                else
+                  state|=ExitState;
+              }
+            windows->image.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->info.id)
+          {
+            windows->info.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->icon.id)
+          {
+            /*
+              Create an icon image.
+            */
+            XMakeStandardColormap(display,icon_visual,icon_resources,
+              display_image,icon_map,icon_pixel);
+            (void) XMakeImage(display,icon_resources,&windows->icon,
+              display_image,windows->icon.width,windows->icon.height);
+            (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
+              windows->icon.pixmap);
+            (void) XClearWindow(display,windows->icon.id);
+            (void) XWithdrawWindow(display,windows->info.id,
+              windows->info.screen);
+            windows->icon.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->command.id)
+          {
+            windows->command.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->popup.id)
+          {
+            windows->popup.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->widget.id)
+          {
+            windows->widget.mapped=MagickTrue;
+            break;
+          }
+        break;
+      }
+      case MappingNotify:
+      {
+        (void) XRefreshKeyboardMapping(&event.xmapping);
+        break;
+      }
+      case NoExpose:
+        break;
+      case PropertyNotify:
+      {
+        Atom
+          type;
+
+        int
+          format,
+          status;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Property Notify: 0x%lx 0x%lx %d",(unsigned long)
+            event.xproperty.window,(unsigned long) event.xproperty.atom,
+            event.xproperty.state);
+        if (event.xproperty.atom != windows->im_remote_command)
+          break;
+        /*
+          Display image named by the remote command protocol.
+        */
+        status=XGetWindowProperty(display,event.xproperty.window,
+          event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
+          AnyPropertyType,&type,&format,&length,&after,&data);
+        if ((status != Success) || (length == 0))
+          break;
+        (void) CopyMagickString(resource_info->image_info->filename,
+          (char *) data,MaxTextExtent);
+        nexus=ReadImage(resource_info->image_info,&image->exception);
+        CatchException(&image->exception);
+        if (nexus != (Image *) NULL)
+          state|=ExitState;
+        (void) XFree((void *) data);
+        break;
+      }
+      case ReparentNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
+            event.xreparent.window);
+        break;
+      }
+      case UnmapNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Unmap Notify: 0x%lx",event.xunmap.window);
+        if (event.xunmap.window == windows->backdrop.id)
+          {
+            windows->backdrop.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->image.id)
+          {
+            windows->image.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->info.id)
+          {
+            windows->info.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->icon.id)
+          {
+            if (map_info->colormap == icon_map->colormap)
+              XConfigureImageColormap(display,resource_info,windows,
+                display_image);
+            (void) XFreeStandardColormap(display,icon_visual,icon_map,
+              icon_pixel);
+            windows->icon.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->command.id)
+          {
+            windows->command.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->popup.id)
+          {
+            if (windows->backdrop.id != (Window) NULL)
+              (void) XSetInputFocus(display,windows->image.id,RevertToParent,
+                CurrentTime);
+            windows->popup.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->widget.id)
+          {
+            if (windows->backdrop.id != (Window) NULL)
+              (void) XSetInputFocus(display,windows->image.id,RevertToParent,
+                CurrentTime);
+            windows->widget.mapped=MagickFalse;
+            break;
+          }
+        break;
+      }
+      default:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
+            event.type);
+        break;
+      }
+    }
+  }
+  while (!(state & ExitState));
+  image_list=(Image **) RelinquishMagickMemory(image_list);
+  images=DestroyImageList(images);
+  if ((windows->visual_info->klass == GrayScale) ||
+      (windows->visual_info->klass == PseudoColor) ||
+      (windows->visual_info->klass == DirectColor))
+    {
+      /*
+        Withdraw windows.
+      */
+      if (windows->info.mapped)
+        (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      if (windows->command.mapped)
+        (void) XWithdrawWindow(display,windows->command.id,
+          windows->command.screen);
+    }
+  if (resource_info->backdrop == MagickFalse)
+    if (windows->backdrop.mapped)
+      {
+        (void) XWithdrawWindow(display,windows->backdrop.id,\
+          windows->backdrop.screen);
+        (void) XDestroyWindow(display,windows->backdrop.id);
+        windows->backdrop.id=(Window) NULL;
+        (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);
+        (void) XDestroyWindow(display,windows->image.id);
+        windows->image.id=(Window) NULL;
+      }
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  for (scene=1; scene < (ssize_t) number_scenes; scene++)
+  {
+    if (windows->image.pixmaps[scene] != (Pixmap) NULL)
+      (void) XFreePixmap(display,windows->image.pixmaps[scene]);
+    windows->image.pixmaps[scene]=(Pixmap) NULL;
+    if (windows->image.matte_pixmaps[scene] != (Pixmap) NULL)
+      (void) XFreePixmap(display,windows->image.matte_pixmaps[scene]);
+    windows->image.matte_pixmaps[scene]=(Pixmap) NULL;
+  }
+  XSetCursorState(display,windows,MagickFalse);
+  windows->image.pixmaps=(Pixmap *)
+    RelinquishMagickMemory(windows->image.pixmaps);
+  windows->image.matte_pixmaps=(Pixmap *)
+    RelinquishMagickMemory(windows->image.matte_pixmaps);
+  if (nexus == (Image *) NULL)
+    {
+      /*
+        Free X resources.
+      */
+      if (windows->image.mapped != MagickFalse)
+        (void) XWithdrawWindow(display,windows->image.id,windows->image.screen);      XDelay(display,SuspendTime);
+      (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
+      if (resource_info->map_type == (char *) NULL)
+        (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
+      DestroyXResources();
+    }
+  (void) XSync(display,MagickFalse);
+  /*
+    Restore our progress monitor and warning handlers.
+  */
+  (void) SetErrorHandler(warning_handler);
+  (void) SetWarningHandler(warning_handler);
+  /*
+    Change to home directory.
+  */
+  directory=getcwd(working_directory,MaxTextExtent);
+  (void) directory;
+  status=chdir(resource_info->home_directory);
+  if (status == -1)
+    (void) ThrowMagickException(&images->exception,GetMagickModule(),
+      FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
+  return(nexus);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S a v e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSaveImage() saves an image to a file.
+%
+%  The format of the XSaveImage method is:
+%
+%      MagickBooleanType XSaveImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o status: Method XSaveImage return True if the image is
+%      written.  False is returned is there is a memory shortage or if the
+%      image fails to write.
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XSaveImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  char
+    filename[MaxTextExtent];
+
+  ImageInfo
+    *image_info;
+
+  MagickStatusType
+    status;
+
+  /*
+    Request file name from user.
+  */
+  if (resource_info->write_filename != (char *) NULL)
+    (void) CopyMagickString(filename,resource_info->write_filename,
+      MaxTextExtent);
+  else
+    {
+      char
+        path[MaxTextExtent];
+
+      int
+        status;
+
+      GetPathComponent(image->filename,HeadPath,path);
+      GetPathComponent(image->filename,TailPath,filename);
+      status=chdir(path);
+      if (status == -1)
+        (void) ThrowMagickException(&image->exception,GetMagickModule(),
+          FileOpenError,"UnableToOpenFile","%s",path);
+    }
+  XFileBrowserWidget(display,windows,"Save",filename);
+  if (*filename == '\0')
+    return(MagickTrue);
+  if (IsPathAccessible(filename) != MagickFalse)
+    {
+      int
+        status;
+
+      /*
+        File exists-- seek user's permission before overwriting.
+      */
+      status=XConfirmWidget(display,windows,"Overwrite",filename);
+      if (status == 0)
+        return(MagickTrue);
+    }
+  image_info=CloneImageInfo(resource_info->image_info);
+  (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+  (void) SetImageInfo(image_info,1,&image->exception);
+  if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
+      (LocaleCompare(image_info->magick,"JPG") == 0))
+    {
+      char
+        quality[MaxTextExtent];
+
+      int
+        status;
+
+      /*
+        Request JPEG quality from user.
+      */
+      (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
+        image_info->quality);
+      status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
+        quality);
+      if (*quality == '\0')
+        return(MagickTrue);
+      image->quality=StringToUnsignedLong(quality);
+      image_info->interlace=status != MagickFalse ?  NoInterlace :
+        PlaneInterlace;
+    }
+  if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
+      (LocaleCompare(image_info->magick,"PDF") == 0) ||
+      (LocaleCompare(image_info->magick,"PS") == 0) ||
+      (LocaleCompare(image_info->magick,"PS2") == 0))
+    {
+      char
+        geometry[MaxTextExtent];
+
+      /*
+        Request page geometry from user.
+      */
+      (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
+      if (LocaleCompare(image_info->magick,"PDF") == 0)
+        (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
+      if (image_info->page != (char *) NULL)
+        (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
+      XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
+        "Select page geometry:",geometry);
+      if (*geometry != '\0')
+        image_info->page=GetPageGeometry(geometry);
+    }
+  /*
+    Write image.
+  */
+  image=GetFirstImageInList(image);
+  status=WriteImages(image_info,image,filename,&image->exception);
+  if (status != MagickFalse)
+    image->taint=MagickFalse;
+  image_info=DestroyImageInfo(image_info);
+  XSetCursorState(display,windows,MagickFalse);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+#else
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A n i m a t e I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AnimateImages() repeatedly displays an image sequence to any X window
+%  screen.  It returns a value other than 0 if successful.  Check the
+%  exception member of image to determine the reason for any failure.
+%
+%  The format of the AnimateImages method is:
+%
+%      MagickBooleanType AnimateImages(const ImageInfo *image_info,
+%        Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
+  Image *image)
+{
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
+    image->filename);
+  return(MagickFalse);
+}
+#endif
diff --git a/MagickCore/animate.h b/MagickCore/animate.h
new file mode 100644
index 0000000..cf7ece6
--- /dev/null
+++ b/MagickCore/animate.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore methods to interactively animate an image sequence.
+*/
+#ifndef _MAGICKCORE_ANIMATE_H
+#define _MAGICKCORE_ANIMATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  AnimateImages(const ImageInfo *,Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/annotate.c b/MagickCore/annotate.c
new file mode 100644
index 0000000..ccdf213
--- /dev/null
+++ b/MagickCore/annotate.c
@@ -0,0 +1,2055 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           AAA   N   N  N   N   OOO   TTTTT   AAA   TTTTT  EEEEE             %
+%          A   A  NN  N  NN  N  O   O    T    A   A    T    E                 %
+%          AAAAA  N N N  N N N  O   O    T    AAAAA    T    EEE               %
+%          A   A  N  NN  N  NN  O   O    T    A   A    T    E                 %
+%          A   A  N   N  N   N   OOO     T    A   A    T    EEEEE             %
+%                                                                             %
+%                                                                             %
+%                   MagickCore Image Annotation Methods                       %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Digital Applications (www.digapp.com) contributed the stroked text algorithm.
+% It was written by Leonard Rosenthol.
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/draw-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/type.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xwindow-private.h"
+#if defined(MAGICKCORE_FREETYPE_DELEGATE)
+#if defined(__MINGW32__)
+#  undef interface
+#endif
+#if defined(MAGICKCORE_HAVE_FT2BUILD_H)
+#  include <ft2build.h>
+#endif
+#if defined(FT_FREETYPE_H)
+#  include FT_FREETYPE_H
+#else
+#  include <freetype/freetype.h>
+#endif
+#if defined(FT_GLYPH_H)
+#  include FT_GLYPH_H
+#else
+#  include <freetype/ftglyph.h>
+#endif
+#if defined(FT_OUTLINE_H)
+#  include FT_OUTLINE_H
+#else
+#  include <freetype/ftoutln.h>
+#endif
+#if defined(FT_BBOX_H)
+#  include FT_BBOX_H
+#else
+#  include <freetype/ftbbox.h>
+#endif /* defined(FT_BBOX_H) */
+#endif
+
+/*
+  Annotate semaphores.
+*/
+static SemaphoreInfo
+  *annotate_semaphore = (SemaphoreInfo *) NULL;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  RenderType(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
+  RenderPostscript(Image *,const DrawInfo *,const PointInfo *,TypeMetric *),
+  RenderFreetype(Image *,const DrawInfo *,const char *,const PointInfo *,
+    TypeMetric *),
+  RenderX11(Image *,const DrawInfo *,const PointInfo *,TypeMetric *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A n n o t a t e C o m p o n e n t G e n e s i s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AnnotateComponentGenesis() instantiates the annotate component.
+%
+%  The format of the AnnotateComponentGenesis method is:
+%
+%      MagickBooleanType AnnotateComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType AnnotateComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&annotate_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A n n o t a t e C o m p o n e n t T e r m i n u s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AnnotateComponentTerminus() destroys the annotate component.
+%
+%  The format of the AnnotateComponentTerminus method is:
+%
+%      AnnotateComponentTerminus(void)
+%
+*/
+MagickExport void AnnotateComponentTerminus(void)
+{
+  if (annotate_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&annotate_semaphore);
+  DestroySemaphoreInfo(&annotate_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A n n o t a t e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AnnotateImage() annotates an image with text.  Optionally you can include
+%  any of the following bits of information about the image by embedding
+%  the appropriate special characters:
+%
+%    %b   file size in bytes.
+%    %c   comment.
+%    %d   directory in which the image resides.
+%    %e   extension of the image file.
+%    %f   original filename of the image.
+%    %h   height of image.
+%    %i   filename of the image.
+%    %k   number of unique colors.
+%    %l   image label.
+%    %m   image file format.
+%    %n   number of images in a image sequence.
+%    %o   output image filename.
+%    %p   page number of the image.
+%    %q   image depth (8 or 16).
+%    %q   image depth (8 or 16).
+%    %s   image scene number.
+%    %t   image filename without any extension.
+%    %u   a unique temporary filename.
+%    %w   image width.
+%    %x   x resolution of the image.
+%    %y   y resolution of the image.
+%
+%  The format of the AnnotateImage method is:
+%
+%      MagickBooleanType AnnotateImage(Image *image,DrawInfo *draw_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+*/
+MagickExport MagickBooleanType AnnotateImage(Image *image,
+  const DrawInfo *draw_info)
+{
+  char
+    primitive[MaxTextExtent],
+    **textlist;
+
+  DrawInfo
+    *annotate,
+    *annotate_info;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  PointInfo
+    offset;
+
+  RectangleInfo
+    geometry;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  TypeMetric
+    metrics;
+
+  size_t
+    height,
+    number_lines;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  if (draw_info->text == (char *) NULL)
+    return(MagickFalse);
+  if (*draw_info->text == '\0')
+    return(MagickTrue);
+  textlist=StringToList(draw_info->text);
+  if (textlist == (char **) NULL)
+    return(MagickFalse);
+  length=strlen(textlist[0]);
+  for (i=1; textlist[i] != (char *) NULL; i++)
+    if (strlen(textlist[i]) > length)
+      length=strlen(textlist[i]);
+  number_lines=(size_t) i;
+  annotate=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  SetGeometry(image,&geometry);
+  SetGeometryInfo(&geometry_info);
+  if (annotate_info->geometry != (char *) NULL)
+    {
+      (void) ParsePageGeometry(image,annotate_info->geometry,&geometry,
+        &image->exception);
+      (void) ParseGeometry(annotate_info->geometry,&geometry_info);
+    }
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  for (i=0; textlist[i] != (char *) NULL; i++)
+  {
+    /*
+      Position text relative to image.
+    */
+    annotate_info->affine.tx=geometry_info.xi-image->page.x;
+    annotate_info->affine.ty=geometry_info.psi-image->page.y;
+    (void) CloneString(&annotate->text,textlist[i]);
+    (void) GetTypeMetrics(image,annotate,&metrics);
+    height=(ssize_t) (metrics.ascent-metrics.descent+
+      draw_info->interline_spacing+0.5);
+    switch (annotate->gravity)
+    {
+      case UndefinedGravity:
+      default:
+      {
+        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
+        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
+        break;
+      }
+      case NorthWestGravity:
+      {
+        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
+          annotate_info->affine.ry*height+annotate_info->affine.ry*
+          (metrics.ascent+metrics.descent);
+        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
+          annotate_info->affine.sy*height+annotate_info->affine.sy*
+          metrics.ascent;
+        break;
+      }
+      case NorthGravity:
+      {
+        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
+          geometry.width/2.0+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
+          annotate_info->affine.ry*(metrics.ascent+metrics.descent);
+        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
+          annotate_info->affine.sy*height+annotate_info->affine.sy*
+          metrics.ascent-annotate_info->affine.rx*(metrics.width-
+          metrics.bounds.x1)/2.0;
+        break;
+      }
+      case NorthEastGravity:
+      {
+        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
+          geometry.width+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
+          annotate_info->affine.ry*(metrics.ascent+metrics.descent)-1.0;
+        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+i*
+          annotate_info->affine.sy*height+annotate_info->affine.sy*
+          metrics.ascent-annotate_info->affine.rx*(metrics.width-
+          metrics.bounds.x1);
+        break;
+      }
+      case WestGravity:
+      {
+        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
+          annotate_info->affine.ry*height+annotate_info->affine.ry*
+          (metrics.ascent+metrics.descent-(number_lines-1.0)*height)/2.0;
+        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
+          geometry.height/2.0+i*annotate_info->affine.sy*height+
+          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
+          (number_lines-1.0)*height)/2.0;
+        break;
+      }
+      case StaticGravity:
+      case CenterGravity:
+      {
+        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
+          geometry.width/2.0+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0+
+          annotate_info->affine.ry*(metrics.ascent+metrics.descent-
+          (number_lines-1)*height)/2.0;
+        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
+          geometry.height/2.0+i*annotate_info->affine.sy*height-
+          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0+
+          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
+          (number_lines-1.0)*height)/2.0;
+        break;
+      }
+      case EastGravity:
+      {
+        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
+          geometry.width+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)+
+          annotate_info->affine.ry*(metrics.ascent+metrics.descent-
+          (number_lines-1.0)*height)/2.0-1.0;
+        offset.y=(geometry.height == 0 ? -1.0 : 1.0)*annotate_info->affine.ty+
+          geometry.height/2.0+i*annotate_info->affine.sy*height-
+          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)+
+          annotate_info->affine.sy*(metrics.ascent+metrics.descent-
+          (number_lines-1.0)*height)/2.0;
+        break;
+      }
+      case SouthWestGravity:
+      {
+        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+i*
+          annotate_info->affine.ry*height-annotate_info->affine.ry*
+          (number_lines-1.0)*height;
+        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
+          geometry.height+i*annotate_info->affine.sy*height-
+          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
+        break;
+      }
+      case SouthGravity:
+      {
+        offset.x=(geometry.width == 0 ? -1.0 : 1.0)*annotate_info->affine.tx+
+          geometry.width/2.0+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0-
+          annotate_info->affine.ry*(number_lines-1.0)*height/2.0;
+        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
+          geometry.height+i*annotate_info->affine.sy*height-
+          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0-
+          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
+        break;
+      }
+      case SouthEastGravity:
+      {
+        offset.x=(geometry.width == 0 ? 1.0 : -1.0)*annotate_info->affine.tx+
+          geometry.width+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)-
+          annotate_info->affine.ry*(number_lines-1.0)*height-1.0;
+        offset.y=(geometry.height == 0 ? 1.0 : -1.0)*annotate_info->affine.ty+
+          geometry.height+i*annotate_info->affine.sy*height-
+          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)-
+          annotate_info->affine.sy*(number_lines-1.0)*height+metrics.descent;
+        break;
+      }
+    }
+    switch (annotate->align)
+    {
+      case LeftAlign:
+      {
+        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height;
+        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height;
+        break;
+      }
+      case CenterAlign:
+      {
+        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1)/2.0;
+        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
+          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1)/2.0;
+        break;
+      }
+      case RightAlign:
+      {
+        offset.x=annotate_info->affine.tx+i*annotate_info->affine.ry*height-
+          annotate_info->affine.sx*(metrics.width+metrics.bounds.x1);
+        offset.y=annotate_info->affine.ty+i*annotate_info->affine.sy*height-
+          annotate_info->affine.rx*(metrics.width+metrics.bounds.x1);
+        break;
+      }
+      default:
+        break;
+    }
+    if (draw_info->undercolor.alpha != TransparentAlpha)
+      {
+        DrawInfo
+          *undercolor_info;
+
+        /*
+          Text box.
+        */
+        undercolor_info=CloneDrawInfo((ImageInfo *) NULL,(DrawInfo *) NULL);
+        undercolor_info->fill=draw_info->undercolor;
+        undercolor_info->affine=draw_info->affine;
+        undercolor_info->affine.tx=offset.x-draw_info->affine.ry*metrics.ascent;
+        undercolor_info->affine.ty=offset.y-draw_info->affine.sy*metrics.ascent;
+        (void) FormatLocaleString(primitive,MaxTextExtent,
+          "rectangle 0,0 %g,%.20g",metrics.origin.x,(double) height);
+        (void) CloneString(&undercolor_info->primitive,primitive);
+        (void) DrawImage(image,undercolor_info);
+        (void) DestroyDrawInfo(undercolor_info);
+      }
+    annotate_info->affine.tx=offset.x;
+    annotate_info->affine.ty=offset.y;
+    (void) FormatLocaleString(primitive,MaxTextExtent,"stroke-width %g "
+      "line 0,0 %g,0",metrics.underline_thickness,metrics.width);
+    if (annotate->decorate == OverlineDecoration)
+      {
+        annotate_info->affine.ty-=(draw_info->affine.sy*(metrics.ascent+
+          metrics.descent-metrics.underline_position));
+        (void) CloneString(&annotate_info->primitive,primitive);
+        (void) DrawImage(image,annotate_info);
+      }
+    else
+      if (annotate->decorate == UnderlineDecoration)
+        {
+          annotate_info->affine.ty-=(draw_info->affine.sy*
+            metrics.underline_position);
+          (void) CloneString(&annotate_info->primitive,primitive);
+          (void) DrawImage(image,annotate_info);
+        }
+    /*
+      Annotate image with text.
+    */
+    status=RenderType(image,annotate,&offset,&metrics);
+    if (status == MagickFalse)
+      break;
+    if (annotate->decorate == LineThroughDecoration)
+      {
+        annotate_info->affine.ty-=(draw_info->affine.sy*(height+
+          metrics.underline_position+metrics.descent)/2.0);
+        (void) CloneString(&annotate_info->primitive,primitive);
+        (void) DrawImage(image,annotate_info);
+      }
+  }
+  /*
+    Relinquish resources.
+  */
+  annotate_info=DestroyDrawInfo(annotate_info);
+  annotate=DestroyDrawInfo(annotate);
+  for (i=0; textlist[i] != (char *) NULL; i++)
+    textlist[i]=DestroyString(textlist[i]);
+  textlist=(char **) RelinquishMagickMemory(textlist);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  F o r m a t M a g i c k C a p t i o n                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatMagickCaption() formats a caption so that it fits within the image
+%  width.  It returns the number of lines in the formatted caption.
+%
+%  The format of the FormatMagickCaption method is:
+%
+%      ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
+%        const MagickBooleanType split,TypeMetric *metrics,char **caption)
+%
+%  A description of each parameter follows.
+%
+%    o image:  The image.
+%
+%    o draw_info: the draw info.
+%
+%    o split: when no convenient line breaks-- insert newline.
+%
+%    o metrics: Return the font metrics in this structure.
+%
+%    o caption: the caption.
+%
+*/
+MagickExport ssize_t FormatMagickCaption(Image *image,DrawInfo *draw_info,
+  const MagickBooleanType split,TypeMetric *metrics,char **caption)
+{
+  MagickBooleanType
+    status;
+
+  register char
+    *p,
+    *q,
+    *s;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  q=draw_info->text;
+  s=(char *) NULL;
+  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
+  {
+    if (IsUTFSpace(GetUTFCode(p)) != MagickFalse)
+      s=p;
+    for (i=0; i < (ssize_t) GetUTFOctets(p); i++)
+      *q++=(*(p+i));
+    *q='\0';
+    status=GetTypeMetrics(image,draw_info,metrics);
+    if (status == MagickFalse)
+      break;
+    width=(size_t) floor(metrics->width+0.5);
+    if (GetUTFCode(p) != '\n')
+      if (width <= image->columns)
+        continue;
+    if (s == (char *) NULL)
+      {
+        s=p;
+        while ((IsUTFSpace(GetUTFCode(s)) == MagickFalse) &&
+               (GetUTFCode(s) != 0))
+          s+=GetUTFOctets(s);
+      }
+    if (GetUTFCode(s) != 0)
+      {
+        *s='\n';
+        p=s;
+      }
+    else
+      if (split != MagickFalse)
+        {
+          char
+            *target;
+
+          ssize_t
+            n;
+
+          /*
+            No convenient line breaks-- insert newline.
+          */
+          target=AcquireString(*caption);
+          n=p-(*caption);
+          CopyMagickString(target,*caption,n+1);
+          ConcatenateMagickString(target,"\n",strlen(*caption)+1);
+          ConcatenateMagickString(target,p,strlen(*caption)+2);
+          (void) DestroyString(*caption);
+          *caption=target;
+          p=(*caption)+n;
+        }
+    s=(char *) NULL;
+    q=draw_info->text;
+  }
+  i=0;
+  for (p=(*caption); GetUTFCode(p) != 0; p+=GetUTFOctets(p))
+    if (GetUTFCode(p) == '\n')
+      i++;
+  return(i);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M u l t i l i n e T y p e M e t r i c s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMultilineTypeMetrics() returns the following information for the
+%  specified font and text:
+%
+%    character width
+%    character height
+%    ascender
+%    descender
+%    text width
+%    text height
+%    maximum horizontal advance
+%    bounds: x1
+%    bounds: y1
+%    bounds: x2
+%    bounds: y2
+%    origin: x
+%    origin: y
+%    underline position
+%    underline thickness
+%
+%  This method is like GetTypeMetrics() but it returns the maximum text width
+%  and height for multiple lines of text.
+%
+%  The format of the GetMultilineTypeMetrics method is:
+%
+%      MagickBooleanType GetMultilineTypeMetrics(Image *image,
+%        const DrawInfo *draw_info,TypeMetric *metrics)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o metrics: Return the font metrics in this structure.
+%
+*/
+MagickExport MagickBooleanType GetMultilineTypeMetrics(Image *image,
+  const DrawInfo *draw_info,TypeMetric *metrics)
+{
+  char
+    **textlist;
+
+  DrawInfo
+    *annotate_info;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  TypeMetric
+    extent;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->text != (char *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  if (*draw_info->text == '\0')
+    return(MagickFalse);
+  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  annotate_info->text=DestroyString(annotate_info->text);
+  /*
+    Convert newlines to multiple lines of text.
+  */
+  textlist=StringToList(draw_info->text);
+  if (textlist == (char **) NULL)
+    return(MagickFalse);
+  annotate_info->render=MagickFalse;
+  annotate_info->direction=UndefinedDirection;
+  (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
+  (void) ResetMagickMemory(&extent,0,sizeof(extent));
+  /*
+    Find the widest of the text lines.
+  */
+  annotate_info->text=textlist[0];
+  status=GetTypeMetrics(image,annotate_info,&extent);
+  *metrics=extent;
+  for (i=1; textlist[i] != (char *) NULL; i++)
+  {
+    annotate_info->text=textlist[i];
+    status=GetTypeMetrics(image,annotate_info,&extent);
+    if (extent.width > metrics->width)
+      *metrics=extent;
+  }
+  metrics->height=(double) (i*(size_t) (metrics->ascent-
+    metrics->descent+0.5)+(i-1)*draw_info->interline_spacing);
+  /*
+    Relinquish resources.
+  */
+  annotate_info->text=(char *) NULL;
+  annotate_info=DestroyDrawInfo(annotate_info);
+  for (i=0; textlist[i] != (char *) NULL; i++)
+    textlist[i]=DestroyString(textlist[i]);
+  textlist=(char **) RelinquishMagickMemory(textlist);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t T y p e M e t r i c s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetTypeMetrics() returns the following information for the specified font
+%  and text:
+%
+%    character width
+%    character height
+%    ascender
+%    descender
+%    text width
+%    text height
+%    maximum horizontal advance
+%    bounds: x1
+%    bounds: y1
+%    bounds: x2
+%    bounds: y2
+%    origin: x
+%    origin: y
+%    underline position
+%    underline thickness
+%
+%  The format of the GetTypeMetrics method is:
+%
+%      MagickBooleanType GetTypeMetrics(Image *image,const DrawInfo *draw_info,
+%        TypeMetric *metrics)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o metrics: Return the font metrics in this structure.
+%
+*/
+MagickExport MagickBooleanType GetTypeMetrics(Image *image,
+  const DrawInfo *draw_info,TypeMetric *metrics)
+{
+  DrawInfo
+    *annotate_info;
+
+  MagickBooleanType
+    status;
+
+  PointInfo
+    offset;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->text != (char *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  annotate_info->render=MagickFalse;
+  annotate_info->direction=UndefinedDirection;
+  (void) ResetMagickMemory(metrics,0,sizeof(*metrics));
+  offset.x=0.0;
+  offset.y=0.0;
+  status=RenderType(image,annotate_info,&offset,metrics);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Metrics: text: %s; "
+      "width: %g; height: %g; ascent: %g; descent: %g; max advance: %g; "
+      "bounds: %g,%g  %g,%g; origin: %g,%g; pixels per em: %g,%g; "
+      "underline position: %g; underline thickness: %g",annotate_info->text,
+      metrics->width,metrics->height,metrics->ascent,metrics->descent,
+      metrics->max_advance,metrics->bounds.x1,metrics->bounds.y1,
+      metrics->bounds.x2,metrics->bounds.y2,metrics->origin.x,metrics->origin.y,
+      metrics->pixels_per_em.x,metrics->pixels_per_em.y,
+      metrics->underline_position,metrics->underline_thickness);
+  annotate_info=DestroyDrawInfo(annotate_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e n d e r T y p e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RenderType() renders text on the image.  It also returns the bounding box of
+%  the text relative to the image.
+%
+%  The format of the RenderType method is:
+%
+%      MagickBooleanType RenderType(Image *image,DrawInfo *draw_info,
+%        const PointInfo *offset,TypeMetric *metrics)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o offset: (x,y) location of text relative to image.
+%
+%    o metrics: bounding box of text.
+%
+*/
+static MagickBooleanType RenderType(Image *image,const DrawInfo *draw_info,
+  const PointInfo *offset,TypeMetric *metrics)
+{
+  const TypeInfo
+    *type_info;
+
+  DrawInfo
+    *annotate_info;
+
+  MagickBooleanType
+    status;
+
+  type_info=(const TypeInfo *) NULL;
+  if (draw_info->font != (char *) NULL)
+    {
+      if (*draw_info->font == '@')
+        {
+          status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
+            metrics);
+          return(status);
+        }
+      if (*draw_info->font == '-')
+        return(RenderX11(image,draw_info,offset,metrics));
+      if (IsPathAccessible(draw_info->font) != MagickFalse)
+        {
+          status=RenderFreetype(image,draw_info,draw_info->encoding,offset,
+            metrics);
+          return(status);
+        }
+      type_info=GetTypeInfo(draw_info->font,&image->exception);
+      if (type_info == (const TypeInfo *) NULL)
+        (void) ThrowMagickException(&image->exception,GetMagickModule(),
+          TypeWarning,"UnableToReadFont","`%s'",draw_info->font);
+    }
+  if ((type_info == (const TypeInfo *) NULL) &&
+      (draw_info->family != (const char *) NULL))
+    {
+      type_info=GetTypeInfoByFamily(draw_info->family,draw_info->style,
+        draw_info->stretch,draw_info->weight,&image->exception);
+      if (type_info == (const TypeInfo *) NULL)
+        (void) ThrowMagickException(&image->exception,GetMagickModule(),
+          TypeWarning,"UnableToReadFont","`%s'",draw_info->family);
+    }
+  if (type_info == (const TypeInfo *) NULL)
+    type_info=GetTypeInfoByFamily("Arial",draw_info->style,
+      draw_info->stretch,draw_info->weight,&image->exception);
+  if (type_info == (const TypeInfo *) NULL)
+    type_info=GetTypeInfoByFamily("Helvetica",draw_info->style,
+      draw_info->stretch,draw_info->weight,&image->exception);
+  if (type_info == (const TypeInfo *) NULL)
+    type_info=GetTypeInfoByFamily("Century Schoolbook",draw_info->style,
+      draw_info->stretch,draw_info->weight,&image->exception);
+  if (type_info == (const TypeInfo *) NULL)
+    type_info=GetTypeInfoByFamily((const char *) NULL,draw_info->style,
+      draw_info->stretch,draw_info->weight,&image->exception);
+  if (type_info == (const TypeInfo *) NULL)
+    type_info=GetTypeInfo("*",&image->exception);
+  if (type_info == (const TypeInfo *) NULL)
+    {
+      status=RenderFreetype(image,draw_info,draw_info->encoding,offset,metrics);
+      return(status);
+    }
+  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  annotate_info->face=type_info->face;
+  if (type_info->metrics != (char *) NULL)
+    (void) CloneString(&annotate_info->metrics,type_info->metrics);
+  if (type_info->glyphs != (char *) NULL)
+    (void) CloneString(&annotate_info->font,type_info->glyphs);
+  status=RenderFreetype(image,annotate_info,type_info->encoding,offset,metrics);
+  annotate_info=DestroyDrawInfo(annotate_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e n d e r F r e e t y p e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RenderFreetype() renders text on the image with a Truetype font.  It also
+%  returns the bounding box of the text relative to the image.
+%
+%  The format of the RenderFreetype method is:
+%
+%      MagickBooleanType RenderFreetype(Image *image,DrawInfo *draw_info,
+%        const char *encoding,const PointInfo *offset,TypeMetric *metrics)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o encoding: the font encoding.
+%
+%    o offset: (x,y) location of text relative to image.
+%
+%    o metrics: bounding box of text.
+%
+*/
+
+#if defined(MAGICKCORE_FREETYPE_DELEGATE)
+
+static int TraceCubicBezier(FT_Vector *p,FT_Vector *q,FT_Vector *to,
+  DrawInfo *draw_info)
+{
+  AffineMatrix
+    affine;
+
+  char
+    path[MaxTextExtent];
+
+  affine=draw_info->affine;
+  (void) FormatLocaleString(path,MaxTextExtent,
+    "C%g,%g %g,%g %g,%g",affine.tx+p->x/64.0,affine.ty-
+    p->y/64.0,affine.tx+q->x/64.0,affine.ty-q->y/64.0,affine.tx+to->x/64.0,
+    affine.ty-to->y/64.0);
+  (void) ConcatenateString(&draw_info->primitive,path);
+  return(0);
+}
+
+static int TraceLineTo(FT_Vector *to,DrawInfo *draw_info)
+{
+  AffineMatrix
+    affine;
+
+  char
+    path[MaxTextExtent];
+
+  affine=draw_info->affine;
+  (void) FormatLocaleString(path,MaxTextExtent,"L%g,%g",affine.tx+
+    to->x/64.0,affine.ty-to->y/64.0);
+  (void) ConcatenateString(&draw_info->primitive,path);
+  return(0);
+}
+
+static int TraceMoveTo(FT_Vector *to,DrawInfo *draw_info)
+{
+  AffineMatrix
+    affine;
+
+  char
+    path[MaxTextExtent];
+
+  affine=draw_info->affine;
+  (void) FormatLocaleString(path,MaxTextExtent,"M%g,%g",affine.tx+
+    to->x/64.0,affine.ty-to->y/64.0);
+  (void) ConcatenateString(&draw_info->primitive,path);
+  return(0);
+}
+
+static int TraceQuadraticBezier(FT_Vector *control,FT_Vector *to,
+  DrawInfo *draw_info)
+{
+  AffineMatrix
+    affine;
+
+  char
+    path[MaxTextExtent];
+
+  affine=draw_info->affine;
+  (void) FormatLocaleString(path,MaxTextExtent,"Q%g,%g %g,%g",
+    affine.tx+control->x/64.0,affine.ty-control->y/64.0,affine.tx+to->x/64.0,
+    affine.ty-to->y/64.0);
+  (void) ConcatenateString(&draw_info->primitive,path);
+  return(0);
+}
+
+static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
+  const char *encoding,const PointInfo *offset,TypeMetric *metrics)
+{
+#if !defined(FT_OPEN_PATHNAME)
+#define FT_OPEN_PATHNAME  ft_open_pathname
+#endif
+
+  typedef struct _GlyphInfo
+  {
+    FT_UInt
+      id;
+
+    FT_Vector
+      origin;
+
+    FT_Glyph
+      image;
+  } GlyphInfo;
+
+  const char
+    *value;
+
+  double
+    direction;
+
+  DrawInfo
+    *annotate_info;
+
+  FT_BBox
+    bounds;
+
+  FT_BitmapGlyph
+    bitmap;
+
+  FT_Encoding
+    encoding_type;
+
+  FT_Error
+    status;
+
+  FT_Face
+    face;
+
+  FT_Int32
+    flags;
+
+  FT_Library
+    library;
+
+  FT_Matrix
+    affine;
+
+  FT_Open_Args
+    args;
+
+  FT_Vector
+    origin;
+
+  GlyphInfo
+    glyph,
+    last_glyph;
+
+  PointInfo
+    point,
+    resolution;
+
+  register char
+    *p;
+
+  ssize_t
+    code,
+    y;
+
+  static FT_Outline_Funcs
+    OutlineMethods =
+    {
+      (FT_Outline_MoveTo_Func) TraceMoveTo,
+      (FT_Outline_LineTo_Func) TraceLineTo,
+      (FT_Outline_ConicTo_Func) TraceQuadraticBezier,
+      (FT_Outline_CubicTo_Func) TraceCubicBezier,
+      0, 0
+    };
+
+  unsigned char
+    *utf8;
+
+  /*
+    Initialize Truetype library.
+  */
+  status=FT_Init_FreeType(&library);
+  if (status != 0)
+    ThrowBinaryException(TypeError,"UnableToInitializeFreetypeLibrary",
+      image->filename);
+  args.flags=FT_OPEN_PATHNAME;
+  if (draw_info->font == (char *) NULL)
+    args.pathname=ConstantString("helvetica");
+  else
+    if (*draw_info->font != '@')
+      args.pathname=ConstantString(draw_info->font);
+    else
+      args.pathname=ConstantString(draw_info->font+1);
+  face=(FT_Face) NULL;
+  status=FT_Open_Face(library,&args,(long) draw_info->face,&face);
+  args.pathname=DestroyString(args.pathname);
+  if (status != 0)
+    {
+      (void) FT_Done_FreeType(library);
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        TypeError,"UnableToReadFont","`%s'",draw_info->font);
+      return(RenderPostscript(image,draw_info,offset,metrics));
+    }
+  if ((draw_info->metrics != (char *) NULL) &&
+      (IsPathAccessible(draw_info->metrics) != MagickFalse))
+    (void) FT_Attach_File(face,draw_info->metrics);
+  encoding_type=ft_encoding_unicode;
+  status=FT_Select_Charmap(face,encoding_type);
+  if ((status != 0) && (face->num_charmaps != 0))
+    status=FT_Set_Charmap(face,face->charmaps[0]);
+  if (encoding != (const char *) NULL)
+    {
+      if (LocaleCompare(encoding,"AdobeCustom") == 0)
+        encoding_type=ft_encoding_adobe_custom;
+      if (LocaleCompare(encoding,"AdobeExpert") == 0)
+        encoding_type=ft_encoding_adobe_expert;
+      if (LocaleCompare(encoding,"AdobeStandard") == 0)
+        encoding_type=ft_encoding_adobe_standard;
+      if (LocaleCompare(encoding,"AppleRoman") == 0)
+        encoding_type=ft_encoding_apple_roman;
+      if (LocaleCompare(encoding,"BIG5") == 0)
+        encoding_type=ft_encoding_big5;
+      if (LocaleCompare(encoding,"GB2312") == 0)
+        encoding_type=ft_encoding_gb2312;
+      if (LocaleCompare(encoding,"Johab") == 0)
+        encoding_type=ft_encoding_johab;
+#if defined(ft_encoding_latin_1)
+      if (LocaleCompare(encoding,"Latin-1") == 0)
+        encoding_type=ft_encoding_latin_1;
+#endif
+      if (LocaleCompare(encoding,"Latin-2") == 0)
+        encoding_type=ft_encoding_latin_2;
+      if (LocaleCompare(encoding,"None") == 0)
+        encoding_type=ft_encoding_none;
+      if (LocaleCompare(encoding,"SJIScode") == 0)
+        encoding_type=ft_encoding_sjis;
+      if (LocaleCompare(encoding,"Symbol") == 0)
+        encoding_type=ft_encoding_symbol;
+      if (LocaleCompare(encoding,"Unicode") == 0)
+        encoding_type=ft_encoding_unicode;
+      if (LocaleCompare(encoding,"Wansung") == 0)
+        encoding_type=ft_encoding_wansung;
+      status=FT_Select_Charmap(face,encoding_type);
+      if (status != 0)
+        ThrowBinaryException(TypeError,"UnrecognizedFontEncoding",encoding);
+    }
+  /*
+    Set text size.
+  */
+  resolution.x=DefaultResolution;
+  resolution.y=DefaultResolution;
+  if (draw_info->density != (char *) NULL)
+    {
+      GeometryInfo
+        geometry_info;
+
+      MagickStatusType
+        flags;
+
+      flags=ParseGeometry(draw_info->density,&geometry_info);
+      resolution.x=geometry_info.rho;
+      resolution.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        resolution.y=resolution.x;
+    }
+  status=FT_Set_Char_Size(face,(FT_F26Dot6) (64.0*draw_info->pointsize),
+    (FT_F26Dot6) (64.0*draw_info->pointsize),(FT_UInt) resolution.x,
+    (FT_UInt) resolution.y);
+  metrics->pixels_per_em.x=face->size->metrics.x_ppem;
+  metrics->pixels_per_em.y=face->size->metrics.y_ppem;
+  metrics->ascent=(double) face->size->metrics.ascender/64.0;
+  metrics->descent=(double) face->size->metrics.descender/64.0;
+  metrics->width=0;
+  metrics->origin.x=0;
+  metrics->origin.y=0;
+  metrics->height=(double) face->size->metrics.height/64.0;
+  metrics->max_advance=0.0;
+  if (face->size->metrics.max_advance > MagickEpsilon)
+    metrics->max_advance=(double) face->size->metrics.max_advance/64.0;
+  metrics->bounds.x1=0.0;
+  metrics->bounds.y1=metrics->descent;
+  metrics->bounds.x2=metrics->ascent+metrics->descent;
+  metrics->bounds.y2=metrics->ascent+metrics->descent;
+  metrics->underline_position=face->underline_position/64.0;
+  metrics->underline_thickness=face->underline_thickness/64.0;
+  if (*draw_info->text == '\0')
+    {
+      (void) FT_Done_Face(face);
+      (void) FT_Done_FreeType(library);
+      return(MagickTrue);
+    }
+  /*
+    Compute bounding box.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),"Font %s; "
+      "font-encoding %s; text-encoding %s; pointsize %g",
+      draw_info->font != (char *) NULL ? draw_info->font : "none",
+      encoding != (char *) NULL ? encoding : "none",
+      draw_info->encoding != (char *) NULL ? draw_info->encoding : "none",
+      draw_info->pointsize);
+  flags=FT_LOAD_NO_BITMAP;
+  value=GetImageProperty(image,"type:hinting");
+  if ((value != (const char *) NULL) && (LocaleCompare(value,"off") == 0))
+    flags|=FT_LOAD_NO_HINTING;
+  glyph.id=0;
+  glyph.image=NULL;
+  last_glyph.id=0;
+  last_glyph.image=NULL;
+  origin.x=0;
+  origin.y=0;
+  affine.xx=65536L;
+  affine.yx=0L;
+  affine.xy=0L;
+  affine.yy=65536L;
+  if (draw_info->render != MagickFalse)
+    {
+      affine.xx=(FT_Fixed) (65536L*draw_info->affine.sx+0.5);
+      affine.yx=(FT_Fixed) (-65536L*draw_info->affine.rx+0.5);
+      affine.xy=(FT_Fixed) (-65536L*draw_info->affine.ry+0.5);
+      affine.yy=(FT_Fixed) (65536L*draw_info->affine.sy+0.5);
+    }
+  annotate_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  (void) CloneString(&annotate_info->primitive,"path '");
+  if (draw_info->render != MagickFalse)
+    {
+      if (image->storage_class != DirectClass)
+        (void) SetImageStorageClass(image,DirectClass);
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+    }
+  direction=1.0;
+  if (draw_info->direction == RightToLeftDirection)
+    direction=(-1.0);
+  point.x=0.0;
+  point.y=0.0;
+  for (p=draw_info->text; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
+    if (GetUTFCode(p) < 0)
+      break;
+  utf8=(unsigned char *) NULL;
+  if (GetUTFCode(p) == 0)
+    p=draw_info->text;
+  else
+    {
+      utf8=ConvertLatin1ToUTF8((unsigned char *) draw_info->text);
+      if (utf8 != (unsigned char *) NULL)
+        p=(char *) utf8;
+    }
+  for (code=0; GetUTFCode(p) != 0; p+=GetUTFOctets(p))
+  {
+    /*
+      Render UTF-8 sequence.
+    */
+    glyph.id=FT_Get_Char_Index(face,GetUTFCode(p));
+    if (glyph.id == 0)
+      glyph.id=FT_Get_Char_Index(face,'?');
+    if ((glyph.id != 0) && (last_glyph.id != 0))
+      {
+        if (draw_info->kerning != 0.0)
+          origin.x+=64.0*direction*draw_info->kerning;
+        else
+          if (FT_HAS_KERNING(face))
+            {
+              FT_Vector
+                kerning;
+
+              status=FT_Get_Kerning(face,last_glyph.id,glyph.id,
+                ft_kerning_default,&kerning);
+              if (status == 0)
+                origin.x+=direction*kerning.x;
+            }
+        }
+    glyph.origin=origin;
+    status=FT_Load_Glyph(face,glyph.id,flags);
+    if (status != 0)
+      continue;
+    status=FT_Get_Glyph(face->glyph,&glyph.image);
+    if (status != 0)
+      continue;
+    status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->outline,
+      &bounds);
+    if (status != 0)
+      continue;
+    if ((p == draw_info->text) || (bounds.xMin < metrics->bounds.x1))
+      metrics->bounds.x1=bounds.xMin;
+    if ((p == draw_info->text) || (bounds.yMin < metrics->bounds.y1))
+      metrics->bounds.y1=bounds.yMin;
+    if ((p == draw_info->text) || (bounds.xMax > metrics->bounds.x2))
+      metrics->bounds.x2=bounds.xMax;
+    if ((p == draw_info->text) || (bounds.yMax > metrics->bounds.y2))
+      metrics->bounds.y2=bounds.yMax;
+    if (draw_info->render != MagickFalse)
+      if ((draw_info->stroke.alpha != TransparentAlpha) ||
+          (draw_info->stroke_pattern != (Image *) NULL))
+        {
+          /*
+            Trace the glyph.
+          */
+          annotate_info->affine.tx=glyph.origin.x/64.0;
+          annotate_info->affine.ty=glyph.origin.y/64.0;
+          (void) FT_Outline_Decompose(&((FT_OutlineGlyph) glyph.image)->
+            outline,&OutlineMethods,annotate_info);
+        }
+    FT_Vector_Transform(&glyph.origin,&affine);
+    (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
+    status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
+      (FT_Vector *) NULL,MagickTrue);
+    if (status != 0)
+      continue;
+    bitmap=(FT_BitmapGlyph) glyph.image;
+    point.x=offset->x+bitmap->left;
+    point.y=offset->y-bitmap->top;
+    if (draw_info->render != MagickFalse)
+      {
+        CacheView
+          *image_view;
+
+        ExceptionInfo
+          *exception;
+
+        MagickBooleanType
+          status;
+
+        /*
+          Rasterize the glyph.
+        */
+        status=MagickTrue;
+        exception=(&image->exception);
+        image_view=AcquireCacheView(image);
+        for (y=0; y < (ssize_t) bitmap->bitmap.rows; y++)
+        {
+          MagickBooleanType
+            active,
+            sync;
+
+          MagickRealType
+            fill_opacity;
+
+          PixelPacket
+            fill_color;
+
+          register Quantum
+            *restrict q;
+
+          register ssize_t
+            x;
+
+          register unsigned char
+            *p;
+
+          ssize_t
+            x_offset,
+            y_offset;
+
+          if (status == MagickFalse)
+            continue;
+          x_offset=(ssize_t) ceil(point.x-0.5);
+          y_offset=(ssize_t) ceil(point.y+y-0.5);
+          if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
+            continue;
+          q=(Quantum *) NULL;
+          if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
+            active=MagickFalse;
+          else
+            {
+              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,
+                bitmap->bitmap.width,1,exception);
+              active=q != (Quantum *) NULL ? MagickTrue : MagickFalse;
+            }
+          p=bitmap->bitmap.buffer+y*bitmap->bitmap.width;
+          for (x=0; x < (ssize_t) bitmap->bitmap.width; x++)
+          {
+            x_offset++;
+            if ((*p == 0) || (x_offset < 0) ||
+                (x_offset >= (ssize_t) image->columns))
+              {
+                p++;
+                q+=GetPixelChannels(image);
+                continue;
+              }
+            fill_opacity=(MagickRealType) (*p)/(bitmap->bitmap.num_grays-1);
+            if (draw_info->text_antialias == MagickFalse)
+              fill_opacity=fill_opacity >= 0.5 ? 1.0 : 0.0;
+            if (active == MagickFalse)
+              q=GetCacheViewAuthenticPixels(image_view,x_offset,y_offset,1,1,
+                exception);
+            if (q == (const Quantum *) NULL)
+              {
+                p++;
+                q+=GetPixelChannels(image);
+                continue;
+              }
+            (void) GetFillColor(draw_info,x_offset,y_offset,&fill_color);
+            fill_opacity=fill_opacity*fill_color.alpha;
+            CompositePixelOver(image,&fill_color,fill_opacity,q,
+              GetPixelAlpha(image,q),q);
+            if (active == MagickFalse)
+              {
+                sync=SyncCacheViewAuthenticPixels(image_view,exception);
+                if (sync == MagickFalse)
+                  status=MagickFalse;
+              }
+            p++;
+            q+=GetPixelChannels(image);
+          }
+          sync=SyncCacheViewAuthenticPixels(image_view,exception);
+          if (sync == MagickFalse)
+            status=MagickFalse;
+        }
+        image_view=DestroyCacheView(image_view);
+      }
+    if ((bitmap->left+bitmap->bitmap.width) > metrics->width)
+      metrics->width=bitmap->left+bitmap->bitmap.width;
+    if ((draw_info->interword_spacing != 0.0) &&
+        (IsUTFSpace(GetUTFCode(p)) != MagickFalse) &&
+        (IsUTFSpace(code) == MagickFalse))
+      origin.x+=64.0*direction*draw_info->interword_spacing;
+    else
+      origin.x+=direction*face->glyph->advance.x;
+    metrics->origin.x=origin.x;
+    metrics->origin.y=origin.y;
+    if (last_glyph.id != 0)
+      FT_Done_Glyph(last_glyph.image);
+    last_glyph=glyph;
+    code=GetUTFCode(p);
+  }
+  if (utf8 != (unsigned char *) NULL)
+    utf8=(unsigned char *) RelinquishMagickMemory(utf8);
+  if (last_glyph.id != 0)
+    FT_Done_Glyph(last_glyph.image);
+  if ((draw_info->stroke.alpha != TransparentAlpha) ||
+      (draw_info->stroke_pattern != (Image *) NULL))
+    {
+      if (draw_info->render != MagickFalse)
+        {
+          /*
+            Draw text stroke.
+          */
+          annotate_info->linejoin=RoundJoin;
+          annotate_info->affine.tx=offset->x;
+          annotate_info->affine.ty=offset->y;
+          (void) ConcatenateString(&annotate_info->primitive,"'");
+          (void) DrawImage(image,annotate_info);
+        }
+      }
+  /*
+    Determine font metrics.
+  */
+  glyph.id=FT_Get_Char_Index(face,'_');
+  glyph.origin=origin;
+  status=FT_Load_Glyph(face,glyph.id,flags);
+  if (status == 0)
+    {
+      status=FT_Get_Glyph(face->glyph,&glyph.image);
+      if (status == 0)
+        {
+          status=FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph.image)->
+            outline,&bounds);
+          if (status == 0)
+            {
+              FT_Vector_Transform(&glyph.origin,&affine);
+              (void) FT_Glyph_Transform(glyph.image,&affine,&glyph.origin);
+              status=FT_Glyph_To_Bitmap(&glyph.image,ft_render_mode_normal,
+                (FT_Vector *) NULL,MagickTrue);
+              bitmap=(FT_BitmapGlyph) glyph.image;
+              if (bitmap->left > metrics->width)
+                metrics->width=bitmap->left;
+            }
+        }
+      if (glyph.id != 0)
+        FT_Done_Glyph(glyph.image);
+    }
+  metrics->width-=metrics->bounds.x1/64.0;
+  metrics->bounds.x1/=64.0;
+  metrics->bounds.y1/=64.0;
+  metrics->bounds.x2/=64.0;
+  metrics->bounds.y2/=64.0;
+  metrics->origin.x/=64.0;
+  metrics->origin.y/=64.0;
+  /*
+    Relinquish resources.
+  */
+  annotate_info=DestroyDrawInfo(annotate_info);
+  (void) FT_Done_Face(face);
+  (void) FT_Done_FreeType(library);
+  return(MagickTrue);
+}
+#else
+static MagickBooleanType RenderFreetype(Image *image,const DrawInfo *draw_info,
+  const char *magick_unused(encoding),const PointInfo *offset,
+  TypeMetric *metrics)
+{
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (Freetype)",
+    draw_info->font != (char *) NULL ? draw_info->font : "none");
+  return(RenderPostscript(image,draw_info,offset,metrics));
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e n d e r P o s t s c r i p t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RenderPostscript() renders text on the image with a Postscript font.  It
+%  also returns the bounding box of the text relative to the image.
+%
+%  The format of the RenderPostscript method is:
+%
+%      MagickBooleanType RenderPostscript(Image *image,DrawInfo *draw_info,
+%        const PointInfo *offset,TypeMetric *metrics)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o offset: (x,y) location of text relative to image.
+%
+%    o metrics: bounding box of text.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static char *EscapeParenthesis(const char *text)
+{
+  char
+    *buffer;
+
+  register char
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    escapes;
+
+  escapes=0;
+  buffer=AcquireString(text);
+  p=buffer;
+  for (i=0; i < (ssize_t) MagickMin(strlen(text),MaxTextExtent-escapes-1); i++)
+  {
+    if ((text[i] == '(') || (text[i] == ')'))
+      {
+        *p++='\\';
+        escapes++;
+      }
+    *p++=text[i];
+  }
+  *p='\0';
+  return(buffer);
+}
+
+static MagickBooleanType RenderPostscript(Image *image,
+  const DrawInfo *draw_info,const PointInfo *offset,TypeMetric *metrics)
+{
+  char
+    filename[MaxTextExtent],
+    geometry[MaxTextExtent],
+    *text;
+
+  FILE
+    *file;
+
+  Image
+    *annotate_image;
+
+  ImageInfo
+    *annotate_info;
+
+  int
+    unique_file;
+
+  MagickBooleanType
+    identity;
+
+  PointInfo
+    extent,
+    point,
+    resolution;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Render label with a Postscript font.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
+      "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
+      draw_info->font : "none",draw_info->pointsize);
+  file=(FILE *) NULL;
+  unique_file=AcquireUniqueFileResource(filename);
+  if (unique_file != -1)
+    file=fdopen(unique_file,"wb");
+  if ((unique_file == -1) || (file == (FILE *) NULL))
+    {
+      ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
+        filename);
+      return(MagickFalse);
+    }
+  (void) FormatLocaleFile(file,"%%!PS-Adobe-3.0\n");
+  (void) FormatLocaleFile(file,"/ReencodeType\n");
+  (void) FormatLocaleFile(file,"{\n");
+  (void) FormatLocaleFile(file,"  findfont dup length\n");
+  (void) FormatLocaleFile(file,
+    "  dict begin { 1 index /FID ne {def} {pop pop} ifelse } forall\n");
+  (void) FormatLocaleFile(file,
+    "  /Encoding ISOLatin1Encoding def currentdict end definefont pop\n");
+  (void) FormatLocaleFile(file,"} bind def\n");
+  /*
+    Sample to compute bounding box.
+  */
+  identity=(draw_info->affine.sx == draw_info->affine.sy) &&
+    (draw_info->affine.rx == 0.0) && (draw_info->affine.ry == 0.0) ?
+    MagickTrue : MagickFalse;
+  extent.x=0.0;
+  extent.y=0.0;
+  for (i=0; i <= (ssize_t) (strlen(draw_info->text)+2); i++)
+  {
+    point.x=fabs(draw_info->affine.sx*i*draw_info->pointsize+
+      draw_info->affine.ry*2.0*draw_info->pointsize);
+    point.y=fabs(draw_info->affine.rx*i*draw_info->pointsize+
+      draw_info->affine.sy*2.0*draw_info->pointsize);
+    if (point.x > extent.x)
+      extent.x=point.x;
+    if (point.y > extent.y)
+      extent.y=point.y;
+  }
+  (void) FormatLocaleFile(file,"%g %g moveto\n",identity  != MagickFalse ? 0.0 :
+    extent.x/2.0,extent.y/2.0);
+  (void) FormatLocaleFile(file,"%g %g scale\n",draw_info->pointsize,
+    draw_info->pointsize);
+  if ((draw_info->font == (char *) NULL) || (*draw_info->font == '\0') ||
+      (strchr(draw_info->font,'/') != (char *) NULL))
+    (void) FormatLocaleFile(file,
+      "/Times-Roman-ISO dup /Times-Roman ReencodeType findfont setfont\n");
+  else
+    (void) FormatLocaleFile(file,
+      "/%s-ISO dup /%s ReencodeType findfont setfont\n",draw_info->font,
+      draw_info->font);
+  (void) FormatLocaleFile(file,"[%g %g %g %g 0 0] concat\n",
+    draw_info->affine.sx,-draw_info->affine.rx,-draw_info->affine.ry,
+    draw_info->affine.sy);
+  text=EscapeParenthesis(draw_info->text);
+  if (identity == MagickFalse)
+    (void) FormatLocaleFile(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",
+      text);
+  (void) FormatLocaleFile(file,"(%s) show\n",text);
+  text=DestroyString(text);
+  (void) FormatLocaleFile(file,"showpage\n");
+  (void) fclose(file);
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0!",
+    floor(extent.x+0.5),floor(extent.y+0.5));
+  annotate_info=AcquireImageInfo();
+  (void) FormatLocaleString(annotate_info->filename,MaxTextExtent,"ps:%s",
+    filename);
+  (void) CloneString(&annotate_info->page,geometry);
+  if (draw_info->density != (char *) NULL)
+    (void) CloneString(&annotate_info->density,draw_info->density);
+  annotate_info->antialias=draw_info->text_antialias;
+  annotate_image=ReadImage(annotate_info,&image->exception);
+  CatchException(&image->exception);
+  annotate_info=DestroyImageInfo(annotate_info);
+  (void) RelinquishUniqueFileResource(filename);
+  if (annotate_image == (Image *) NULL)
+    return(MagickFalse);
+  resolution.x=DefaultResolution;
+  resolution.y=DefaultResolution;
+  if (draw_info->density != (char *) NULL)
+    {
+      GeometryInfo
+        geometry_info;
+
+      MagickStatusType
+        flags;
+
+      flags=ParseGeometry(draw_info->density,&geometry_info);
+      resolution.x=geometry_info.rho;
+      resolution.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        resolution.y=resolution.x;
+    }
+  if (identity == MagickFalse)
+    (void) TransformImage(&annotate_image,"0x0",(char *) NULL);
+  else
+    {
+      RectangleInfo
+        crop_info;
+
+      crop_info=GetImageBoundingBox(annotate_image,&annotate_image->exception);
+      crop_info.height=(size_t) ((resolution.y/DefaultResolution)*
+        ExpandAffine(&draw_info->affine)*draw_info->pointsize+0.5);
+      crop_info.y=(ssize_t) ceil((resolution.y/DefaultResolution)*extent.y/8.0-
+        0.5);
+      (void) FormatLocaleString(geometry,MaxTextExtent,
+        "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
+        crop_info.height,(double) crop_info.x,(double) crop_info.y);
+      (void) TransformImage(&annotate_image,geometry,(char *) NULL);
+    }
+  metrics->pixels_per_em.x=(resolution.y/DefaultResolution)*
+    ExpandAffine(&draw_info->affine)*draw_info->pointsize;
+  metrics->pixels_per_em.y=metrics->pixels_per_em.x;
+  metrics->ascent=metrics->pixels_per_em.x;
+  metrics->descent=metrics->pixels_per_em.y/-5.0;
+  metrics->width=(double) annotate_image->columns/
+    ExpandAffine(&draw_info->affine);
+  metrics->height=1.152*metrics->pixels_per_em.x;
+  metrics->max_advance=metrics->pixels_per_em.x;
+  metrics->bounds.x1=0.0;
+  metrics->bounds.y1=metrics->descent;
+  metrics->bounds.x2=metrics->ascent+metrics->descent;
+  metrics->bounds.y2=metrics->ascent+metrics->descent;
+  metrics->underline_position=(-2.0);
+  metrics->underline_thickness=1.0;
+  if (draw_info->render == MagickFalse)
+    {
+      annotate_image=DestroyImage(annotate_image);
+      return(MagickTrue);
+    }
+  if (draw_info->fill.alpha != TransparentAlpha)
+    {
+      ExceptionInfo
+        *exception;
+
+      MagickBooleanType
+        sync;
+
+      PixelPacket
+        fill_color;
+
+      CacheView
+        *annotate_view;
+
+      /*
+        Render fill color.
+      */
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      if (annotate_image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(annotate_image,OpaqueAlphaChannel);
+      fill_color=draw_info->fill;
+      exception=(&image->exception);
+      annotate_view=AcquireCacheView(annotate_image);
+      for (y=0; y < (ssize_t) annotate_image->rows; y++)
+      {
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        q=GetCacheViewAuthenticPixels(annotate_view,0,y,annotate_image->columns,
+          1,exception);
+        if (q == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) annotate_image->columns; x++)
+        {
+          (void) GetFillColor(draw_info,x,y,&fill_color);
+          SetPixelAlpha(annotate_image,ClampToQuantum((((MagickRealType)
+            GetPixelIntensity(annotate_image,q)*fill_color.alpha)/
+            QuantumRange)),q);
+          SetPixelRed(annotate_image,fill_color.red,q);
+          SetPixelGreen(annotate_image,fill_color.green,q);
+          SetPixelBlue(annotate_image,fill_color.blue,q);
+          q+=GetPixelChannels(annotate_image);
+        }
+        sync=SyncCacheViewAuthenticPixels(annotate_view,exception);
+        if (sync == MagickFalse)
+          break;
+      }
+      annotate_view=DestroyCacheView(annotate_view);
+      (void) CompositeImage(image,OverCompositeOp,annotate_image,
+        (ssize_t) ceil(offset->x-0.5),(ssize_t) ceil(offset->y-(metrics->ascent+
+        metrics->descent)-0.5));
+    }
+  annotate_image=DestroyImage(annotate_image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e n d e r X 1 1                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RenderX11() renders text on the image with an X11 font.  It also returns the
+%  bounding box of the text relative to the image.
+%
+%  The format of the RenderX11 method is:
+%
+%      MagickBooleanType RenderX11(Image *image,DrawInfo *draw_info,
+%        const PointInfo *offset,TypeMetric *metrics)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o offset: (x,y) location of text relative to image.
+%
+%    o metrics: bounding box of text.
+%
+*/
+#if defined(MAGICKCORE_X11_DELEGATE)
+static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
+  const PointInfo *offset,TypeMetric *metrics)
+{
+  MagickBooleanType
+    status;
+
+  static DrawInfo
+    cache_info;
+
+  static Display
+    *display = (Display *) NULL;
+
+  static XAnnotateInfo
+    annotate_info;
+
+  static XFontStruct
+    *font_info;
+
+  static XPixelInfo
+    pixel;
+
+  static XResourceInfo
+    resource_info;
+
+  static XrmDatabase
+    resource_database;
+
+  static XStandardColormap
+    *map_info;
+
+  static XVisualInfo
+    *visual_info;
+
+  size_t
+    height,
+    width;
+
+  if (annotate_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&annotate_semaphore);
+  LockSemaphoreInfo(annotate_semaphore);
+  if (display == (Display *) NULL)
+    {
+      const char
+        *client_name;
+
+      ImageInfo
+        *image_info;
+
+      /*
+        Open X server connection.
+      */
+      display=XOpenDisplay(draw_info->server_name);
+      if (display == (Display *) NULL)
+        {
+          ThrowXWindowException(XServerError,"UnableToOpenXServer",
+            draw_info->server_name);
+          return(MagickFalse);
+        }
+      /*
+        Get user defaults from X resource database.
+      */
+      (void) XSetErrorHandler(XError);
+      image_info=AcquireImageInfo();
+      client_name=GetClientName();
+      resource_database=XGetResourceDatabase(display,client_name);
+      XGetResourceInfo(image_info,resource_database,client_name,&resource_info);
+      resource_info.close_server=MagickFalse;
+      resource_info.colormap=PrivateColormap;
+      resource_info.font=AcquireString(draw_info->font);
+      resource_info.background_color=AcquireString("#ffffffffffff");
+      resource_info.foreground_color=AcquireString("#000000000000");
+      map_info=XAllocStandardColormap();
+      if (map_info == (XStandardColormap *) NULL)
+        {
+          ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
+            image->filename);
+          return(MagickFalse);
+        }
+      /*
+        Initialize visual info.
+      */
+      visual_info=XBestVisualInfo(display,map_info,&resource_info);
+      if (visual_info == (XVisualInfo *) NULL)
+        {
+          ThrowXWindowException(XServerError,"UnableToGetVisual",
+            image->filename);
+          return(MagickFalse);
+        }
+      map_info->colormap=(Colormap) NULL;
+      pixel.pixels=(unsigned long *) NULL;
+      /*
+        Initialize Standard Colormap info.
+      */
+      XGetMapInfo(visual_info,XDefaultColormap(display,visual_info->screen),
+        map_info);
+      XGetPixelInfo(display,visual_info,map_info,&resource_info,(Image *) NULL,
+        &pixel);
+      pixel.annotate_context=XDefaultGC(display,visual_info->screen);
+      /*
+        Initialize font info.
+      */
+      font_info=XBestFont(display,&resource_info,MagickFalse);
+      if (font_info == (XFontStruct *) NULL)
+        {
+          ThrowXWindowException(XServerError,"UnableToLoadFont",
+            draw_info->font);
+          return(MagickFalse);
+        }
+      if ((map_info == (XStandardColormap *) NULL) ||
+          (visual_info == (XVisualInfo *) NULL) ||
+          (font_info == (XFontStruct *) NULL))
+        {
+          XFreeResources(display,visual_info,map_info,&pixel,font_info,
+            &resource_info,(XWindowInfo *) NULL);
+          ThrowXWindowException(XServerError,"UnableToLoadFont",
+            image->filename);
+          return(MagickFalse);
+        }
+      cache_info=(*draw_info);
+    }
+  UnlockSemaphoreInfo(annotate_semaphore);
+  /*
+    Initialize annotate info.
+  */
+  XGetAnnotateInfo(&annotate_info);
+  annotate_info.stencil=ForegroundStencil;
+  if (cache_info.font != draw_info->font)
+    {
+      /*
+        Type name has changed.
+      */
+      (void) XFreeFont(display,font_info);
+      (void) CloneString(&resource_info.font,draw_info->font);
+      font_info=XBestFont(display,&resource_info,MagickFalse);
+      if (font_info == (XFontStruct *) NULL)
+        {
+          ThrowXWindowException(XServerError,"UnableToLoadFont",
+            draw_info->font);
+          return(MagickFalse);
+        }
+    }
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(AnnotateEvent,GetMagickModule(),
+      "Font %s; pointsize %g",draw_info->font != (char *) NULL ?
+      draw_info->font : "none",draw_info->pointsize);
+  cache_info=(*draw_info);
+  annotate_info.font_info=font_info;
+  annotate_info.text=(char *) draw_info->text;
+  annotate_info.width=(unsigned int) XTextWidth(font_info,draw_info->text,
+    (int) strlen(draw_info->text));
+  annotate_info.height=(unsigned int) font_info->ascent+font_info->descent;
+  metrics->pixels_per_em.x=(double) font_info->max_bounds.width;
+  metrics->pixels_per_em.y=(double) font_info->ascent+font_info->descent;
+  metrics->ascent=(double) font_info->ascent+4;
+  metrics->descent=(double) (-font_info->descent);
+  metrics->width=annotate_info.width/ExpandAffine(&draw_info->affine);
+  metrics->height=font_info->ascent+font_info->descent;
+  metrics->max_advance=(double) font_info->max_bounds.width;
+  metrics->bounds.x1=0.0;
+  metrics->bounds.y1=metrics->descent;
+  metrics->bounds.x2=metrics->ascent+metrics->descent;
+  metrics->bounds.y2=metrics->ascent+metrics->descent;
+  metrics->underline_position=(-2.0);
+  metrics->underline_thickness=1.0;
+  if (draw_info->render == MagickFalse)
+    return(MagickTrue);
+  if (draw_info->fill.alpha == TransparentAlpha)
+    return(MagickTrue);
+  /*
+    Render fill color.
+  */
+  width=annotate_info.width;
+  height=annotate_info.height;
+  if ((draw_info->affine.rx != 0.0) || (draw_info->affine.ry != 0.0))
+    {
+      if (((draw_info->affine.sx-draw_info->affine.sy) == 0.0) &&
+          ((draw_info->affine.rx+draw_info->affine.ry) == 0.0))
+        annotate_info.degrees=(180.0/MagickPI)*
+          atan2(draw_info->affine.rx,draw_info->affine.sx);
+    }
+  (void) FormatLocaleString(annotate_info.geometry,MaxTextExtent,
+    "%.20gx%.20g%+.20g%+.20g",(double) width,(double) height,
+    ceil(offset->x-0.5),ceil(offset->y-metrics->ascent-metrics->descent+
+    draw_info->interline_spacing-0.5));
+  pixel.pen_color.red=ScaleQuantumToShort(draw_info->fill.red);
+  pixel.pen_color.green=ScaleQuantumToShort(draw_info->fill.green);
+  pixel.pen_color.blue=ScaleQuantumToShort(draw_info->fill.blue);
+  status=XAnnotateImage(display,&pixel,&annotate_info,image);
+  if (status == 0)
+    {
+      ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+#else
+static MagickBooleanType RenderX11(Image *image,const DrawInfo *draw_info,
+  const PointInfo *offset,TypeMetric *metrics)
+{
+  (void) draw_info;
+  (void) offset;
+  (void) metrics;
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
+    image->filename);
+  return(MagickFalse);
+}
+#endif
diff --git a/MagickCore/annotate.h b/MagickCore/annotate.h
new file mode 100644
index 0000000..14df56a
--- /dev/null
+++ b/MagickCore/annotate.h
@@ -0,0 +1,44 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image annotation methods.
+*/
+#ifndef _MAGICKCORE_ANNOTATE_H
+#define _MAGICKCORE_ANNOTATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/draw.h"
+
+extern MagickExport MagickBooleanType
+  AnnotateComponentGenesis(void),
+  AnnotateImage(Image *,const DrawInfo *),
+  GetMultilineTypeMetrics(Image *,const DrawInfo *,TypeMetric *),
+  GetTypeMetrics(Image *,const DrawInfo *,TypeMetric *);
+
+extern MagickExport ssize_t
+  FormatMagickCaption(Image *,DrawInfo *,const MagickBooleanType,TypeMetric *,
+    char **);
+
+extern MagickExport void
+  AnnotateComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/api.h b/MagickCore/api.h
new file mode 100644
index 0000000..0caf8e2
--- /dev/null
+++ b/MagickCore/api.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  Deprecated as of ImageMagick 6.2.3.
+
+  MagickCore Application Programming Interface declarations.
+*/
+
+#ifndef _MAGICKCORE_API_DEPRECATED_H
+#define _MAGICKCORE_API_DEPRECATED_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "magick/MagickCore.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/artifact.c b/MagickCore/artifact.c
new file mode 100644
index 0000000..9693c7f
--- /dev/null
+++ b/MagickCore/artifact.c
@@ -0,0 +1,450 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            AAA   RRRR   TTTTT  IIIII  FFFFF   AAA    CCCC  TTTTT            %
+%           A   A  R   R    T      I    F      A   A  C        T              %
+%           AAAAA  RRRRR    T      I    FFF    AAAAA  C        T              %
+%           A   A  R R      T      I    F      A   A  C        T              %
+%           A   A  R  R     T    IIIII  F      A   A  CCCCC    T              %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Artifact Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 March 2000                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/compare.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/fx-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/option.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e A r t i f a c t s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageArtifacts() clones one or more image artifacts.
+%
+%  The format of the CloneImageArtifacts method is:
+%
+%      MagickBooleanType CloneImageArtifacts(Image *image,
+%        const Image *clone_image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o clone_image: the clone image.
+%
+*/
+MagickExport MagickBooleanType CloneImageArtifacts(Image *image,
+  const Image *clone_image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(clone_image != (const Image *) NULL);
+  assert(clone_image->signature == MagickSignature);
+  if (clone_image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      clone_image->filename);
+  if (clone_image->artifacts != (void *) NULL)
+    image->artifacts=CloneSplayTree((SplayTreeInfo *) clone_image->artifacts,
+      (void *(*)(void *)) ConstantString,(void *(*)(void *)) ConstantString);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e f i n e I m a g e A r t i f a c t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineImageArtifact() associates a key/value pair with an image artifact.
+%
+%  The format of the DefineImageArtifact method is:
+%
+%      MagickBooleanType DefineImageArtifact(Image *image,
+%        const char *artifact)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o artifact: the image artifact.
+%
+*/
+MagickExport MagickBooleanType DefineImageArtifact(Image *image,
+  const char *artifact)
+{
+  char
+    key[MaxTextExtent],
+    value[MaxTextExtent];
+
+  register char
+    *p;
+
+  assert(image != (Image *) NULL);
+  assert(artifact != (const char *) NULL);
+  (void) CopyMagickString(key,artifact,MaxTextExtent-1);
+  for (p=key; *p != '\0'; p++)
+    if (*p == '=')
+      break;
+  *value='\0';
+  if (*p == '=')
+    (void) CopyMagickString(value,p+1,MaxTextExtent);
+  *p='\0';
+  return(SetImageArtifact(image,key,value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e A r t i f a c t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageArtifact() deletes an image artifact.
+%
+%  The format of the DeleteImageArtifact method is:
+%
+%      MagickBooleanType DeleteImageArtifact(Image *image,const char *artifact)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o artifact: the image artifact.
+%
+*/
+MagickExport MagickBooleanType DeleteImageArtifact(Image *image,
+  const char *artifact)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->artifacts == (void *) NULL)
+    return(MagickFalse);
+  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->artifacts,artifact));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e A r t i f a c t s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageArtifacts() releases memory associated with image artifact
+%  values.
+%
+%  The format of the DestroyDefines method is:
+%
+%      void DestroyImageArtifacts(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DestroyImageArtifacts(Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->artifacts != (void *) NULL)
+    image->artifacts=(void *) DestroySplayTree((SplayTreeInfo *)
+      image->artifacts);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e A r t i f a c t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageArtifact() gets a value associated with an image artifact.
+%
+%  Note, the artifact is a constant.  Do not attempt to free it.
+%
+%  The format of the GetImageArtifact method is:
+%
+%      const char *GetImageArtifact(const Image *image,const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o key: the key.
+%
+*/
+MagickExport const char *GetImageArtifact(const Image *image,
+  const char *artifact)
+{
+  register const char
+    *p;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  p=(const char *) NULL;
+  if (artifact == (const char *) NULL)
+    {
+      ResetSplayTreeIterator((SplayTreeInfo *) image->artifacts);
+      p=(const char *) GetNextValueInSplayTree((SplayTreeInfo *)
+        image->artifacts);
+      return(p);
+    }
+  if (image->artifacts != (void *) NULL)
+    {
+      p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+        image->artifacts,artifact);
+      if (p != (const char *) NULL)
+        return(p);
+    }
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e A r t i f a c t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageArtifact() gets the next image artifact value.
+%
+%  The format of the GetNextImageArtifact method is:
+%
+%      char *GetNextImageArtifact(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport char *GetNextImageArtifact(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->artifacts == (void *) NULL)
+    return((char *) NULL);
+  return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->artifacts));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e I m a g e A r t i f a c t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveImageArtifact() removes an artifact from the image and returns its
+%  value.
+%
+%  The format of the RemoveImageArtifact method is:
+%
+%      char *RemoveImageArtifact(Image *image,const char *artifact)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o artifact: the image artifact.
+%
+*/
+MagickExport char *RemoveImageArtifact(Image *image,const char *artifact)
+{
+  char
+    *value;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->artifacts == (void *) NULL)
+    return((char *) NULL);
+  value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *) image->artifacts,
+    artifact);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e A r t i f a c t I t e r a t o r                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImageArtifactIterator() resets the image artifact iterator.  Use it
+%  in conjunction with GetNextImageArtifact() to iterate over all the values
+%  associated with an image artifact.
+%
+%  The format of the ResetImageArtifactIterator method is:
+%
+%      ResetImageArtifactIterator(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void ResetImageArtifactIterator(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->artifacts == (void *) NULL)
+    return;
+  ResetSplayTreeIterator((SplayTreeInfo *) image->artifacts);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e A r t i f a c t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageArtifact() associates a value with an image artifact.
+%
+%  The format of the SetImageArtifact method is:
+%
+%      MagickBooleanType SetImageArtifact(Image *image,const char *artifact,
+%        const char *value)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o artifact: the image artifact.
+%
+%    o values: the image artifact values.
+%
+*/
+MagickExport MagickBooleanType SetImageArtifact(Image *image,
+  const char *artifact,const char *value)
+{
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->artifacts == (void *) NULL)
+    image->artifacts=NewSplayTree(CompareSplayTreeString,
+      RelinquishMagickMemory,RelinquishMagickMemory);
+  if ((value == (const char *) NULL) || (*value == '\0'))
+    return(DeleteImageArtifact(image,artifact));
+  status=AddValueToSplayTree((SplayTreeInfo *) image->artifacts,
+    ConstantString(artifact),ConstantString(value));
+  return(status);
+}
diff --git a/MagickCore/artifact.h b/MagickCore/artifact.h
new file mode 100644
index 0000000..b4de809
--- /dev/null
+++ b/MagickCore/artifact.h
@@ -0,0 +1,46 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore artifact methods.
+*/
+#ifndef _MAGICKCORE_ARTIFACT_H
+#define _MAGICKCORE_ARTIFACT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport char
+  *GetNextImageArtifact(const Image *),
+  *RemoveImageArtifact(Image *,const char *);
+
+extern MagickExport const char
+  *GetImageArtifact(const Image *,const char *);
+
+extern MagickExport MagickBooleanType
+  CloneImageArtifacts(Image *,const Image *),
+  DefineImageArtifact(Image *,const char *),
+  DeleteImageArtifact(Image *,const char *),
+  SetImageArtifact(Image *,const char *,const char *);
+
+extern MagickExport void
+  DestroyImageArtifacts(Image *),
+  ResetImageArtifactIterator(const Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/attribute.c b/MagickCore/attribute.c
new file mode 100644
index 0000000..12f35e3
--- /dev/null
+++ b/MagickCore/attribute.c
@@ -0,0 +1,924 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%         AAA   TTTTT  TTTTT  RRRR   IIIII  BBBB   U   U  TTTTT  EEEEE        %
+%        A   A    T      T    R   R    I    B   B  U   U    T    E            %
+%        AAAAA    T      T    RRRR     I    BBBB   U   U    T    EEE          %
+%        A   A    T      T    R R      I    B   B  U   U    T    E            %
+%        A   A    T      T    R  R   IIIII  BBBB    UUU     T    EEEEE        %
+%                                                                             %
+%                                                                             %
+%                    MagickCore Get / Set Image Attributes                    %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                October 2002                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colormap-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/draw-private.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/identify.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e B o u n d i n g B o x                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageBoundingBox() returns the bounding box of an image canvas.
+%
+%  The format of the GetImageBoundingBox method is:
+%
+%      RectangleInfo GetImageBoundingBox(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o bounds: Method GetImageBoundingBox returns the bounding box of an
+%      image canvas.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    target[3],
+    zero;
+
+  RectangleInfo
+    bounds;
+
+  register const Quantum
+    *p;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  bounds.width=0;
+  bounds.height=0;
+  bounds.x=(ssize_t) image->columns;
+  bounds.y=(ssize_t) image->rows;
+  GetPixelInfo(image,&target[0]);
+  image_view=AcquireCacheView(image);
+  p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
+  if (p == (const Quantum *) NULL)
+    {
+      image_view=DestroyCacheView(image_view);
+      return(bounds);
+    }
+  SetPixelInfo(image,p,&target[0]);
+  GetPixelInfo(image,&target[1]);
+  p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
+    exception);
+  SetPixelInfo(image,p,&target[1]);
+  GetPixelInfo(image,&target[2]);
+  p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
+    exception);
+  SetPixelInfo(image,p,&target[2]);
+  status=MagickTrue;
+  GetPixelInfo(image,&zero);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    RectangleInfo
+      bounding_box;
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#  pragma omp critical (MagickCore_GetImageBoundingBox)
+#endif
+    bounding_box=bounds;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,p,&pixel);
+      if ((x < bounding_box.x) &&
+          (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
+        bounding_box.x=x;
+      if ((x > (ssize_t) bounding_box.width) &&
+          (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
+        bounding_box.width=(size_t) x;
+      if ((y < bounding_box.y) &&
+          (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
+        bounding_box.y=y;
+      if ((y > (ssize_t) bounding_box.height) &&
+          (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
+        bounding_box.height=(size_t) y;
+      p+=GetPixelChannels(image);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#  pragma omp critical (MagickCore_GetImageBoundingBox)
+#endif
+    {
+      if (bounding_box.x < bounds.x)
+        bounds.x=bounding_box.x;
+      if (bounding_box.y < bounds.y)
+        bounds.y=bounding_box.y;
+      if (bounding_box.width > bounds.width)
+        bounds.width=bounding_box.width;
+      if (bounding_box.height > bounds.height)
+        bounds.height=bounding_box.height;
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  if ((bounds.width == 0) || (bounds.height == 0))
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+      "GeometryDoesNotContainImage","`%s'",image->filename);
+  else
+    {
+      bounds.width-=(bounds.x-1);
+      bounds.height-=(bounds.y-1);
+    }
+  return(bounds);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l D e p t h                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelDepth() returns the depth of a particular image channel.
+%
+%  The format of the GetImageChannelDepth method is:
+%
+%      size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
+%      size_t GetImageChannelDepth(const Image *image,
+%        const ChannelType channel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
+{
+  return(GetImageChannelDepth(image,CompositeChannels,exception));
+}
+
+MagickExport size_t GetImageChannelDepth(const Image *image,
+  const ChannelType channel,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    id;
+
+  size_t
+    *current_depth,
+    depth,
+    number_threads;
+
+  ssize_t
+    y;
+
+  /*
+    Compute image depth.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  number_threads=GetOpenMPMaximumThreads();
+  current_depth=(size_t *) AcquireQuantumMemory(number_threads,
+    sizeof(*current_depth));
+  if (current_depth == (size_t *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  status=MagickTrue;
+  for (id=0; id < (ssize_t) number_threads; id++)
+    current_depth[id]=1;
+  if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
+    {
+      register const PixelPacket
+        *restrict p;
+
+      register ssize_t
+        i;
+
+      p=image->colormap;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        const int
+          id = GetOpenMPThreadId();
+
+        if (status == MagickFalse)
+          continue;
+        while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
+        {
+          MagickStatusType
+            status;
+
+          QuantumAny
+            range;
+
+          status=0;
+          range=GetQuantumRange(current_depth[id]);
+          if ((channel & RedChannel) != 0)
+            status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
+              range),range);
+          if ((channel & GreenChannel) != 0)
+            status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
+              range),range);
+          if ((channel & BlueChannel) != 0)
+            status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
+              range),range);
+          if (status == 0)
+            break;
+          current_depth[id]++;
+        }
+        p++;
+      }
+      depth=current_depth[0];
+      for (id=1; id < (ssize_t) number_threads; id++)
+        if (depth < current_depth[id])
+          depth=current_depth[id];
+      current_depth=(size_t *) RelinquishMagickMemory(current_depth);
+      return(depth);
+    }
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      continue;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
+      {
+        MagickStatusType
+          status;
+
+        QuantumAny
+          range;
+
+        status=0;
+        range=GetQuantumRange(current_depth[id]);
+        if ((channel & RedChannel) != 0)
+          status|=GetPixelRed(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelRed(image,p),range),range);
+        if ((channel & GreenChannel) != 0)
+          status|=GetPixelGreen(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelGreen(image,p),range),range);
+        if ((channel & BlueChannel) != 0)
+          status|=GetPixelBlue(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelBlue(image,p),range),range);
+        if (((channel & AlphaChannel) != 0) && (image->matte != MagickFalse))
+          status|=GetPixelAlpha(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelAlpha(image,p),range),range);
+        if (((channel & BlackChannel) != 0) &&
+            (image->colorspace == CMYKColorspace))
+          status|=GetPixelBlack(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelBlack(image,p),range),range);
+        if (status == 0)
+          break;
+        current_depth[id]++;
+      }
+      p+=GetPixelChannels(image);
+    }
+    if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  depth=current_depth[0];
+  for (id=1; id < (ssize_t) number_threads; id++)
+    if (depth < current_depth[id])
+      depth=current_depth[id];
+  current_depth=(size_t *) RelinquishMagickMemory(current_depth);
+  return(depth);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e Q u a n t u m D e p t h                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageQuantumDepth() returns the depth of the image rounded to a legal
+%  quantum depth: 8, 16, or 32.
+%
+%  The format of the GetImageQuantumDepth method is:
+%
+%      size_t GetImageQuantumDepth(const Image *image,
+%        const MagickBooleanType constrain)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o constrain: A value other than MagickFalse, constrains the depth to
+%      a maximum of MAGICKCORE_QUANTUM_DEPTH.
+%
+*/
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport size_t GetImageQuantumDepth(const Image *image,
+  const MagickBooleanType constrain)
+{
+  size_t
+    depth;
+
+  depth=image->depth;
+  if (depth <= 8)
+    depth=8;
+  else
+    if (depth <= 16)
+      depth=16;
+    else
+      if (depth <= 32)
+        depth=32;
+      else
+        if (depth <= 64)
+          depth=64;
+  if (constrain != MagickFalse)
+    depth=(size_t) MagickMin((double) depth,(double)
+      MAGICKCORE_QUANTUM_DEPTH);
+  return(depth);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e T y p e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageType() returns the potential type of image:
+%
+%        Bilevel         Grayscale        GrayscaleMatte
+%        Palette         PaletteMatte     TrueColor
+%        TrueColorMatte  ColorSeparation  ColorSeparationMatte
+%
+%  To ensure the image type matches its potential, use SetImageType():
+%
+%    (void) SetImageType(image,GetImageType(image));
+%
+%  The format of the GetImageType method is:
+%
+%      ImageType GetImageType(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->colorspace == CMYKColorspace)
+    {
+      if (image->matte == MagickFalse)
+        return(ColorSeparationType);
+      return(ColorSeparationMatteType);
+    }
+  if (IsImageMonochrome(image,exception) != MagickFalse)
+    return(BilevelType);
+  if (IsImageGray(image,exception) != MagickFalse)
+    {
+      if (image->matte != MagickFalse)
+        return(GrayscaleMatteType);
+      return(GrayscaleType);
+    }
+  if (IsPaletteImage(image,exception) != MagickFalse)
+    {
+      if (image->matte != MagickFalse)
+        return(PaletteMatteType);
+      return(PaletteType);
+    }
+  if (image->matte != MagickFalse)
+    return(TrueColorMatteType);
+  return(TrueColorType);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s I m a g e G r a y                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImageGray() returns MagickTrue if all the pixels in the image have the
+%  same red, green, and blue intensities.
+%
+%  The format of the IsImageGray method is:
+%
+%      MagickBooleanType IsImageGray(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsImageGray(const Image *image,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  ImageType
+    type;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    x;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
+      (image->type == GrayscaleMatteType))
+    return(MagickTrue);
+  if (image->colorspace == CMYKColorspace)
+    return(MagickFalse);
+  type=BilevelType;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (IsPixelGray(image,p) == MagickFalse)
+        {
+          type=UndefinedType;
+          break;
+        }
+      if ((type == BilevelType) &&
+          (IsPixelMonochrome(image,p) == MagickFalse))
+        type=GrayscaleType;
+      p+=GetPixelChannels(image);
+    }
+    if (type == UndefinedType)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  if (type == UndefinedType)
+    return(MagickFalse);
+  ((Image *) image)->type=type;
+  if ((type == GrayscaleType) && (image->matte != MagickFalse))
+    ((Image *) image)->type=GrayscaleMatteType;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s I m a g e M o n o c h r o m e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImageMonochrome() returns MagickTrue if all the pixels in the image have
+%  the same red, green, and blue intensities and the intensity is either
+%  0 or QuantumRange.
+%
+%  The format of the IsImageMonochrome method is:
+%
+%      MagickBooleanType IsImageMonochrome(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  ImageType
+    type;
+
+  register ssize_t
+    x;
+
+  register const Quantum
+    *p;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->type == BilevelType)
+    return(MagickTrue);
+  if (image->colorspace == CMYKColorspace)
+    return(MagickFalse);
+  type=BilevelType;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (IsPixelMonochrome(image,p) == MagickFalse)
+        {
+          type=UndefinedType;
+          break;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (type == UndefinedType)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  if (type == UndefinedType)
+    return(MagickFalse);
+  ((Image *) image)->type=type;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s I m a g e O p a q u e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImageOpaque() returns MagickTrue if none of the pixels in the image have
+%  an opacity value other than opaque (0).
+%
+%  The format of the IsImageOpaque method is:
+%
+%      MagickBooleanType IsImageOpaque(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsImageOpaque(const Image *image,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    x;
+
+  ssize_t
+    y;
+
+  /*
+    Determine if image is opaque.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->matte == MagickFalse)
+    return(MagickTrue);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (GetPixelAlpha(image,p) != OpaqueAlpha)
+        break;
+      p+=GetPixelChannels(image);
+    }
+    if (x < (ssize_t) image->columns)
+     break;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e C h a n n e l D e p t h                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageChannelDepth() sets the depth of the image.
+%
+%  The format of the SetImageChannelDepth method is:
+%
+%      MagickBooleanType SetImageDepth(Image *image,const size_t depth)
+%      MagickBooleanType SetImageChannelDepth(Image *image,
+%        const ChannelType channel,const size_t depth)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o depth: the image depth.
+%
+*/
+MagickExport MagickBooleanType SetImageDepth(Image *image,
+  const size_t depth)
+{
+  return(SetImageChannelDepth(image,CompositeChannels,depth));
+}
+
+MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
+  const ChannelType channel,const size_t depth)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  QuantumAny
+    range;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (GetImageDepth(image,&image->exception) <= (size_t)
+      MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
+    {
+      image->depth=depth;
+      return(MagickTrue);
+    }
+  /*
+    Scale pixels to desired depth.
+  */
+  status=MagickTrue;
+  range=GetQuantumRange(depth);
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,ScaleAnyToQuantum(ScaleQuantumToAny(
+          GetPixelRed(image,q),range),range),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,ScaleAnyToQuantum(ScaleQuantumToAny(
+          GetPixelGreen(image,q),range),range),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,ScaleAnyToQuantum(ScaleQuantumToAny(
+          GetPixelBlue(image,q),range),range),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,ScaleAnyToQuantum(ScaleQuantumToAny(
+          GetPixelBlack(image,q),range),range),q);
+      if (((channel & AlphaChannel) != 0) && (image->matte != MagickFalse))
+        SetPixelAlpha(image,ScaleAnyToQuantum(ScaleQuantumToAny(
+          GetPixelAlpha(image,q),range),range),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      {
+        status=MagickFalse;
+        continue;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (image->storage_class == PseudoClass)
+    {
+      register ssize_t
+        i;
+
+      register PixelPacket
+        *restrict p;
+
+      p=image->colormap;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if ((channel & RedChannel) != 0)
+          p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
+        if ((channel & GreenChannel) != 0)
+          p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
+        if ((channel & BlueChannel) != 0)
+          p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
+        if ((channel & AlphaChannel) != 0)
+          p->alpha=ScaleAnyToQuantum(ScaleQuantumToAny(p->alpha,range),range);
+        p++;
+      }
+    }
+  image->depth=depth;
+  return(status);
+}
diff --git a/MagickCore/attribute.h b/MagickCore/attribute.h
new file mode 100644
index 0000000..029ef11
--- /dev/null
+++ b/MagickCore/attribute.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore methods to set or get image attributes.
+*/
+#ifndef _MAGICKCORE_ATTRIBUTE_H
+#define _MAGICKCORE_ATTRIBUTE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/image.h>
+#include <MagickCore/exception.h>
+
+extern MagickExport ImageType
+  GetImageType(const Image *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  IsImageGray(const Image *,ExceptionInfo *),
+  IsImageMonochrome(const Image *,ExceptionInfo *),
+  IsImageOpaque(const Image *,ExceptionInfo *),
+  SetImageChannelDepth(Image *,const ChannelType,const size_t),
+  SetImageDepth(Image *,const size_t);
+
+extern MagickExport RectangleInfo
+  GetImageBoundingBox(const Image *,ExceptionInfo *exception);
+
+extern MagickExport size_t
+  GetImageChannelDepth(const Image *,const ChannelType,ExceptionInfo *),
+  GetImageDepth(const Image *,ExceptionInfo *),
+  GetImageQuantumDepth(const Image *,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/blob-private.h b/MagickCore/blob-private.h
new file mode 100644
index 0000000..fe31b5f
--- /dev/null
+++ b/MagickCore/blob-private.h
@@ -0,0 +1,133 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore Binary Large OBjects private methods.
+*/
+#ifndef _MAGICKCORE_BLOB_PRIVATE_H
+#define _MAGICKCORE_BLOB_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/image.h"
+#include "MagickCore/stream.h"
+
+#define MagickMinBlobExtent  32767L
+#if defined(MAGICKCORE_HAVE_FSEEKO)
+# define fseek  fseeko
+# define ftell  ftello
+#endif
+
+typedef enum
+{
+  UndefinedBlobMode,
+  ReadBlobMode,
+  ReadBinaryBlobMode,
+  WriteBlobMode,
+  WriteBinaryBlobMode,
+  AppendBlobMode,
+  AppendBinaryBlobMode
+} BlobMode;
+
+typedef enum
+{
+  UndefinedStream,
+  FileStream,
+  StandardStream,
+  PipeStream,
+  ZipStream,
+  BZipStream,
+  FifoStream,
+  BlobStream
+} StreamType;
+
+typedef int
+  *(*BlobFifo)(const Image *,const void *,const size_t);
+
+extern MagickExport BlobInfo
+  *CloneBlobInfo(const BlobInfo *),
+  *ReferenceBlob(BlobInfo *);
+
+extern MagickExport char
+  *ReadBlobString(Image *,char *);
+
+extern MagickExport const struct stat
+  *GetBlobProperties(const Image *);
+
+extern MagickExport double
+  ReadBlobDouble(Image *);
+
+extern MagickExport float
+  ReadBlobFloat(Image *);
+
+extern MagickExport int
+  EOFBlob(const Image *),
+  ReadBlobByte(Image *);
+
+extern MagickExport  MagickBooleanType
+  CloseBlob(Image *),
+  DiscardBlobBytes(Image *,const MagickSizeType),
+  OpenBlob(const ImageInfo *,Image *,const BlobMode,ExceptionInfo *),
+  SetBlobExtent(Image *,const MagickSizeType),
+  UnmapBlob(void *,const size_t);
+
+extern MagickExport MagickOffsetType
+  SeekBlob(Image *,const MagickOffsetType,const int),
+  TellBlob(const Image *);
+
+extern MagickExport MagickSizeType
+  ReadBlobLongLong(Image *),
+  ReadBlobMSBLongLong(Image *);
+
+extern MagickExport ssize_t
+  ReadBlob(Image *,const size_t,unsigned char *),
+  WriteBlob(Image *,const size_t,const unsigned char *),
+  WriteBlobByte(Image *,const unsigned char),
+  WriteBlobFloat(Image *,const float),
+  WriteBlobLong(Image *,const unsigned int),
+  WriteBlobShort(Image *,const unsigned short),
+  WriteBlobLSBLong(Image *,const unsigned int),
+  WriteBlobLSBShort(Image *,const unsigned short),
+  WriteBlobMSBLong(Image *,const unsigned int),
+  WriteBlobMSBLongLong(Image *,const MagickSizeType),
+  WriteBlobMSBShort(Image *,const unsigned short),
+  WriteBlobString(Image *,const char *);
+
+extern MagickExport unsigned char
+  *DetachBlob(BlobInfo *),
+  *MapBlob(int,const MapMode,const MagickOffsetType,const size_t);
+
+extern MagickExport unsigned int
+  ReadBlobLong(Image *),
+  ReadBlobLSBLong(Image *),
+  ReadBlobMSBLong(Image *);
+
+extern MagickExport unsigned short
+  ReadBlobShort(Image *),
+  ReadBlobLSBShort(Image *),
+  ReadBlobMSBShort(Image *);
+
+extern MagickExport void
+  AttachBlob(BlobInfo *,const void *,const size_t),
+  GetBlobInfo(BlobInfo *),
+  MSBOrderLong(unsigned char *,const size_t),
+  MSBOrderShort(unsigned char *,const size_t);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/blob.c b/MagickCore/blob.c
new file mode 100644
index 0000000..683dc15
--- /dev/null
+++ b/MagickCore/blob.c
@@ -0,0 +1,4475 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                         BBBB   L       OOO   BBBB                           %
+%                         B   B  L      O   O  B   B                          %
+%                         BBBB   L      O   O  BBBB                           %
+%                         B   B  L      O   O  B   B                          %
+%                         BBBB   LLLLL   OOO   BBBB                           %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Binary Large OBjectS Methods                 %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1999                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/client.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#if defined(MAGICKCORE_HAVE_MMAP_FILEIO) && !defined(MAGICKCORE_WINDOWS_SUPPORT)
+# include <sys/mman.h>
+#endif
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+#include "zlib.h"
+#endif
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+#include "bzlib.h"
+#endif
+
+/*
+  Define declarations.
+*/
+#define MagickMaxBlobExtent  65541
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+# define MAP_ANONYMOUS  MAP_ANON
+#endif
+#if !defined(MAP_FAILED)
+#define MAP_FAILED  ((void *) -1)
+#endif
+#if !defined(MS_SYNC)
+#define MS_SYNC  0x04
+#endif
+#if defined(__OS2__)
+#include <io.h>
+#define _O_BINARY O_BINARY
+#endif
+
+/*
+  Typedef declarations.
+*/
+struct _BlobInfo
+{
+  size_t
+    length,
+    extent,
+    quantum;
+
+  MagickBooleanType
+    mapped,
+    eof;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    size;
+
+  MagickBooleanType
+    exempt,
+    synchronize,
+    status,
+    temporary;
+
+  StreamType
+    type;
+
+  FILE
+    *file;
+
+  struct stat
+    properties;
+
+  StreamHandler
+    stream;
+
+  unsigned char
+    *data;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  ssize_t
+    reference_count;
+
+  size_t
+    signature;
+};
+
+/*
+  Forward declarations.
+*/
+static int
+  SyncBlob(Image *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A t t a c h B l o b                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AttachBlob() attaches a blob to the BlobInfo structure.
+%
+%  The format of the AttachBlob method is:
+%
+%      void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o blob_info: Specifies a pointer to a BlobInfo structure.
+%
+%    o blob: the address of a character stream in one of the image formats
+%      understood by ImageMagick.
+%
+%    o length: This size_t integer reflects the length in bytes of the blob.
+%
+*/
+MagickExport void AttachBlob(BlobInfo *blob_info,const void *blob,
+  const size_t length)
+{
+  assert(blob_info != (BlobInfo *) NULL);
+  if (blob_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  blob_info->length=length;
+  blob_info->extent=length;
+  blob_info->quantum=(size_t) MagickMaxBlobExtent;
+  blob_info->offset=0;
+  blob_info->type=BlobStream;
+  blob_info->file=(FILE *) NULL;
+  blob_info->data=(unsigned char *) blob;
+  blob_info->mapped=MagickFalse;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   B l o b T o F i l e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BlobToFile() writes a blob to a file.  It returns MagickFalse if an error
+%  occurs otherwise MagickTrue.
+%
+%  The format of the BlobToFile method is:
+%
+%       MagickBooleanType BlobToFile(char *filename,const void *blob,
+%         const size_t length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: Write the blob to this file.
+%
+%    o blob: the address of a blob.
+%
+%    o length: This length in bytes of the blob.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline MagickSizeType MagickMin(const MagickSizeType x,
+  const MagickSizeType y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
+  const size_t length,ExceptionInfo *exception)
+{
+  int
+    file;
+
+  register size_t
+    i;
+
+  ssize_t
+    count;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(blob != (const void *) NULL);
+  if (*filename == '\0')
+    file=AcquireUniqueFileResource(filename);
+  else
+    file=open(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
+  if (file == -1)
+    {
+      ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
+      return(MagickFalse);
+    }
+  for (i=0; i < length; i+=count)
+  {
+    count=(ssize_t) write(file,(const char *) blob+i,(size_t) MagickMin(length-
+      i,(MagickSizeType) SSIZE_MAX));
+    if (count <= 0)
+      {
+        count=0;
+        if (errno != EINTR)
+          break;
+      }
+  }
+  file=close(file);
+  if ((file == -1) || (i < length))
+    {
+      ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   B l o b T o I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BlobToImage() implements direct to memory image formats.  It returns the
+%  blob as an image.
+%
+%  The format of the BlobToImage method is:
+%
+%      Image *BlobToImage(const ImageInfo *image_info,const void *blob,
+%        const size_t length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o blob: the address of a character stream in one of the image formats
+%      understood by ImageMagick.
+%
+%    o length: This size_t integer reflects the length in bytes of the blob.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *BlobToImage(const ImageInfo *image_info,const void *blob,
+  const size_t length,ExceptionInfo *exception)
+{
+  const MagickInfo
+    *magick_info;
+
+  Image
+    *image;
+
+  ImageInfo
+    *blob_info,
+    *clone_info;
+
+  MagickBooleanType
+    status;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((blob == (const void *) NULL) || (length == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
+        "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
+      return((Image *) NULL);
+    }
+  blob_info=CloneImageInfo(image_info);
+  blob_info->blob=(void *) blob;
+  blob_info->length=length;
+  if (*blob_info->magick == '\0')
+    (void) SetImageInfo(blob_info,0,exception);
+  magick_info=GetMagickInfo(blob_info->magick,exception);
+  if (magick_info == (const MagickInfo *) NULL)
+    {
+      blob_info=DestroyImageInfo(blob_info);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+        image_info->filename);
+      return((Image *) NULL);
+    }
+  if (GetMagickBlobSupport(magick_info) != MagickFalse)
+    {
+      /*
+        Native blob support for this image format.
+      */
+      (void) CopyMagickString(blob_info->filename,image_info->filename,
+        MaxTextExtent);
+      (void) CopyMagickString(blob_info->magick,image_info->magick,
+        MaxTextExtent);
+      image=ReadImage(blob_info,exception);
+      if (image != (Image *) NULL)
+        (void) DetachBlob(image->blob);
+      blob_info=DestroyImageInfo(blob_info);
+      return(image);
+    }
+  /*
+    Write blob to a temporary file on disk.
+  */
+  blob_info->blob=(void *) NULL;
+  blob_info->length=0;
+  *blob_info->filename='\0';
+  status=BlobToFile(blob_info->filename,blob,length,exception);
+  if (status == MagickFalse)
+    {
+      (void) RelinquishUniqueFileResource(blob_info->filename);
+      blob_info=DestroyImageInfo(blob_info);
+      return((Image *) NULL);
+    }
+  clone_info=CloneImageInfo(blob_info);
+  (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:%s",
+    blob_info->magick,blob_info->filename);
+  image=ReadImage(clone_info,exception);
+  clone_info=DestroyImageInfo(clone_info);
+  (void) RelinquishUniqueFileResource(blob_info->filename);
+  blob_info=DestroyImageInfo(blob_info);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o n e B l o b I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneBlobInfo() makes a duplicate of the given blob info structure, or if
+%  blob info is NULL, a new one.
+%
+%  The format of the CloneBlobInfo method is:
+%
+%      BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
+%
+%  A description of each parameter follows:
+%
+%    o blob_info: the blob info.
+%
+*/
+MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
+{
+  BlobInfo
+    *clone_info;
+
+  clone_info=(BlobInfo *) AcquireMagickMemory(sizeof(*clone_info));
+  if (clone_info == (BlobInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetBlobInfo(clone_info);
+  if (blob_info == (BlobInfo *) NULL)
+    return(clone_info);
+  clone_info->length=blob_info->length;
+  clone_info->extent=blob_info->extent;
+  clone_info->synchronize=blob_info->synchronize;
+  clone_info->quantum=blob_info->quantum;
+  clone_info->mapped=blob_info->mapped;
+  clone_info->eof=blob_info->eof;
+  clone_info->offset=blob_info->offset;
+  clone_info->size=blob_info->size;
+  clone_info->exempt=blob_info->exempt;
+  clone_info->status=blob_info->status;
+  clone_info->temporary=blob_info->temporary;
+  clone_info->type=blob_info->type;
+  clone_info->file=blob_info->file;
+  clone_info->properties=blob_info->properties;
+  clone_info->stream=blob_info->stream;
+  clone_info->data=blob_info->data;
+  clone_info->debug=IsEventLogging();
+  clone_info->reference_count=1;
+  return(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o s e B l o b                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloseBlob() closes a stream associated with the image.
+%
+%  The format of the CloseBlob method is:
+%
+%      MagickBooleanType CloseBlob(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType CloseBlob(Image *image)
+{
+  int
+    status;
+
+  /*
+    Close image file.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  if (image->blob->type == UndefinedStream)
+    return(MagickTrue);
+  if (image->blob->synchronize != MagickFalse)
+    SyncBlob(image);
+  image->blob->size=GetBlobSize(image);
+  image->extent=image->blob->size;
+  image->blob->eof=MagickFalse;
+  if (image->blob->exempt != MagickFalse)
+    {
+      image->blob->type=UndefinedStream;
+      return(MagickTrue);
+    }
+  status=0;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    case StandardStream:
+    case PipeStream:
+    {
+      status=ferror(image->blob->file);
+      break;
+    }
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      (void) gzerror(image->blob->file,&status);
+#endif
+      break;
+    }
+    case BZipStream:
+    {
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+      (void) BZ2_bzerror((BZFILE *) image->blob->file,&status);
+#endif
+      break;
+    }
+    case FifoStream:
+    case BlobStream:
+      break;
+  }
+  image->blob->status=status < 0 ? MagickTrue : MagickFalse;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    case StandardStream:
+    {
+      if (image->blob->synchronize != MagickFalse)
+        {
+          status=fflush(image->blob->file);
+          status=fsync(fileno(image->blob->file));
+        }
+      status=fclose(image->blob->file);
+      break;
+    }
+    case PipeStream:
+    {
+#if defined(MAGICKCORE_HAVE_PCLOSE)
+      status=pclose(image->blob->file);
+#endif
+      break;
+    }
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      status=gzclose(image->blob->file);
+#endif
+      break;
+    }
+    case BZipStream:
+    {
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+      BZ2_bzclose((BZFILE *) image->blob->file);
+#endif
+      break;
+    }
+    case FifoStream:
+      break;
+    case BlobStream:
+    {
+      if (image->blob->file != (FILE *) NULL)
+        {
+          if (image->blob->synchronize != MagickFalse)
+            (void) fsync(fileno(image->blob->file));
+          status=fclose(image->blob->file);
+        }
+      break;
+    }
+  }
+  (void) DetachBlob(image->blob);
+  image->blob->status=status < 0 ? MagickTrue : MagickFalse;
+  return(image->blob->status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y B l o b                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyBlob() deallocates memory associated with a blob.
+%
+%  The format of the DestroyBlob method is:
+%
+%      void DestroyBlob(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DestroyBlob(Image *image)
+{
+  MagickBooleanType
+    destroy;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->signature == MagickSignature);
+  destroy=MagickFalse;
+  LockSemaphoreInfo(image->blob->semaphore);
+  image->blob->reference_count--;
+  assert(image->blob->reference_count >= 0);
+  if (image->blob->reference_count == 0)
+    destroy=MagickTrue;
+  UnlockSemaphoreInfo(image->blob->semaphore);
+  if (destroy == MagickFalse)
+    return;
+  (void) CloseBlob(image);
+  if (image->blob->mapped != MagickFalse)
+    (void) UnmapBlob(image->blob->data,image->blob->length);
+  if (image->blob->semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&image->blob->semaphore);
+  image->blob->signature=(~MagickSignature);
+  image->blob=(BlobInfo *) RelinquishMagickMemory(image->blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e t a c h B l o b                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DetachBlob() detaches a blob from the BlobInfo structure.
+%
+%  The format of the DetachBlob method is:
+%
+%      unsigned char *DetachBlob(BlobInfo *blob_info)
+%
+%  A description of each parameter follows:
+%
+%    o blob_info: Specifies a pointer to a BlobInfo structure.
+%
+*/
+MagickExport unsigned char *DetachBlob(BlobInfo *blob_info)
+{
+  unsigned char
+    *data;
+
+  assert(blob_info != (BlobInfo *) NULL);
+  if (blob_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (blob_info->mapped != MagickFalse)
+    (void) UnmapBlob(blob_info->data,blob_info->length);
+  blob_info->mapped=MagickFalse;
+  blob_info->length=0;
+  blob_info->offset=0;
+  blob_info->eof=MagickFalse;
+  blob_info->exempt=MagickFalse;
+  blob_info->type=UndefinedStream;
+  blob_info->file=(FILE *) NULL;
+  data=blob_info->data;
+  blob_info->data=(unsigned char *) NULL;
+  blob_info->stream=(StreamHandler) NULL;
+  return(data);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  D i s c a r d B l o b B y t e s                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DiscardBlobBytes() discards bytes in a blob.
+%
+%  The format of the DiscardBlobBytes method is:
+%
+%      MagickBooleanType DiscardBlobBytes(Image *image,const size_t length)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o length:  the number of bytes to skip.
+%
+*/
+
+static inline const unsigned char *ReadBlobStream(Image *image,
+  const size_t length,unsigned char *data,ssize_t *count)
+{
+  assert(count != (ssize_t *) NULL);
+  assert(image->blob != (BlobInfo *) NULL);
+  if (image->blob->type != BlobStream)
+    {
+      *count=ReadBlob(image,length,data);
+      return(data);
+    }
+  if (image->blob->offset >= (MagickOffsetType) image->blob->length)
+    {
+      *count=0;
+      image->blob->eof=MagickTrue;
+      return(data);
+    }
+  data=image->blob->data+image->blob->offset;
+  *count=(ssize_t) MagickMin(length,(MagickSizeType) (image->blob->length-
+    image->blob->offset));
+  image->blob->offset+=(*count);
+  if (*count != (ssize_t) length)
+    image->blob->eof=MagickTrue;
+  return(data);
+}
+
+MagickExport MagickBooleanType DiscardBlobBytes(Image *image,
+  const MagickSizeType length)
+{
+  register MagickOffsetType
+    i;
+
+  size_t
+    quantum;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[16384];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  count=0;
+  for (i=0; i < (MagickOffsetType) length; i+=count)
+  {
+    quantum=(size_t) MagickMin(length-i,sizeof(buffer));
+    (void) ReadBlobStream(image,quantum,buffer,&count);
+    if (count <= 0)
+      {
+        count=0;
+        if (errno != EINTR)
+          break;
+      }
+  }
+  return(i < (MagickOffsetType) length ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D u p l i c a t e s B l o b                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DuplicateBlob() duplicates a blob descriptor.
+%
+%  The format of the DuplicateBlob method is:
+%
+%      void DuplicateBlob(Image *image,const Image *duplicate)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o duplicate: the duplicate image.
+%
+*/
+MagickExport void DuplicateBlob(Image *image,const Image *duplicate)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(duplicate != (Image *) NULL);
+  assert(duplicate->signature == MagickSignature);
+  DestroyBlob(image);
+  image->blob=ReferenceBlob(duplicate->blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  E O F B l o b                                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EOFBlob() returns a non-zero value when EOF has been detected reading from
+%  a blob or file.
+%
+%  The format of the EOFBlob method is:
+%
+%      int EOFBlob(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport int EOFBlob(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    case StandardStream:
+    case PipeStream:
+    {
+      image->blob->eof=feof(image->blob->file) != 0 ? MagickTrue : MagickFalse;
+      break;
+    }
+    case ZipStream:
+    {
+      image->blob->eof=MagickFalse;
+      break;
+    }
+    case BZipStream:
+    {
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+      int
+        status;
+
+      status=0;
+      (void) BZ2_bzerror((BZFILE *) image->blob->file,&status);
+      image->blob->eof=status == BZ_UNEXPECTED_EOF ? MagickTrue : MagickFalse;
+#endif
+      break;
+    }
+    case FifoStream:
+    {
+      image->blob->eof=MagickFalse;
+      break;
+    }
+    case BlobStream:
+      break;
+  }
+  return((int) image->blob->eof);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   F i l e T o B l o b                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FileToBlob() returns the contents of a file as a buffer terminated with
+%  the '\0' character.  The length of the buffer (not including the extra
+%  terminating '\0' character) is returned via the 'length' parameter.  Free
+%  the buffer with RelinquishMagickMemory().
+%
+%  The format of the FileToBlob method is:
+%
+%      unsigned char *FileToBlob(const char *filename,const size_t extent,
+%        size_t *length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o blob:  FileToBlob() returns the contents of a file as a blob.  If
+%      an error occurs NULL is returned.
+%
+%    o filename: the filename.
+%
+%    o extent:  The maximum length of the blob.
+%
+%    o length: On return, this reflects the actual length of the blob.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned char *FileToBlob(const char *filename,const size_t extent,
+  size_t *length,ExceptionInfo *exception)
+{
+  int
+    file;
+
+  MagickOffsetType
+    offset;
+
+  register size_t
+    i;
+
+  ssize_t
+    count;
+
+  unsigned char
+    *blob;
+
+  void
+    *map;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  *length=0;
+  file=fileno(stdin);
+  if (LocaleCompare(filename,"-") != 0)
+    file=open(filename,O_RDONLY | O_BINARY);
+  if (file == -1)
+    {
+      ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
+      return((unsigned char *) NULL);
+    }
+  offset=(MagickOffsetType) lseek(file,0,SEEK_END);
+  count=0;
+  if ((offset < 0) || (offset != (MagickOffsetType) ((ssize_t) offset)))
+    {
+      size_t
+        quantum;
+
+      struct stat
+        file_info;
+
+      /*
+        Stream is not seekable.
+      */
+      quantum=(size_t) MagickMaxBufferExtent;
+      if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
+        quantum=(size_t) MagickMin((MagickSizeType) file_info.st_size,
+          MagickMaxBufferExtent);
+      blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
+      for (i=0; blob != (unsigned char *) NULL; i+=count)
+      {
+        count=(ssize_t) read(file,blob+i,quantum);
+        if (count <= 0)
+          {
+            count=0;
+            if (errno != EINTR)
+              break;
+          }
+        if (~(1UL*i) < (quantum+1))
+          {
+            blob=(unsigned char *) RelinquishMagickMemory(blob);
+            break;
+          }
+        blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
+          sizeof(*blob));
+        if ((size_t) (i+count) >= extent)
+          break;
+      }
+      if (LocaleCompare(filename,"-") != 0)
+        file=close(file);
+      if (blob == (unsigned char *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
+          return((unsigned char *) NULL);
+        }
+      if (file == -1)
+        {
+          blob=(unsigned char *) RelinquishMagickMemory(blob);
+          ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
+          return((unsigned char *) NULL);
+        }
+      *length=(size_t) MagickMin(i+count,extent);
+      blob[*length]='\0';
+      return(blob);
+    }
+  *length=(size_t) MagickMin((MagickSizeType) offset,extent);
+  blob=(unsigned char *) NULL;
+  if (~(*length) >= (MaxTextExtent-1))
+    blob=(unsigned char *) AcquireQuantumMemory(*length+MaxTextExtent,
+      sizeof(*blob));
+  if (blob == (unsigned char *) NULL)
+    {
+      file=close(file);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
+      return((unsigned char *) NULL);
+    }
+  map=MapBlob(file,ReadMode,0,*length);
+  if (map != (unsigned char *) NULL)
+    {
+      (void) memcpy(blob,map,*length);
+      (void) UnmapBlob(map,*length);
+    }
+  else
+    {
+      (void) lseek(file,0,SEEK_SET);
+      for (i=0; i < *length; i+=count)
+      {
+        count=(ssize_t) read(file,blob+i,(size_t) MagickMin(*length-i,
+          (MagickSizeType) SSIZE_MAX));
+        if (count <= 0)
+          {
+            count=0;
+            if (errno != EINTR)
+              break;
+          }
+      }
+      if (i < *length)
+        {
+          file=close(file)-1;
+          blob=(unsigned char *) RelinquishMagickMemory(blob);
+          ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
+          return((unsigned char *) NULL);
+        }
+    }
+  blob[*length]='\0';
+  if (LocaleCompare(filename,"-") != 0)
+    file=close(file);
+  if (file == -1)
+    {
+      blob=(unsigned char *) RelinquishMagickMemory(blob);
+      ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
+    }
+  return(blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F i l e T o I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FileToImage() write the contents of a file to an image.
+%
+%  The format of the FileToImage method is:
+%
+%      MagickBooleanType FileToImage(Image *,const char *filename)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o filename: the filename.
+%
+*/
+
+static inline ssize_t WriteBlobStream(Image *image,const size_t length,
+  const unsigned char *data)
+{
+  MagickSizeType
+    extent;
+
+  register unsigned char
+    *q;
+
+  assert(image->blob != (BlobInfo *) NULL);
+  if (image->blob->type != BlobStream)
+    return(WriteBlob(image,length,data));
+  assert(image->blob->type != UndefinedStream);
+  assert(data != (void *) NULL);
+  extent=(MagickSizeType) (image->blob->offset+(MagickOffsetType) length);
+  if (extent >= image->blob->extent)
+    {
+      image->blob->quantum<<=1;
+      extent=image->blob->extent+image->blob->quantum+length;
+      if (SetBlobExtent(image,extent) == MagickFalse)
+        return(0);
+    }
+  q=image->blob->data+image->blob->offset;
+  (void) memcpy(q,data,length);
+  image->blob->offset+=length;
+  if (image->blob->offset >= (MagickOffsetType) image->blob->length)
+    image->blob->length=(size_t) image->blob->offset;
+  return((ssize_t) length);
+}
+
+MagickExport MagickBooleanType FileToImage(Image *image,const char *filename)
+{
+  int
+    file;
+
+  size_t
+    length,
+    quantum;
+
+  ssize_t
+    count;
+
+  struct stat
+    file_info;
+
+  unsigned char
+    *blob;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  file=open(filename,O_RDONLY | O_BINARY);
+  if (file == -1)
+    {
+      ThrowFileException(&image->exception,BlobError,"UnableToOpenBlob",
+        filename);
+      return(MagickFalse);
+    }
+  quantum=(size_t) MagickMaxBufferExtent;
+  if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
+    quantum=(size_t) MagickMin(file_info.st_size,MagickMaxBufferExtent);
+  blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
+  if (blob == (unsigned char *) NULL)
+    {
+      ThrowFileException(&image->exception,ResourceLimitError,
+        "MemoryAllocationFailed",filename);
+      return(MagickFalse);
+    }
+  for ( ; ; )
+  {
+    count=(ssize_t) read(file,blob,quantum);
+    if (count <= 0)
+      {
+        count=0;
+        if (errno != EINTR)
+          break;
+      }
+    length=(size_t) count;
+    count=WriteBlobStream(image,length,blob);
+    if (count != (ssize_t) length)
+      {
+        ThrowFileException(&image->exception,BlobError,"UnableToWriteBlob",
+          filename);
+        break;
+      }
+  }
+  file=close(file);
+  if (file == -1)
+    ThrowFileException(&image->exception,BlobError,"UnableToWriteBlob",
+      filename);
+  blob=(unsigned char *) RelinquishMagickMemory(blob);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t B l o b E r r o r                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobError() returns MagickTrue if the blob associated with the specified
+%  image encountered an error.
+%
+%  The format of the GetBlobError method is:
+%
+%       MagickBooleanType GetBlobError(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType GetBlobError(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(image->blob->status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t B l o b F i l e H a n d l e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobFileHandle() returns the file handle associated with the image blob.
+%
+%  The format of the GetBlobFile method is:
+%
+%      FILE *GetBlobFileHandle(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport FILE *GetBlobFileHandle(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  return(image->blob->file);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t B l o b I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobInfo() initializes the BlobInfo structure.
+%
+%  The format of the GetBlobInfo method is:
+%
+%      void GetBlobInfo(BlobInfo *blob_info)
+%
+%  A description of each parameter follows:
+%
+%    o blob_info: Specifies a pointer to a BlobInfo structure.
+%
+*/
+MagickExport void GetBlobInfo(BlobInfo *blob_info)
+{
+  assert(blob_info != (BlobInfo *) NULL);
+  (void) ResetMagickMemory(blob_info,0,sizeof(*blob_info));
+  blob_info->type=UndefinedStream;
+  blob_info->quantum=(size_t) MagickMaxBlobExtent;
+  blob_info->properties.st_mtime=time((time_t *) NULL);
+  blob_info->properties.st_ctime=time((time_t *) NULL);
+  blob_info->debug=IsEventLogging();
+  blob_info->reference_count=1;
+  blob_info->semaphore=AllocateSemaphoreInfo();
+  blob_info->signature=MagickSignature;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t B l o b P r o p e r t i e s                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobProperties() returns information about an image blob.
+%
+%  The format of the GetBlobProperties method is:
+%
+%      const struct stat *GetBlobProperties(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const struct stat *GetBlobProperties(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(&image->blob->properties);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  G e t B l o b S i z e                                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobSize() returns the current length of the image file or blob; zero is
+%  returned if the size cannot be determined.
+%
+%  The format of the GetBlobSize method is:
+%
+%      MagickSizeType GetBlobSize(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickSizeType GetBlobSize(const Image *image)
+{
+  MagickSizeType
+    extent;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  extent=0;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+    {
+      extent=image->blob->size;
+      break;
+    }
+    case FileStream:
+    {
+      if (fstat(fileno(image->blob->file),&image->blob->properties) == 0)
+        extent=(MagickSizeType) image->blob->properties.st_size;
+      break;
+    }
+    case StandardStream:
+    case PipeStream:
+    {
+      extent=image->blob->size;
+      break;
+    }
+    case ZipStream:
+    case BZipStream:
+    {
+      MagickBooleanType
+        status;
+
+      status=GetPathAttributes(image->filename,&image->blob->properties);
+      if (status != MagickFalse)
+        extent=(MagickSizeType) image->blob->properties.st_size;
+      break;
+    }
+    case FifoStream:
+      break;
+    case BlobStream:
+    {
+      extent=(MagickSizeType) image->blob->length;
+      break;
+    }
+  }
+  return(extent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t B l o b S t r e a m D a t a                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobStreamData() returns the stream data for the image.
+%
+%  The format of the GetBlobStreamData method is:
+%
+%      unsigned char *GetBlobStreamData(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned char *GetBlobStreamData(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  return(image->blob->data);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t B l o b S t r e a m H a n d l e r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetBlobStreamHandler() returns the stream handler for the image.
+%
+%  The format of the GetBlobStreamHandler method is:
+%
+%      StreamHandler GetBlobStreamHandler(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport StreamHandler GetBlobStreamHandler(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(image->blob->stream);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I m a g e T o B l o b                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImageToBlob() implements direct to memory image formats.  It returns the
+%  image as a formatted blob and its length.  The magick member of the Image
+%  structure determines the format of the returned blob (GIF, JPEG, PNG,
+%  etc.).  This method is the equivalent of WriteImage(), but writes the
+%  formatted "file" to a memory buffer rather than to an actual file.
+%
+%  The format of the ImageToBlob method is:
+%
+%      unsigned char *ImageToBlob(const ImageInfo *image_info,Image *image,
+%        size_t *length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+%    o length: This pointer to a size_t integer sets the initial length of the
+%      blob.  On return, it reflects the actual length of the blob.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned char *ImageToBlob(const ImageInfo *image_info,
+  Image *image,size_t *length,ExceptionInfo *exception)
+{
+  const MagickInfo
+    *magick_info;
+
+  ImageInfo
+    *blob_info;
+
+  MagickBooleanType
+    status;
+
+  unsigned char
+    *blob;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  *length=0;
+  blob=(unsigned char *) NULL;
+  blob_info=CloneImageInfo(image_info);
+  blob_info->adjoin=MagickFalse;
+  (void) SetImageInfo(blob_info,1,exception);
+  if (*blob_info->magick != '\0')
+    (void) CopyMagickString(image->magick,blob_info->magick,MaxTextExtent);
+  magick_info=GetMagickInfo(image->magick,exception);
+  if (magick_info == (const MagickInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+        image->filename);
+      return(blob);
+    }
+  (void) CopyMagickString(blob_info->magick,image->magick,MaxTextExtent);
+  if (GetMagickBlobSupport(magick_info) != MagickFalse)
+    {
+      /*
+        Native blob support for this image format.
+      */
+      blob_info->length=0;
+      blob_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
+        sizeof(unsigned char));
+      if (blob_info->blob == (void *) NULL)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      else
+        {
+          (void) CloseBlob(image);
+          image->blob->exempt=MagickTrue;
+          *image->filename='\0';
+          status=WriteImage(blob_info,image);
+          if ((status == MagickFalse) || (image->blob->length == 0))
+            InheritException(exception,&image->exception);
+          else
+            {
+              *length=image->blob->length;
+              blob=DetachBlob(image->blob);
+              blob=(unsigned char *) ResizeQuantumMemory(blob,*length,
+                sizeof(*blob));
+            }
+        }
+    }
+  else
+    {
+      char
+        unique[MaxTextExtent];
+
+      int
+        file;
+
+      /*
+        Write file to disk in blob image format.
+      */
+      file=AcquireUniqueFileResource(unique);
+      if (file == -1)
+        {
+          ThrowFileException(exception,BlobError,"UnableToWriteBlob",
+            image_info->filename);
+        }
+      else
+        {
+          blob_info->file=fdopen(file,"wb");
+          if (blob_info->file != (FILE *) NULL)
+            {
+              (void) FormatLocaleString(image->filename,MaxTextExtent,"%s:%s",
+                image->magick,unique);
+              status=WriteImage(blob_info,image);
+              (void) fclose(blob_info->file);
+              if (status == MagickFalse)
+                InheritException(exception,&image->exception);
+              else
+                blob=FileToBlob(image->filename,~0UL,length,exception);
+            }
+          (void) RelinquishUniqueFileResource(unique);
+        }
+    }
+  blob_info=DestroyImageInfo(blob_info);
+  return(blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I m a g e T o F i l e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImageToFile() writes an image to a file.  It returns MagickFalse if an error
+%  occurs otherwise MagickTrue.
+%
+%  The format of the ImageToFile method is:
+%
+%       MagickBooleanType ImageToFile(Image *image,char *filename,
+%         ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o filename: Write the image to this file.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ImageToFile(Image *image,char *filename,
+  ExceptionInfo *exception)
+{
+  int
+    file;
+
+  register const unsigned char
+    *p;
+
+  register size_t
+    i;
+
+  size_t
+    length,
+    quantum;
+
+  ssize_t
+    count;
+
+  struct stat
+    file_info;
+
+  unsigned char
+    *buffer;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(filename != (const char *) NULL);
+  if (*filename == '\0')
+    file=AcquireUniqueFileResource(filename);
+  else
+    if (LocaleCompare(filename,"-") == 0)
+      file=fileno(stdout);
+    else
+      file=open(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
+  if (file == -1)
+    {
+      ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
+      return(MagickFalse);
+    }
+  quantum=(size_t) MagickMaxBufferExtent;
+  if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
+    quantum=(size_t) MagickMin((MagickSizeType) file_info.st_size,
+      MagickMaxBufferExtent);
+  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
+  if (buffer == (unsigned char *) NULL)
+    {
+      file=close(file)-1;
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationError","`%s'",filename);
+      return(MagickFalse);
+    }
+  length=0;
+  p=ReadBlobStream(image,quantum,buffer,&count);
+  for (i=0; count > 0; p=ReadBlobStream(image,quantum,buffer,&count))
+  {
+    length=(size_t) count;
+    for (i=0; i < length; i+=count)
+    {
+      count=write(file,p+i,(size_t) (length-i));
+      if (count <= 0)
+        {
+          count=0;
+          if (errno != EINTR)
+            break;
+        }
+    }
+    if (i < length)
+      break;
+  }
+  if (LocaleCompare(filename,"-") != 0)
+    file=close(file);
+  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+  if ((file == -1) || (i < length))
+    {
+      ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I m a g e s T o B l o b                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImagesToBlob() implements direct to memory image formats.  It returns the
+%  image sequence as a blob and its length.  The magick member of the ImageInfo
+%  structure determines the format of the returned blob (GIF, JPEG,  PNG, etc.)
+%
+%  Note, some image formats do not permit multiple images to the same image
+%  stream (e.g. JPEG).  in this instance, just the first image of the
+%  sequence is returned as a blob.
+%
+%  The format of the ImagesToBlob method is:
+%
+%      unsigned char *ImagesToBlob(const ImageInfo *image_info,Image *images,
+%        size_t *length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o images: the image list.
+%
+%    o length: This pointer to a size_t integer sets the initial length of the
+%      blob.  On return, it reflects the actual length of the blob.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport unsigned char *ImagesToBlob(const ImageInfo *image_info,
+  Image *images,size_t *length,ExceptionInfo *exception)
+{
+  const MagickInfo
+    *magick_info;
+
+  ImageInfo
+    *blob_info;
+
+  MagickBooleanType
+    status;
+
+  unsigned char
+    *blob;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  *length=0;
+  blob=(unsigned char *) NULL;
+  blob_info=CloneImageInfo(image_info);
+  (void) SetImageInfo(blob_info,(unsigned int) GetImageListLength(images),
+    exception);
+  if (*blob_info->magick != '\0')
+    (void) CopyMagickString(images->magick,blob_info->magick,MaxTextExtent);
+  if (blob_info->adjoin == MagickFalse)
+    {
+      blob_info=DestroyImageInfo(blob_info);
+      return(ImageToBlob(image_info,images,length,exception));
+    }
+  magick_info=GetMagickInfo(images->magick,exception);
+  if (magick_info == (const MagickInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+        images->filename);
+      return(blob);
+    }
+  (void) CopyMagickString(blob_info->magick,images->magick,MaxTextExtent);
+  if (GetMagickBlobSupport(magick_info) != MagickFalse)
+    {
+      /*
+        Native blob support for this images format.
+      */
+      blob_info->length=0;
+      blob_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
+        sizeof(unsigned char));
+      if (blob_info->blob == (void *) NULL)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      else
+        {
+          images->blob->exempt=MagickTrue;
+          *images->filename='\0';
+          status=WriteImages(blob_info,images,images->filename,exception);
+          if ((status == MagickFalse) || (images->blob->length == 0))
+            InheritException(exception,&images->exception);
+          else
+            {
+              *length=images->blob->length;
+              blob=DetachBlob(images->blob);
+              blob=(unsigned char *) ResizeQuantumMemory(blob,*length,
+                sizeof(*blob));
+            }
+        }
+    }
+  else
+    {
+      char
+        filename[MaxTextExtent],
+        unique[MaxTextExtent];
+
+      int
+        file;
+
+      /*
+        Write file to disk in blob images format.
+      */
+      file=AcquireUniqueFileResource(unique);
+      if (file == -1)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",
+            image_info->filename);
+        }
+      else
+        {
+          blob_info->file=fdopen(file,"wb");
+          if (blob_info->file != (FILE *) NULL)
+            {
+              (void) FormatLocaleString(filename,MaxTextExtent,"%s:%s",
+                images->magick,unique);
+              status=WriteImages(blob_info,images,filename,exception);
+              (void) fclose(blob_info->file);
+              if (status == MagickFalse)
+                InheritException(exception,&images->exception);
+              else
+                blob=FileToBlob(images->filename,~0UL,length,exception);
+            }
+          (void) RelinquishUniqueFileResource(unique);
+        }
+    }
+  blob_info=DestroyImageInfo(blob_info);
+  return(blob);
+}
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n j e c t I m a g e B l o b                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InjectImageBlob() injects the image with a copy of itself in the specified
+%  format (e.g. inject JPEG into a PDF image).
+%
+%  The format of the InjectImageBlob method is:
+%
+%      MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
+%        Image *image,Image *inject_image,const char *format,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info..
+%
+%    o image: the image.
+%
+%    o inject_image: inject into the image stream.
+%
+%    o format: the image format.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
+  Image *image,Image *inject_image,const char *format,ExceptionInfo *exception)
+{
+  char
+    filename[MaxTextExtent];
+
+  FILE
+    *unique_file;
+
+  Image
+    *byte_image;
+
+  ImageInfo
+    *write_info;
+
+  int
+    file;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    quantum;
+
+  ssize_t
+    count;
+
+  struct stat
+    file_info;
+
+  unsigned char
+    *buffer;
+
+  /*
+    Write inject image to a temporary file.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(inject_image != (Image *) NULL);
+  assert(inject_image->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  unique_file=(FILE *) NULL;
+  file=AcquireUniqueFileResource(filename);
+  if (file != -1)
+    unique_file=fdopen(file,"wb");
+  if ((file == -1) || (unique_file == (FILE *) NULL))
+    {
+      (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+      ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
+        image->filename);
+      return(MagickFalse);
+    }
+  byte_image=CloneImage(inject_image,0,0,MagickFalse,exception);
+  if (byte_image == (Image *) NULL)
+    {
+      (void) fclose(unique_file);
+      (void) RelinquishUniqueFileResource(filename);
+      return(MagickFalse);
+    }
+  (void) FormatLocaleString(byte_image->filename,MaxTextExtent,"%s:%s",format,
+    filename);
+  DestroyBlob(byte_image);
+  byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
+  write_info=CloneImageInfo(image_info);
+  SetImageInfoFile(write_info,unique_file);
+  status=WriteImage(write_info,byte_image);
+  write_info=DestroyImageInfo(write_info);
+  byte_image=DestroyImage(byte_image);
+  (void) fclose(unique_file);
+  if (status == MagickFalse)
+    {
+      (void) RelinquishUniqueFileResource(filename);
+      return(MagickFalse);
+    }
+  /*
+    Inject into image stream.
+  */
+  file=open(filename,O_RDONLY | O_BINARY);
+  if (file == -1)
+    {
+      (void) RelinquishUniqueFileResource(filename);
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        image_info->filename);
+      return(MagickFalse);
+    }
+  quantum=(size_t) MagickMaxBufferExtent;
+  if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
+    quantum=(size_t) MagickMin(file_info.st_size,MagickMaxBufferExtent);
+  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
+  if (buffer == (unsigned char *) NULL)
+    {
+      (void) RelinquishUniqueFileResource(filename);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  for (i=0; ; i+=count)
+  {
+    count=(ssize_t) read(file,buffer,quantum);
+    if (count <= 0)
+      {
+        count=0;
+        if (errno != EINTR)
+          break;
+      }
+    status=WriteBlobStream(image,(size_t) count,buffer) == count ? MagickTrue :
+      MagickFalse;
+  }
+  file=close(file);
+  if (file == -1)
+    ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",filename);
+  (void) RelinquishUniqueFileResource(filename);
+  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s B l o b E x e m p t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsBlobExempt() returns true if the blob is exempt.
+%
+%  The format of the IsBlobExempt method is:
+%
+%       MagickBooleanType IsBlobExempt(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType IsBlobExempt(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(image->blob->exempt);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s B l o b S e e k a b l e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsBlobSeekable() returns true if the blob is seekable.
+%
+%  The format of the IsBlobSeekable method is:
+%
+%       MagickBooleanType IsBlobSeekable(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType IsBlobSeekable(const Image *image)
+{
+  MagickBooleanType
+    seekable;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  seekable=(image->blob->type == FileStream) ||
+    (image->blob->type == BlobStream) ? MagickTrue : MagickFalse;
+  return(seekable);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s B l o b T e m p o r a r y                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsBlobTemporary() returns true if the blob is temporary.
+%
+%  The format of the IsBlobTemporary method is:
+%
+%       MagickBooleanType IsBlobTemporary(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType IsBlobTemporary(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(image->blob->temporary);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  M a p B l o b                                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MapBlob() creates a mapping from a file to a binary large object.
+%
+%  The format of the MapBlob method is:
+%
+%      unsigned char *MapBlob(int file,const MapMode mode,
+%        const MagickOffsetType offset,const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o file: map this file descriptor.
+%
+%    o mode: ReadMode, WriteMode, or IOMode.
+%
+%    o offset: starting at this offset within the file.
+%
+%    o length: the length of the mapping is returned in this pointer.
+%
+*/
+MagickExport unsigned char *MapBlob(int file,const MapMode mode,
+  const MagickOffsetType offset,const size_t length)
+{
+#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
+  int
+    flags,
+    protection;
+
+  unsigned char
+    *map;
+
+  /*
+    Map file.
+  */
+  flags=0;
+  if (file == -1)
+#if defined(MAP_ANONYMOUS)
+    flags|=MAP_ANONYMOUS;
+#else
+    return((unsigned char *) NULL);
+#endif
+  switch (mode)
+  {
+    case ReadMode:
+    default:
+    {
+      protection=PROT_READ;
+      flags|=MAP_PRIVATE;
+      map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
+        (off_t) offset);
+      break;
+    }
+    case WriteMode:
+    {
+      protection=PROT_WRITE;
+      flags|=MAP_SHARED;
+      map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
+        (off_t) offset);
+#if defined(MAGICKCORE_HAVE_POSIX_MADVISE)
+      (void) posix_madvise(map,length,POSIX_MADV_SEQUENTIAL |
+        POSIX_MADV_WILLNEED);
+#endif
+      break;
+    }
+    case IOMode:
+    {
+      protection=PROT_READ | PROT_WRITE;
+      flags|=MAP_SHARED;
+      map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
+        (off_t) offset);
+      break;
+    }
+  }
+  if (map == (unsigned char *) MAP_FAILED)
+    return((unsigned char *) NULL);
+  return(map);
+#else
+  (void) file;
+  (void) mode;
+  (void) offset;
+  (void) length;
+  return((unsigned char *) NULL);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  M S B O r d e r L o n g                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MSBOrderLong() converts a least-significant byte first buffer of integers to
+%  most-significant byte first.
+%
+%  The format of the MSBOrderLong method is:
+%
+%      void MSBOrderLong(unsigned char *buffer,const size_t length)
+%
+%  A description of each parameter follows.
+%
+%   o  buffer:  Specifies a pointer to a buffer of integers.
+%
+%   o  length:  Specifies the length of the buffer.
+%
+*/
+MagickExport void MSBOrderLong(unsigned char *buffer,const size_t length)
+{
+  int
+    c;
+
+  register unsigned char
+    *p,
+    *q;
+
+  assert(buffer != (unsigned char *) NULL);
+  q=buffer+length;
+  while (buffer < q)
+  {
+    p=buffer+3;
+    c=(int) (*p);
+    *p=(*buffer);
+    *buffer++=(unsigned char) c;
+    p=buffer+1;
+    c=(int) (*p);
+    *p=(*buffer);
+    *buffer++=(unsigned char) c;
+    buffer+=2;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  M S B O r d e r S h o r t                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MSBOrderShort() converts a least-significant byte first buffer of integers
+%  to most-significant byte first.
+%
+%  The format of the MSBOrderShort method is:
+%
+%      void MSBOrderShort(unsigned char *p,const size_t length)
+%
+%  A description of each parameter follows.
+%
+%   o  p:  Specifies a pointer to a buffer of integers.
+%
+%   o  length:  Specifies the length of the buffer.
+%
+*/
+MagickExport void MSBOrderShort(unsigned char *p,const size_t length)
+{
+  int
+    c;
+
+  register unsigned char
+    *q;
+
+  assert(p != (unsigned char *) NULL);
+  q=p+length;
+  while (p < q)
+  {
+    c=(int) (*p);
+    *p=(*(p+1));
+    p++;
+    *p++=(unsigned char) c;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   O p e n B l o b                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenBlob() opens a file associated with the image.  A file name of '-' sets
+%  the file to stdin for type 'r' and stdout for type 'w'.  If the filename
+%  suffix is '.gz' or '.Z', the image is decompressed for type 'r' and
+%  compressed for type 'w'.  If the filename prefix is '|', it is piped to or
+%  from a system command.
+%
+%  The format of the OpenBlob method is:
+%
+%       MagickBooleanType OpenBlob(const ImageInfo *image_info,Image *image,
+%        const BlobMode mode,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+%    o mode: the mode for opening the file.
+%
+*/
+MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
+  Image *image,const BlobMode mode,ExceptionInfo *exception)
+{
+  char
+    extension[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  const char
+    *type;
+
+  MagickBooleanType
+    status;
+
+  PolicyRights
+    rights;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image_info->blob != (void *) NULL)
+    {
+      if (image_info->stream != (StreamHandler) NULL)
+        image->blob->stream=(StreamHandler) image_info->stream;
+      AttachBlob(image->blob,image_info->blob,image_info->length);
+      return(MagickTrue);
+    }
+  (void) DetachBlob(image->blob);
+  switch (mode)
+  {
+    default: type="r"; break;
+    case ReadBlobMode: type="r"; break;
+    case ReadBinaryBlobMode: type="rb"; break;
+    case WriteBlobMode: type="w"; break;
+    case WriteBinaryBlobMode: type="w+b"; break;
+    case AppendBlobMode: type="a"; break;
+    case AppendBinaryBlobMode: type="a+b"; break;
+  }
+  if (*type != 'r')
+    image->blob->synchronize=image_info->synchronize;
+  if (image_info->stream != (StreamHandler) NULL)
+    {
+      image->blob->stream=(StreamHandler) image_info->stream;
+      if (*type == 'w')
+        {
+          image->blob->type=FifoStream;
+          return(MagickTrue);
+        }
+    }
+  /*
+    Open image file.
+  */
+  *filename='\0';
+  (void) CopyMagickString(filename,image->filename,MaxTextExtent);
+  rights=ReadPolicyRights;
+  if (*type == 'w')
+    rights=WritePolicyRights;
+  if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",filename);
+      return(MagickFalse);
+    }
+  if ((LocaleCompare(filename,"-") == 0) ||
+      ((*filename == '\0') && (image_info->file == (FILE *) NULL)))
+    {
+      image->blob->file=(*type == 'r') ? stdin : stdout;
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
+      if (strchr(type,'b') != (char *) NULL)
+        setmode(_fileno(image->blob->file),_O_BINARY);
+#endif
+      image->blob->type=StandardStream;
+      image->blob->exempt=MagickTrue;
+      return(MagickTrue);
+    }
+  if (LocaleNCompare(filename,"fd:",3) == 0)
+    {
+      char
+        mode[MaxTextExtent];
+
+      *mode=(*type);
+      mode[1]='\0';
+      image->blob->file=fdopen(StringToLong(filename+3),mode);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
+      if (strchr(type,'b') != (char *) NULL)
+        setmode(_fileno(image->blob->file),_O_BINARY);
+#endif
+      image->blob->type=StandardStream;
+      image->blob->exempt=MagickTrue;
+      return(MagickTrue);
+    }
+#if defined(MAGICKCORE_HAVE_POPEN)
+  if (*filename == '|')
+    {
+      char
+        mode[MaxTextExtent];
+
+      /*
+        Pipe image to or from a system command.
+      */
+#if defined(SIGPIPE)
+      if (*type == 'w')
+        (void) signal(SIGPIPE,SIG_IGN);
+#endif
+      *mode=(*type);
+      mode[1]='\0';
+      image->blob->file=(FILE *) popen(filename+1,mode);
+      if (image->blob->file == (FILE *) NULL)
+        {
+          ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
+          return(MagickFalse);
+        }
+      image->blob->type=PipeStream;
+      image->blob->exempt=MagickTrue;
+      return(MagickTrue);
+    }
+#endif
+  status=GetPathAttributes(filename,&image->blob->properties);
+#if defined(S_ISFIFO)
+  if ((status == MagickTrue) && S_ISFIFO(image->blob->properties.st_mode))
+    {
+      image->blob->file=(FILE *) OpenMagickStream(filename,type);
+      if (image->blob->file == (FILE *) NULL)
+        {
+          ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
+          return(MagickFalse);
+        }
+      image->blob->type=FileStream;
+      image->blob->exempt=MagickTrue;
+      return(MagickTrue);
+    }
+#endif
+  GetPathComponent(image->filename,ExtensionPath,extension);
+  if (*type == 'w')
+    {
+      (void) CopyMagickString(filename,image->filename,MaxTextExtent);
+      if ((image_info->adjoin == MagickFalse) ||
+          (strchr(filename,'%') != (char *) NULL))
+        {
+          /*
+            Form filename for multi-part images.
+          */
+          (void) InterpretImageFilename(image_info,image,image->filename,(int)
+            image->scene,filename);
+          if ((LocaleCompare(filename,image->filename) == 0) &&
+              ((GetPreviousImageInList(image) != (Image *) NULL) ||
+               (GetNextImageInList(image) != (Image *) NULL)))
+            {
+              char
+                path[MaxTextExtent];
+
+              GetPathComponent(image->filename,RootPath,path);
+              if (*extension == '\0')
+                (void) FormatLocaleString(filename,MaxTextExtent,"%s-%.20g",
+                  path,(double) image->scene);
+              else
+                (void) FormatLocaleString(filename,MaxTextExtent,"%s-%.20g.%s",
+                  path,(double) image->scene,extension);
+            }
+          (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+#if defined(macintosh)
+          SetApplicationType(filename,image_info->magick,'8BIM');
+#endif
+        }
+    }
+  if (image_info->file != (FILE *) NULL)
+    {
+      image->blob->file=image_info->file;
+      image->blob->type=FileStream;
+      image->blob->exempt=MagickTrue;
+    }
+  else
+    if (*type == 'r')
+      {
+        image->blob->file=(FILE *) OpenMagickStream(filename,type);
+        if (image->blob->file != (FILE *) NULL)
+          {
+            size_t
+              count;
+
+            unsigned char
+              magick[3];
+
+            image->blob->type=FileStream;
+#if defined(MAGICKCORE_HAVE_SETVBUF)
+            (void) setvbuf(image->blob->file,(char *) NULL,(int) _IOFBF,16384);
+#endif
+            (void) ResetMagickMemory(magick,0,sizeof(magick));
+            count=fread(magick,1,sizeof(magick),image->blob->file);
+            (void) rewind(image->blob->file);
+            (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+               "  read %.20g magic header bytes",(double) count);
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+            if (((int) magick[0] == 0x1F) && ((int) magick[1] == 0x8B) &&
+                ((int) magick[2] == 0x08))
+              {
+                (void) fclose(image->blob->file);
+                image->blob->file=(FILE *) gzopen(filename,type);
+                if (image->blob->file != (FILE *) NULL)
+                  image->blob->type=ZipStream;
+               }
+#endif
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+            if (strncmp((char *) magick,"BZh",3) == 0)
+              {
+                (void) fclose(image->blob->file);
+                image->blob->file=(FILE *) BZ2_bzopen(filename,type);
+                if (image->blob->file != (FILE *) NULL)
+                  image->blob->type=BZipStream;
+              }
+#endif
+            if (image->blob->type == FileStream)
+              {
+                const MagickInfo
+                  *magick_info;
+
+                ExceptionInfo
+                  *sans_exception;
+
+                struct stat
+                  *properties;
+
+                sans_exception=AcquireExceptionInfo();
+                magick_info=GetMagickInfo(image_info->magick,sans_exception);
+                sans_exception=DestroyExceptionInfo(sans_exception);
+                properties=(&image->blob->properties);
+                if ((magick_info != (const MagickInfo *) NULL) &&
+                    (GetMagickBlobSupport(magick_info) != MagickFalse) &&
+                    (properties->st_size <= MagickMaxBufferExtent))
+                  {
+                    size_t
+                      length;
+
+                    void
+                      *blob;
+
+                    length=(size_t) properties->st_size;
+                    blob=MapBlob(fileno(image->blob->file),ReadMode,0,length);
+                    if (blob != (void *) NULL)
+                      {
+                        /*
+                          Format supports blobs-- use memory-mapped I/O.
+                        */
+                        if (image_info->file != (FILE *) NULL)
+                          image->blob->exempt=MagickFalse;
+                        else
+                          {
+                            (void) fclose(image->blob->file);
+                            image->blob->file=(FILE *) NULL;
+                          }
+                        AttachBlob(image->blob,blob,length);
+                        image->blob->mapped=MagickTrue;
+                      }
+                  }
+              }
+          }
+        }
+      else
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+        if ((LocaleCompare(extension,"Z") == 0) ||
+            (LocaleCompare(extension,"gz") == 0) ||
+            (LocaleCompare(extension,"wmz") == 0) ||
+            (LocaleCompare(extension,"svgz") == 0))
+          {
+            if (mode == WriteBinaryBlobMode)
+              type="wb";
+            image->blob->file=(FILE *) gzopen(filename,type);
+            if (image->blob->file != (FILE *) NULL)
+              image->blob->type=ZipStream;
+          }
+        else
+#endif
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+          if (LocaleCompare(extension,".bz2") == 0)
+            {
+              image->blob->file=(FILE *) BZ2_bzopen(filename,type);
+              if (image->blob->file != (FILE *) NULL)
+                image->blob->type=BZipStream;
+            }
+          else
+#endif
+            {
+              image->blob->file=(FILE *) OpenMagickStream(filename,type);
+              if (image->blob->file != (FILE *) NULL)
+                {
+                  image->blob->type=FileStream;
+#if defined(MAGICKCORE_HAVE_SETVBUF)
+                  (void) setvbuf(image->blob->file,(char *) NULL,(int) _IOFBF,
+                    16384);
+#endif
+                }
+       }
+  image->blob->status=MagickFalse;
+  if (image->blob->type != UndefinedStream)
+    image->blob->size=GetBlobSize(image);
+  else
+    {
+      ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P i n g B l o b                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PingBlob() returns all the attributes of an image or image sequence except
+%  for the pixels.  It is much faster and consumes far less memory than
+%  BlobToImage().  On failure, a NULL image is returned and exception
+%  describes the reason for the failure.
+%
+%  The format of the PingBlob method is:
+%
+%      Image *PingBlob(const ImageInfo *image_info,const void *blob,
+%        const size_t length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o blob: the address of a character stream in one of the image formats
+%      understood by ImageMagick.
+%
+%    o length: This size_t integer reflects the length in bytes of the blob.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static size_t PingStream(const Image *magick_unused(image),
+  const void *magick_unused(pixels),const size_t columns)
+{
+  return(columns);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport Image *PingBlob(const ImageInfo *image_info,const void *blob,
+  const size_t length,ExceptionInfo *exception)
+{
+  Image
+    *image;
+
+  ImageInfo
+    *ping_info;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((blob == (const void *) NULL) || (length == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
+        "UnrecognizedImageFormat","`%s'",image_info->magick);
+      return((Image *) NULL);
+    }
+  ping_info=CloneImageInfo(image_info);
+  ping_info->blob=(void *) AcquireQuantumMemory(length,sizeof(unsigned char));
+  if (ping_info->blob == (const void *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitFatalError,"MemoryAllocationFailed","`%s'","");
+      return((Image *) NULL);
+    }
+  (void) memcpy(ping_info->blob,blob,length);
+  ping_info->length=length;
+  ping_info->ping=MagickTrue;
+  image=ReadStream(ping_info,&PingStream,exception);
+  ping_info->blob=(void *) RelinquishMagickMemory(ping_info->blob);
+  ping_info=DestroyImageInfo(ping_info);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b                                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlob() reads data from the blob or image file and returns it.  It
+%  returns the number of bytes read.
+%
+%  The format of the ReadBlob method is:
+%
+%      ssize_t ReadBlob(Image *image,const size_t length,unsigned char *data)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o length:  Specifies an integer representing the number of bytes to read
+%      from the file.
+%
+%    o data:  Specifies an area to place the information requested from the
+%      file.
+%
+*/
+MagickExport ssize_t ReadBlob(Image *image,const size_t length,
+  unsigned char *data)
+{
+  int
+    c;
+
+  register unsigned char
+    *q;
+
+  ssize_t
+    count;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  if (length == 0)
+    return(0);
+  assert(data != (void *) NULL);
+  count=0;
+  q=data;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    case StandardStream:
+    case PipeStream:
+    {
+      switch (length)
+      {
+        default:
+        {
+          count=(ssize_t) fread(q,1,length,image->blob->file);
+          break;
+        }
+        case 2:
+        {
+          c=getc(image->blob->file);
+          if (c == EOF)
+            break;
+          *q++=(unsigned char) c;
+          count++;
+        }
+        case 1:
+        {
+          c=getc(image->blob->file);
+          if (c == EOF)
+            break;
+          *q++=(unsigned char) c;
+          count++;
+        }
+        case 0:
+          break;
+      }
+      break;
+    }
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      switch (length)
+      {
+        default:
+        {
+          count=(ssize_t) gzread(image->blob->file,q,(unsigned int) length);
+          break;
+        }
+        case 2:
+        {
+          c=gzgetc(image->blob->file);
+          if (c == EOF)
+            break;
+          *q++=(unsigned char) c;
+          count++;
+        }
+        case 1:
+        {
+          c=gzgetc(image->blob->file);
+          if (c == EOF)
+            break;
+          *q++=(unsigned char) c;
+          count++;
+        }
+        case 0:
+          break;
+      }
+#endif
+      break;
+    }
+    case BZipStream:
+    {
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+      count=(ssize_t) BZ2_bzread((BZFILE *) image->blob->file,q,(int) length);
+#endif
+      break;
+    }
+    case FifoStream:
+      break;
+    case BlobStream:
+    {
+      register const unsigned char
+        *p;
+
+      if (image->blob->offset >= (MagickOffsetType) image->blob->length)
+        {
+          image->blob->eof=MagickTrue;
+          break;
+        }
+      p=image->blob->data+image->blob->offset;
+      count=(ssize_t) MagickMin(length,image->blob->length-image->blob->offset);
+      image->blob->offset+=count;
+      if (count != (ssize_t) length)
+        image->blob->eof=MagickTrue;
+      (void) memcpy(q,p,(size_t) count);
+      break;
+    }
+  }
+  return(count);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b B y t e                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobByte() reads a single byte from the image file and returns it.
+%
+%  The format of the ReadBlobByte method is:
+%
+%      int ReadBlobByte(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport int ReadBlobByte(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[1];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  p=ReadBlobStream(image,1,buffer,&count);
+  if (count != 1)
+    return(EOF);
+  return((int) (*p));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b D o u b l e                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the ReadBlobDouble method is:
+%
+%      double ReadBlobDouble(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport double ReadBlobDouble(Image *image)
+{
+  union
+  {
+    MagickSizeType
+      unsigned_value;
+
+    double
+      double_value;
+  } quantum;
+
+  quantum.double_value=0.0;
+  quantum.unsigned_value=ReadBlobLongLong(image);
+  return(quantum.double_value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b F l o a t                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the ReadBlobFloat method is:
+%
+%      float ReadBlobFloat(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport float ReadBlobFloat(Image *image)
+{
+  union
+  {
+    unsigned int
+      unsigned_value;
+
+    float
+      float_value;
+  } quantum;
+
+  quantum.float_value=0.0;
+  quantum.unsigned_value=ReadBlobLong(image);
+  return(quantum.float_value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b L o n g                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobLong() reads a ssize_t value as a 32-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the ReadBlobLong method is:
+%
+%      unsigned int ReadBlobLong(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned int ReadBlobLong(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[4];
+
+  unsigned int
+    value;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,4,buffer,&count);
+  if (count != 4)
+    return(0UL);
+  if (image->endian == LSBEndian)
+    {
+      value=(unsigned int) (*p++);
+      value|=((unsigned int) (*p++)) << 8;
+      value|=((unsigned int) (*p++)) << 16;
+      value|=((unsigned int) (*p++)) << 24;
+      return(value);
+    }
+  value=((unsigned int) (*p++)) << 24;
+  value|=((unsigned int) (*p++)) << 16;
+  value|=((unsigned int) (*p++)) << 8;
+  value|=((unsigned int) (*p++));
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b L o n g L o n g                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobLongLong() reads a long long value as a 64-bit quantity in the
+%  byte-order specified by the endian member of the image structure.
+%
+%  The format of the ReadBlobLongLong method is:
+%
+%      MagickSizeType ReadBlobLongLong(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickSizeType ReadBlobLongLong(Image *image)
+{
+  MagickSizeType
+    value;
+
+  register const unsigned char
+    *p;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[8];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,8,buffer,&count);
+  if (count != 8)
+    return(MagickULLConstant(0));
+  if (image->endian == LSBEndian)
+    {
+      value=(MagickSizeType) (*p++);
+      value|=((MagickSizeType) (*p++)) << 8;
+      value|=((MagickSizeType) (*p++)) << 16;
+      value|=((MagickSizeType) (*p++)) << 24;
+      value|=((MagickSizeType) (*p++)) << 32;
+      value|=((MagickSizeType) (*p++)) << 40;
+      value|=((MagickSizeType) (*p++)) << 48;
+      value|=((MagickSizeType) (*p++)) << 56;
+      return(value & MagickULLConstant(0xffffffffffffffff));
+    }
+  value=((MagickSizeType) (*p++)) << 56;
+  value|=((MagickSizeType) (*p++)) << 48;
+  value|=((MagickSizeType) (*p++)) << 40;
+  value|=((MagickSizeType) (*p++)) << 32;
+  value|=((MagickSizeType) (*p++)) << 24;
+  value|=((MagickSizeType) (*p++)) << 16;
+  value|=((MagickSizeType) (*p++)) << 8;
+  value|=((MagickSizeType) (*p++));
+  return(value & MagickULLConstant(0xffffffffffffffff));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b S h o r t                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the ReadBlobShort method is:
+%
+%      unsigned short ReadBlobShort(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned short ReadBlobShort(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned int
+    value;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[2];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,2,buffer,&count);
+  if (count != 2)
+    return((unsigned short) 0U);
+  if (image->endian == LSBEndian)
+    {
+      value=(unsigned int) (*p++);
+      value|=((unsigned int) (*p++)) << 8;
+      return((unsigned short) (value & 0xffff));
+    }
+  value=(unsigned int) ((*p++) << 8);
+  value|=(unsigned int) (*p++);
+  return((unsigned short) (value & 0xffff));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b L S B L o n g                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobLSBLong() reads a ssize_t value as a 32-bit quantity in
+%  least-significant byte first order.
+%
+%  The format of the ReadBlobLSBLong method is:
+%
+%      unsigned int ReadBlobLSBLong(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned int ReadBlobLSBLong(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned int
+    value;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[4];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,4,buffer,&count);
+  if (count != 4)
+    return(0U);
+  value=(unsigned int) (*p++);
+  value|=((unsigned int) (*p++)) << 8;
+  value|=((unsigned int) (*p++)) << 16;
+  value|=((unsigned int) (*p++)) << 24;
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b L S B S h o r t                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobLSBShort() reads a short value as a 16-bit quantity in
+%  least-significant byte first order.
+%
+%  The format of the ReadBlobLSBShort method is:
+%
+%      unsigned short ReadBlobLSBShort(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned short ReadBlobLSBShort(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned int
+    value;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[2];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,2,buffer,&count);
+  if (count != 2)
+    return((unsigned short) 0U);
+  value=(unsigned int) (*p++);
+  value|=((unsigned int) ((*p++)) << 8);
+  return((unsigned short) (value & 0xffff));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b M S B L o n g                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobMSBLong() reads a ssize_t value as a 32-bit quantity in
+%  most-significant byte first order.
+%
+%  The format of the ReadBlobMSBLong method is:
+%
+%      unsigned int ReadBlobMSBLong(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned int ReadBlobMSBLong(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned int
+    value;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[4];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,4,buffer,&count);
+  if (count != 4)
+    return(0UL);
+  value=((unsigned int) (*p++) << 24);
+  value|=((unsigned int) (*p++) << 16);
+  value|=((unsigned int) (*p++) << 8);
+  value|=(unsigned int) (*p++);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b M S B L o n g L o n g                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobMSBLongLong() reads a ssize_t value as a 64-bit quantity in
+%  most-significant byte first order.
+%
+%  The format of the ReadBlobMSBLongLong method is:
+%
+%      unsigned int ReadBlobMSBLongLong(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickSizeType ReadBlobMSBLongLong(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  register MagickSizeType
+    value;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[8];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,8,buffer,&count);
+  if (count != 8)
+    return(MagickULLConstant(0));
+  value=((MagickSizeType) (*p++)) << 56;
+  value|=((MagickSizeType) (*p++)) << 48;
+  value|=((MagickSizeType) (*p++)) << 40;
+  value|=((MagickSizeType) (*p++)) << 32;
+  value|=((MagickSizeType) (*p++)) << 24;
+  value|=((MagickSizeType) (*p++)) << 16;
+  value|=((MagickSizeType) (*p++)) << 8;
+  value|=((MagickSizeType) (*p++));
+  return(value & MagickULLConstant(0xffffffffffffffff));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  R e a d B l o b M S B S h o r t                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobMSBShort() reads a short value as a 16-bit quantity in
+%  most-significant byte first order.
+%
+%  The format of the ReadBlobMSBShort method is:
+%
+%      unsigned short ReadBlobMSBShort(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned short ReadBlobMSBShort(Image *image)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned int
+    value;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[2];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *buffer='\0';
+  p=ReadBlobStream(image,2,buffer,&count);
+  if (count != 2)
+    return((unsigned short) 0U);
+  value=(unsigned int) ((*p++) << 8);
+  value|=(unsigned int) (*p++);
+  return((unsigned short) (value & 0xffff));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e a d B l o b S t r i n g                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadBlobString() reads characters from a blob or file until a newline
+%  character is read or an end-of-file condition is encountered.
+%
+%  The format of the ReadBlobString method is:
+%
+%      char *ReadBlobString(Image *image,char *string)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o string: the address of a character buffer.
+%
+*/
+MagickExport char *ReadBlobString(Image *image,char *string)
+{
+  register const unsigned char
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    count;
+
+  unsigned char
+    buffer[1];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  for (i=0; i < (MaxTextExtent-1L); i++)
+  {
+    p=ReadBlobStream(image,1,buffer,&count);
+    if (count != 1)
+      {
+        if (i == 0)
+          return((char *) NULL);
+        break;
+      }
+    string[i]=(char) (*p);
+    if ((string[i] == '\r') || (string[i] == '\n'))
+      break;
+  }
+  if (string[i] == '\r')
+    (void) ReadBlobStream(image,1,buffer,&count);
+  string[i]='\0';
+  return(string);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e f e r e n c e B l o b                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReferenceBlob() increments the reference count associated with the pixel
+%  blob returning a pointer to the blob.
+%
+%  The format of the ReferenceBlob method is:
+%
+%      BlobInfo ReferenceBlob(BlobInfo *blob_info)
+%
+%  A description of each parameter follows:
+%
+%    o blob_info: the blob_info.
+%
+*/
+MagickExport BlobInfo *ReferenceBlob(BlobInfo *blob)
+{
+  assert(blob != (BlobInfo *) NULL);
+  assert(blob->signature == MagickSignature);
+  if (blob->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(blob->semaphore);
+  blob->reference_count++;
+  UnlockSemaphoreInfo(blob->semaphore);
+  return(blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S e e k B l o b                                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SeekBlob() sets the offset in bytes from the beginning of a blob or file
+%  and returns the resulting offset.
+%
+%  The format of the SeekBlob method is:
+%
+%      MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
+%        const int whence)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o offset:  Specifies an integer representing the offset in bytes.
+%
+%    o whence:  Specifies an integer representing how the offset is
+%      treated relative to the beginning of the blob as follows:
+%
+%        SEEK_SET  Set position equal to offset bytes.
+%        SEEK_CUR  Set position to current location plus offset.
+%        SEEK_END  Set position to EOF plus offset.
+%
+*/
+MagickExport MagickOffsetType SeekBlob(Image *image,
+  const MagickOffsetType offset,const int whence)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    {
+      if (fseek(image->blob->file,offset,whence) < 0)
+        return(-1);
+      image->blob->offset=TellBlob(image);
+      break;
+    }
+    case StandardStream:
+    case PipeStream:
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      if (gzseek(image->blob->file,(off_t) offset,whence) < 0)
+        return(-1);
+#endif
+      image->blob->offset=TellBlob(image);
+      break;
+    }
+    case BZipStream:
+      return(-1);
+    case FifoStream:
+      return(-1);
+    case BlobStream:
+    {
+      switch (whence)
+      {
+        case SEEK_SET:
+        default:
+        {
+          if (offset < 0)
+            return(-1);
+          image->blob->offset=offset;
+          break;
+        }
+        case SEEK_CUR:
+        {
+          if ((image->blob->offset+offset) < 0)
+            return(-1);
+          image->blob->offset+=offset;
+          break;
+        }
+        case SEEK_END:
+        {
+          if (((MagickOffsetType) image->blob->length+offset) < 0)
+            return(-1);
+          image->blob->offset=image->blob->length+offset;
+          break;
+        }
+      }
+      if (image->blob->offset <= (MagickOffsetType)
+          ((off_t) image->blob->length))
+        image->blob->eof=MagickFalse;
+      else
+        if (image->blob->mapped != MagickFalse)
+          return(-1);
+        else
+          {
+            image->blob->extent=(size_t) (image->blob->offset+
+              image->blob->quantum);
+            image->blob->data=(unsigned char *) ResizeQuantumMemory(
+              image->blob->data,image->blob->extent+1,
+              sizeof(*image->blob->data));
+            (void) SyncBlob(image);
+            if (image->blob->data == (unsigned char *) NULL)
+              {
+                (void) DetachBlob(image->blob);
+                return(-1);
+              }
+          }
+      break;
+    }
+  }
+  return(image->blob->offset);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t B l o b E x e m p t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetBlobExempt() sets the blob exempt status.
+%
+%  The format of the SetBlobExempt method is:
+%
+%      MagickBooleanType SetBlobExempt(const Image *image,
+%        const MagickBooleanType exempt)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exempt: Set to true if this blob is exempt from being closed.
+%
+*/
+MagickExport void SetBlobExempt(Image *image,const MagickBooleanType exempt)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  image->blob->exempt=exempt;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S e t B l o b E x t e n t                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetBlobExtent() ensures enough space is allocated for the blob.  If the
+%  method is successful, subsequent writes to bytes in the specified range are
+%  guaranteed not to fail.
+%
+%  The format of the SetBlobExtent method is:
+%
+%      MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o extent:  the blob maximum extent.
+%
+*/
+MagickExport MagickBooleanType SetBlobExtent(Image *image,
+  const MagickSizeType extent)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    {
+      if (extent != (MagickSizeType) ((off_t) extent))
+        return(MagickFalse);
+#if !defined(MAGICKCORE_POSIX_FALLOCATE)
+        return(MagickFalse);
+#else
+      {
+        int
+          status;
+
+        MagickOffsetType
+          offset;
+
+        offset=TellBlob(image);
+        status=posix_fallocate(fileno(image->blob->file),(off_t) offset,
+          (off_t) (extent-offset));
+        if (status != 0)
+          return(MagickFalse);
+      }
+#endif
+      break;
+    }
+    case StandardStream:
+    case PipeStream:
+    case ZipStream:
+      return(MagickFalse);
+    case BZipStream:
+      return(MagickFalse);
+    case FifoStream:
+      return(MagickFalse);
+    case BlobStream:
+    {
+      if (image->blob->mapped != MagickFalse)
+        {
+          if (image->blob->file == (FILE *) NULL)
+            return(MagickFalse);
+          (void) UnmapBlob(image->blob->data,image->blob->length);
+#if !defined(MAGICKCORE_POSIX_FALLOCATE)
+          return(MagickFalse);
+#else
+          {
+            int
+              status;
+
+            MagickOffsetType
+              offset;
+
+            offset=TellBlob(image);
+            status=posix_fallocate(fileno(image->blob->file),(off_t) offset,
+              (off_t) (extent-offset));
+            if (status != 0)
+              return(MagickFalse);
+          }
+          image->blob->data=(unsigned char*) MapBlob(fileno(image->blob->file),
+            WriteMode,0,(size_t) extent);
+          image->blob->extent=(size_t) extent;
+          image->blob->length=(size_t) extent;
+          (void) SyncBlob(image);
+          break;
+#endif
+        }
+      if (extent != (MagickSizeType) ((size_t) extent))
+        return(MagickFalse);
+      image->blob->extent=(size_t) extent;
+      image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
+        image->blob->extent+1,sizeof(*image->blob->data));
+      (void) SyncBlob(image);
+      if (image->blob->data == (unsigned char *) NULL)
+        {
+          (void) DetachBlob(image->blob);
+          return(MagickFalse);
+        }
+      break;
+    }
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  S y n c B l o b                                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncBlob() flushes the datastream if it is a file or synchronizes the data
+%  attributes if it is an blob.
+%
+%  The format of the SyncBlob method is:
+%
+%      int SyncBlob(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static int SyncBlob(Image *image)
+{
+  int
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  status=0;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    case StandardStream:
+    case PipeStream:
+    {
+      status=fflush(image->blob->file);
+      break;
+    }
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      status=gzflush(image->blob->file,Z_SYNC_FLUSH);
+#endif
+      break;
+    }
+    case BZipStream:
+    {
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+      status=BZ2_bzflush((BZFILE *) image->blob->file);
+#endif
+      break;
+    }
+    case FifoStream:
+      break;
+    case BlobStream:
+    {
+#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
+      if (image->blob->mapped != MagickFalse)
+        status=msync(image->blob->data,image->blob->length,MS_SYNC);
+#endif
+      break;
+    }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  T e l l B l o b                                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TellBlob() obtains the current value of the blob or file position.
+%
+%  The format of the TellBlob method is:
+%
+%      MagickOffsetType TellBlob(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickOffsetType TellBlob(const Image *image)
+{
+  MagickOffsetType
+    offset;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  offset=(-1);
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    {
+      offset=ftell(image->blob->file);
+      break;
+    }
+    case StandardStream:
+    case PipeStream:
+      break;
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      offset=(MagickOffsetType) gztell(image->blob->file);
+#endif
+      break;
+    }
+    case BZipStream:
+      break;
+    case FifoStream:
+      break;
+    case BlobStream:
+    {
+      offset=image->blob->offset;
+      break;
+    }
+  }
+  return(offset);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  U n m a p B l o b                                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnmapBlob() deallocates the binary large object previously allocated with
+%  the MapBlob method.
+%
+%  The format of the UnmapBlob method is:
+%
+%       MagickBooleanType UnmapBlob(void *map,const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o map: the address  of the binary large object.
+%
+%    o length: the length of the binary large object.
+%
+*/
+MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
+{
+#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
+  int
+    status;
+
+  status=munmap(map,length);
+  return(status == -1 ? MagickFalse : MagickTrue);
+#else
+  (void) map;
+  (void) length;
+  return(MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b                                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlob() writes data to a blob or image file.  It returns the number of
+%  bytes written.
+%
+%  The format of the WriteBlob method is:
+%
+%      ssize_t WriteBlob(Image *image,const size_t length,
+%        const unsigned char *data)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o length:  Specifies an integer representing the number of bytes to
+%      write to the file.
+%
+%    o data:  The address of the data to write to the blob or file.
+%
+*/
+MagickExport ssize_t WriteBlob(Image *image,const size_t length,
+  const unsigned char *data)
+{
+  int
+    c;
+
+  register const unsigned char
+    *p;
+
+  ssize_t
+    count;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(data != (const unsigned char *) NULL);
+  assert(image->blob != (BlobInfo *) NULL);
+  assert(image->blob->type != UndefinedStream);
+  if (length == 0)
+    return(0);
+  count=0;
+  p=data;
+  switch (image->blob->type)
+  {
+    case UndefinedStream:
+      break;
+    case FileStream:
+    case StandardStream:
+    case PipeStream:
+    {
+      switch (length)
+      {
+        default:
+        {
+          count=(ssize_t) fwrite((const char *) data,1,length,
+            image->blob->file);
+          break;
+        }
+        case 2:
+        {
+          c=putc((int) *p++,image->blob->file);
+          if (c == EOF)
+            break;
+          count++;
+        }
+        case 1:
+        {
+          c=putc((int) *p++,image->blob->file);
+          if (c == EOF)
+            break;
+          count++;
+        }
+        case 0:
+          break;
+      }
+      break;
+    }
+    case ZipStream:
+    {
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+      switch (length)
+      {
+        default:
+        {
+          count=(ssize_t) gzwrite(image->blob->file,(void *) data,
+            (unsigned int) length);
+          break;
+        }
+        case 2:
+        {
+          c=gzputc(image->blob->file,(int) *p++);
+          if (c == EOF)
+            break;
+          count++;
+        }
+        case 1:
+        {
+          c=gzputc(image->blob->file,(int) *p++);
+          if (c == EOF)
+            break;
+          count++;
+        }
+        case 0:
+          break;
+      }
+#endif
+      break;
+    }
+    case BZipStream:
+    {
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+      count=(ssize_t) BZ2_bzwrite((BZFILE *) image->blob->file,(void *) data,
+        (int) length);
+#endif
+      break;
+    }
+    case FifoStream:
+    {
+      count=(ssize_t) image->blob->stream(image,data,length);
+      break;
+    }
+    case BlobStream:
+    {
+      register unsigned char
+        *q;
+
+      if ((image->blob->offset+(MagickOffsetType) length) >=
+          (MagickOffsetType) image->blob->extent)
+        {
+          if (image->blob->mapped != MagickFalse)
+            return(0);
+          image->blob->quantum<<=1;
+          image->blob->extent+=length+image->blob->quantum;
+          image->blob->data=(unsigned char *) ResizeQuantumMemory(
+            image->blob->data,image->blob->extent+1,sizeof(*image->blob->data));
+          (void) SyncBlob(image);
+          if (image->blob->data == (unsigned char *) NULL)
+            {
+              (void) DetachBlob(image->blob);
+              return(0);
+            }
+        }
+      q=image->blob->data+image->blob->offset;
+      (void) memcpy(q,p,length);
+      image->blob->offset+=length;
+      if (image->blob->offset >= (MagickOffsetType) image->blob->length)
+        image->blob->length=(size_t) image->blob->offset;
+      count=(ssize_t) length;
+    }
+  }
+  return(count);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b B y t e                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobByte() write an integer to a blob.  It returns the number of bytes
+%  written (either 0 or 1);
+%
+%  The format of the WriteBlobByte method is:
+%
+%      ssize_t WriteBlobByte(Image *image,const unsigned char value)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o value: Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  return(WriteBlobStream(image,1,&value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b F l o a t                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the WriteBlobFloat method is:
+%
+%      ssize_t WriteBlobFloat(Image *image,const float value)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o value: Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
+{
+  union
+  {
+    unsigned int
+      unsigned_value;
+
+    float
+      float_value;
+  } quantum;
+
+  quantum.unsigned_value=0U;
+  quantum.float_value=value;
+  return(WriteBlobLong(image,quantum.unsigned_value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b L o n g                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobLong() writes a ssize_t value as a 32-bit quantity in the byte-order
+%  specified by the endian member of the image structure.
+%
+%  The format of the WriteBlobLong method is:
+%
+%      ssize_t WriteBlobLong(Image *image,const unsigned int value)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o value: Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
+{
+  unsigned char
+    buffer[4];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->endian == LSBEndian)
+    {
+      buffer[0]=(unsigned char) value;
+      buffer[1]=(unsigned char) (value >> 8);
+      buffer[2]=(unsigned char) (value >> 16);
+      buffer[3]=(unsigned char) (value >> 24);
+      return(WriteBlobStream(image,4,buffer));
+    }
+  buffer[0]=(unsigned char) (value >> 24);
+  buffer[1]=(unsigned char) (value >> 16);
+  buffer[2]=(unsigned char) (value >> 8);
+  buffer[3]=(unsigned char) value;
+  return(WriteBlobStream(image,4,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   W r i t e B l o b S h o r t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobShort() writes a short value as a 16-bit quantity in the
+%  byte-order specified by the endian member of the image structure.
+%
+%  The format of the WriteBlobShort method is:
+%
+%      ssize_t WriteBlobShort(Image *image,const unsigned short value)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o value:  Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
+{
+  unsigned char
+    buffer[2];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->endian == LSBEndian)
+    {
+      buffer[0]=(unsigned char) value;
+      buffer[1]=(unsigned char) (value >> 8);
+      return(WriteBlobStream(image,2,buffer));
+    }
+  buffer[0]=(unsigned char) (value >> 8);
+  buffer[1]=(unsigned char) value;
+  return(WriteBlobStream(image,2,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b L S B L o n g                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobLSBLong() writes a ssize_t value as a 32-bit quantity in
+%  least-significant byte first order.
+%
+%  The format of the WriteBlobLSBLong method is:
+%
+%      ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o value: Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
+{
+  unsigned char
+    buffer[4];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  buffer[0]=(unsigned char) value;
+  buffer[1]=(unsigned char) (value >> 8);
+  buffer[2]=(unsigned char) (value >> 16);
+  buffer[3]=(unsigned char) (value >> 24);
+  return(WriteBlobStream(image,4,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   W r i t e B l o b L S B S h o r t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobLSBShort() writes a ssize_t value as a 16-bit quantity in
+%  least-significant byte first order.
+%
+%  The format of the WriteBlobLSBShort method is:
+%
+%      ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o value:  Specifies the value to write.
+%
+*/
+MagickExport ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
+{
+  unsigned char
+    buffer[2];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  buffer[0]=(unsigned char) value;
+  buffer[1]=(unsigned char) (value >> 8);
+  return(WriteBlobStream(image,2,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b M S B L o n g                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobMSBLong() writes a ssize_t value as a 32-bit quantity in
+%  most-significant byte first order.
+%
+%  The format of the WriteBlobMSBLong method is:
+%
+%      ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
+%
+%  A description of each parameter follows.
+%
+%    o value:  Specifies the value to write.
+%
+%    o image: the image.
+%
+*/
+MagickExport ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
+{
+  unsigned char
+    buffer[4];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  buffer[0]=(unsigned char) (value >> 24);
+  buffer[1]=(unsigned char) (value >> 16);
+  buffer[2]=(unsigned char) (value >> 8);
+  buffer[3]=(unsigned char) value;
+  return(WriteBlobStream(image,4,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b M S B L o n g L o n g                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in
+%  most-significant byte first order.
+%
+%  The format of the WriteBlobMSBLongLong method is:
+%
+%      ssize_t WriteBlobMSBLongLong(Image *image,const MagickSizeType value)
+%
+%  A description of each parameter follows.
+%
+%    o value:  Specifies the value to write.
+%
+%    o image: the image.
+%
+*/
+MagickExport ssize_t WriteBlobMSBLongLong(Image *image,
+  const MagickSizeType value)
+{
+  unsigned char
+    buffer[8];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  buffer[0]=(unsigned char) (value >> 56);
+  buffer[1]=(unsigned char) (value >> 48);
+  buffer[2]=(unsigned char) (value >> 40);
+  buffer[3]=(unsigned char) (value >> 32);
+  buffer[4]=(unsigned char) (value >> 24);
+  buffer[5]=(unsigned char) (value >> 16);
+  buffer[6]=(unsigned char) (value >> 8);
+  buffer[7]=(unsigned char) value;
+  return(WriteBlobStream(image,8,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b M S B S h o r t                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobMSBShort() writes a ssize_t value as a 16-bit quantity in
+%  most-significant byte first order.
+%
+%  The format of the WriteBlobMSBShort method is:
+%
+%      ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
+%
+%  A description of each parameter follows.
+%
+%   o  value:  Specifies the value to write.
+%
+%   o  file:  Specifies the file to write the data to.
+%
+*/
+MagickExport ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
+{
+  unsigned char
+    buffer[2];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  buffer[0]=(unsigned char) (value >> 8);
+  buffer[1]=(unsigned char) value;
+  return(WriteBlobStream(image,2,buffer));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  W r i t e B l o b S t r i n g                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteBlobString() write a string to a blob.  It returns the number of
+%  characters written.
+%
+%  The format of the WriteBlobString method is:
+%
+%      ssize_t WriteBlobString(Image *image,const char *string)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o string: Specifies the string to write.
+%
+*/
+MagickExport ssize_t WriteBlobString(Image *image,const char *string)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(string != (const char *) NULL);
+  return(WriteBlobStream(image,strlen(string),(const unsigned char *) string));
+}
diff --git a/MagickCore/blob.h b/MagickCore/blob.h
new file mode 100644
index 0000000..6590ab0
--- /dev/null
+++ b/MagickCore/blob.h
@@ -0,0 +1,76 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore Binary Large OBjects methods.
+*/
+#ifndef _MAGICKCORE_BLOB_H
+#define _MAGICKCORE_BLOB_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/image.h"
+#include "MagickCore/stream.h"
+
+#define MagickMaxBufferExtent  (32*8192)
+
+typedef enum
+{
+  ReadMode,
+  WriteMode,
+  IOMode
+} MapMode;
+
+extern MagickExport FILE
+  *GetBlobFileHandle(const Image *);
+
+extern MagickExport Image
+  *BlobToImage(const ImageInfo *,const void *,const size_t,ExceptionInfo *),
+  *PingBlob(const ImageInfo *,const void *,const size_t,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  BlobToFile(char *,const void *,const size_t,ExceptionInfo *),
+  FileToImage(Image *,const char *),
+  GetBlobError(const Image *),
+  ImageToFile(Image *,char *,ExceptionInfo *),
+  InjectImageBlob(const ImageInfo *,Image *,Image *,const char *,
+    ExceptionInfo *),
+  IsBlobExempt(const Image *),
+  IsBlobSeekable(const Image *),
+  IsBlobTemporary(const Image *);
+
+extern MagickExport MagickSizeType
+  GetBlobSize(const Image *);
+
+extern MagickExport StreamHandler
+  GetBlobStreamHandler(const Image *);
+
+extern MagickExport unsigned char
+  *FileToBlob(const char *,const size_t,size_t *,ExceptionInfo *),
+  *GetBlobStreamData(const Image *),
+  *ImageToBlob(const ImageInfo *,Image *,size_t *,ExceptionInfo *),
+  *ImagesToBlob(const ImageInfo *,Image *,size_t *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyBlob(Image *),
+  DuplicateBlob(Image *,const Image *),
+  SetBlobExempt(Image *,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/cache-private.h b/MagickCore/cache-private.h
new file mode 100644
index 0000000..5906035
--- /dev/null
+++ b/MagickCore/cache-private.h
@@ -0,0 +1,253 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore cache private methods.
+*/
+#ifndef _MAGICKCORE_CACHE_PRIVATE_H
+#define _MAGICKCORE_CACHE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <time.h>
+#include "MagickCore/random_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/semaphore.h"
+
+typedef enum
+{
+  UndefinedCache,
+  MemoryCache,
+  MapCache,
+  DiskCache,
+  PingCache
+} CacheType;
+
+typedef void
+  *Cache;
+
+typedef MagickBooleanType
+  (*GetOneAuthenticPixelFromHandler)(Image *,const ssize_t,const ssize_t,
+    PixelPacket *,ExceptionInfo *),
+  (*GetOneVirtualPixelFromHandler)(const Image *,const VirtualPixelMethod,
+    const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
+  (*SyncAuthenticPixelsHandler)(Image *,ExceptionInfo *);
+
+typedef const Quantum
+  *(*GetVirtualPixelHandler)(const Image *,const VirtualPixelMethod,
+    const ssize_t,const ssize_t,const size_t,const size_t,ExceptionInfo *),
+  *(*GetVirtualPixelsHandler)(const Image *);
+
+typedef const void
+  *(*GetVirtualMetacontentFromHandler)(const Image *);
+
+typedef Quantum
+  *(*GetAuthenticPixelsHandler)(Image *,const ssize_t,const ssize_t,
+    const size_t,const size_t,ExceptionInfo *);
+
+typedef Quantum
+  *(*GetAuthenticPixelsFromHandler)(const Image *);
+
+typedef Quantum
+  *(*QueueAuthenticPixelsHandler)(Image *,const ssize_t,const ssize_t,
+    const size_t,const size_t,ExceptionInfo *);
+
+typedef void
+  (*DestroyPixelHandler)(Image *);
+
+typedef void
+  *(*GetAuthenticMetacontentFromHandler)(const Image *);
+
+typedef struct _CacheMethods
+{
+  GetVirtualPixelHandler
+    get_virtual_pixel_handler;
+
+  GetVirtualPixelsHandler
+    get_virtual_pixels_handler;
+
+  GetVirtualMetacontentFromHandler
+    get_virtual_metacontent_from_handler;
+
+  GetOneVirtualPixelFromHandler
+    get_one_virtual_pixel_from_handler;
+
+  GetAuthenticPixelsHandler
+    get_authentic_pixels_handler;
+
+  GetAuthenticMetacontentFromHandler
+    get_authentic_metacontent_from_handler;
+
+  GetOneAuthenticPixelFromHandler
+    get_one_authentic_pixel_from_handler;
+
+  GetAuthenticPixelsFromHandler
+    get_authentic_pixels_from_handler;
+
+  QueueAuthenticPixelsHandler
+    queue_authentic_pixels_handler;
+
+  SyncAuthenticPixelsHandler
+    sync_authentic_pixels_handler;
+
+  DestroyPixelHandler
+    destroy_pixel_handler;
+} CacheMethods;
+
+typedef struct _NexusInfo
+   NexusInfo;
+
+typedef struct _CacheInfo
+{
+  ClassType
+    storage_class;
+
+  ColorspaceType
+    colorspace;
+
+  size_t
+    metacontent_extent,
+    pixel_channels;
+
+  CacheType
+    type;
+
+  MapMode
+    mode;
+
+  MagickBooleanType
+    mapped;
+
+  size_t
+    columns,
+    rows;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    length;
+
+  VirtualPixelMethod
+    virtual_pixel_method;
+
+  PixelInfo
+    virtual_pixel_color;
+
+  size_t
+    number_threads;
+
+  NexusInfo
+    **nexus_info;
+
+  Quantum
+    *pixels;
+
+  void
+    *metacontent;
+
+  int
+    file;
+
+  char
+    filename[MaxTextExtent],
+    cache_filename[MaxTextExtent];
+
+  CacheMethods
+    methods;
+
+  RandomInfo
+    *random_info;
+
+  MagickBooleanType
+    debug;
+
+  MagickThreadType
+    id;
+
+  ssize_t
+    reference_count;
+
+  SemaphoreInfo
+    *semaphore,
+    *disk_semaphore;
+
+  time_t
+    timestamp;
+
+  size_t
+    signature;
+} CacheInfo;
+
+extern MagickExport Cache
+  AcquirePixelCache(const size_t),
+  ClonePixelCache(const Cache),
+  DestroyPixelCache(Cache),
+  ReferencePixelCache(Cache);
+
+extern MagickExport CacheType
+  GetPixelCacheType(const Image *);
+
+extern MagickExport ClassType
+  GetPixelCacheStorageClass(const Cache);
+
+extern MagickExport ColorspaceType
+  GetPixelCacheColorspace(const Cache);
+
+
+extern MagickExport const Quantum
+  *GetVirtualPixelsFromNexus(const Image *,const VirtualPixelMethod,
+    const ssize_t,const ssize_t,const size_t,const size_t,NexusInfo *,
+    ExceptionInfo *),
+  *GetVirtualPixelsNexus(const Cache,NexusInfo *);
+
+extern MagickExport const void
+  *GetVirtualMetacontentFromNexus(const Cache,NexusInfo *);
+
+extern MagickExport MagickBooleanType
+  SyncAuthenticPixelCacheNexus(Image *,NexusInfo *,ExceptionInfo *);
+
+extern MagickExport MagickSizeType
+  GetPixelCacheNexusExtent(const Cache,NexusInfo *);
+
+extern MagickExport NexusInfo
+  **AcquirePixelCacheNexus(const size_t),
+  **DestroyPixelCacheNexus(NexusInfo **,const size_t);
+
+extern MagickExport Quantum
+  *GetAuthenticPixelCacheNexus(Image *,const ssize_t,const ssize_t,
+    const size_t,const size_t,NexusInfo *,ExceptionInfo *),
+  *GetPixelCacheNexusPixels(const Cache,NexusInfo *),
+  *QueueAuthenticNexus(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,NexusInfo *,ExceptionInfo *);
+
+extern MagickExport size_t
+  GetPixelCacheChannels(const Cache);
+
+extern MagickExport void
+  ClonePixelCacheMethods(Cache,const Cache),
+  GetPixelCacheTileSize(const Image *,size_t *,size_t *),
+  GetPixelCacheMethods(CacheMethods *),
+  SetPixelCacheMethods(Cache,CacheMethods *);
+
+extern MagickExport void
+  *GetPixelCacheNexusMetacontent(const Cache,NexusInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/cache-view.c b/MagickCore/cache-view.c
new file mode 100644
index 0000000..f82db39
--- /dev/null
+++ b/MagickCore/cache-view.c
@@ -0,0 +1,966 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      CCCC   AAA    CCCC  H   H  EEEEE                       %
+%                     C      A   A  C      H   H  E                           %
+%                     C      AAAAA  C      HHHHH  EEE                         %
+%                     C      A   A  C      H   H  E                           %
+%                      CCCC  A   A   CCCC  H   H  EEEEE                       %
+%                                                                             %
+%                        V   V  IIIII  EEEEE  W   W                           %
+%                        V   V    I    E      W   W                           %
+%                        V   V    I    EEE    W W W                           %
+%                         V V     I    E      WW WW                           %
+%                          V    IIIII  EEEEE  W   W                           %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Cache View Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               February 2000                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+
+/*
+  Typedef declarations.
+*/
+struct _CacheView
+{
+  Image
+    *image;
+
+  VirtualPixelMethod
+    virtual_pixel_method;
+
+  size_t
+    number_threads;
+
+  NexusInfo
+    **nexus_info;
+
+  MagickBooleanType
+    debug;
+
+  size_t
+    signature;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e C a c h e V i e w                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireCacheView() acquires a view into the pixel cache, using the
+%  VirtualPixelMethod that is defined within the given image itself.
+%
+%  The format of the AcquireCacheView method is:
+%
+%      CacheView *AcquireCacheView(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport CacheView *AcquireCacheView(const Image *image)
+{
+  CacheView
+    *cache_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_view=(CacheView *) AcquireMagickMemory(sizeof(*cache_view));
+  if (cache_view == (CacheView *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(cache_view,0,sizeof(*cache_view));
+  cache_view->image=ReferenceImage((Image *) image);
+  cache_view->number_threads=GetOpenMPMaximumThreads();
+  cache_view->nexus_info=AcquirePixelCacheNexus(cache_view->number_threads);
+  cache_view->virtual_pixel_method=GetImageVirtualPixelMethod(image);
+  cache_view->debug=IsEventLogging();
+  cache_view->signature=MagickSignature;
+  if (cache_view->nexus_info == (NexusInfo **) NULL)
+    ThrowFatalException(CacheFatalError,"UnableToAcquireCacheView");
+  return(cache_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e C a c h e V i e w                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneCacheView()  makes an exact copy of the specified cache view.
+%
+%  The format of the CloneCacheView method is:
+%
+%      CacheView *CloneCacheView(const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport CacheView *CloneCacheView(const CacheView *cache_view)
+{
+  CacheView
+    *clone_view;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  clone_view=(CacheView *) AcquireMagickMemory(sizeof(*clone_view));
+  if (clone_view == (CacheView *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
+  clone_view->image=ReferenceImage(cache_view->image);
+  clone_view->number_threads=cache_view->number_threads;
+  clone_view->nexus_info=AcquirePixelCacheNexus(cache_view->number_threads);
+  clone_view->virtual_pixel_method=cache_view->virtual_pixel_method;
+  clone_view->debug=cache_view->debug;
+  clone_view->signature=MagickSignature;
+  return(clone_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y C a c h e V i e w                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyCacheView() destroys the specified view returned by a previous call
+%  to AcquireCacheView().
+%
+%  The format of the DestroyCacheView method is:
+%
+%      CacheView *DestroyCacheView(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport CacheView *DestroyCacheView(CacheView *cache_view)
+{
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  if (cache_view->nexus_info != (NexusInfo **) NULL)
+    cache_view->nexus_info=DestroyPixelCacheNexus(cache_view->nexus_info,
+      cache_view->number_threads);
+  cache_view->image=DestroyImage(cache_view->image);
+  cache_view->signature=(~MagickSignature);
+  cache_view=(CacheView *) RelinquishMagickMemory(cache_view);
+  return(cache_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w C o l o r s p a c e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewColorspace() returns the image colorspace associated with the
+%  specified view.
+%
+%  The format of the GetCacheViewColorspace method is:
+%
+%      ColorspaceType GetCacheViewColorspace(const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport ColorspaceType GetCacheViewColorspace(const CacheView *cache_view)
+{
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  return(GetPixelCacheColorspace(cache_view->image->cache));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w E x c e p t i o n                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewException() returns the image exception associated with the
+%  specified view.
+%
+%  The format of the GetCacheViewException method is:
+%
+%      ExceptionInfo GetCacheViewException(const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport ExceptionInfo *GetCacheViewException(const CacheView *cache_view)
+{
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  return(&cache_view->image->exception);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C a c h e V i e w E x t e n t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewExtent() returns the extent of the pixels associated with the
+%  last call to QueueCacheViewAuthenticPixels() or
+%  GetCacheViewAuthenticPixels().
+%
+%  The format of the GetCacheViewExtent() method is:
+%
+%      MagickSizeType GetCacheViewExtent(const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport MagickSizeType GetCacheViewExtent(const CacheView *cache_view)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  MagickSizeType
+    extent;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  assert(cache_view->image->cache != (Cache) NULL);
+  assert(id < (int) cache_view->number_threads);
+  extent=GetPixelCacheNexusExtent(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(extent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w S t o r a g e C l a s s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewStorageClass() returns the image storage class  associated with
+%  the specified view.
+%
+%  The format of the GetCacheViewStorageClass method is:
+%
+%      ClassType GetCacheViewStorageClass(const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport ClassType GetCacheViewStorageClass(const CacheView *cache_view)
+{
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  return(GetPixelCacheStorageClass(cache_view->image->cache));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w A u t h e n t i c P i x e l s                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewAuthenticPixels() gets pixels from the in-memory or disk pixel
+%  cache as defined by the geometry parameters.   A pointer to the pixels is
+%  returned if the pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the GetCacheViewAuthenticPixels method is:
+%
+%      Quantum *GetCacheViewAuthenticPixels(CacheView *cache_view,
+%        const ssize_t x,const ssize_t y,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+*/
+MagickExport Quantum *GetCacheViewAuthenticPixels(CacheView *cache_view,
+  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(id < (int) cache_view->number_threads);
+  pixels=GetAuthenticPixelCacheNexus(cache_view->image,x,y,columns,rows,
+    cache_view->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w A u t h e n t i c M e t a c o n t e n t           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewAuthenticMetacontent() returns the meta-content corresponding
+%  with the last call to SetCacheViewIndexes() or
+%  GetCacheViewAuthenticMetacontent().  The meta-content are authentic and can
+%  be updated.
+%
+%  The format of the GetCacheViewAuthenticMetacontent() method is:
+%
+%      void *GetCacheViewAuthenticMetacontent(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport void *GetCacheViewAuthenticMetacontent(
+  CacheView *cache_view)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  void
+    *metacontent;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(cache_view->image->cache != (Cache) NULL);
+  assert(id < (int) cache_view->number_threads);
+  metacontent=GetPixelCacheNexusMetacontent(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w A u t h e n t i c P i x e l Q u e u e             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewAuthenticPixelQueue() returns the pixels associated with the
+%  last call to QueueCacheViewAuthenticPixels() or
+%  GetCacheViewAuthenticPixels().  The pixels are authentic and therefore can be
+%  updated.
+%
+%  The format of the GetCacheViewAuthenticPixelQueue() method is:
+%
+%      Quantum *GetCacheViewAuthenticPixelQueue(CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport Quantum *GetCacheViewAuthenticPixelQueue(CacheView *cache_view)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(cache_view->image->cache != (Cache) NULL);
+  assert(id < (int) cache_view->number_threads);
+  pixels=GetPixelCacheNexusPixels(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w V i r t u a l M e t a c o n t e n t               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewVirtualMetacontent() returns the meta-content corresponding
+%  with the last call to GetCacheViewVirtualMetacontent().  The meta-content
+%  is virtual and therefore cannot be updated.
+%
+%  The format of the GetCacheViewVirtualMetacontent() method is:
+%
+%      const void *GetCacheViewVirtualMetacontent(
+%        const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport const void *GetCacheViewVirtualMetacontent(
+  const CacheView *cache_view)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  const void
+    *metacontent;
+
+  assert(cache_view != (const CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(cache_view->image->cache != (Cache) NULL);
+  assert(id < (int) cache_view->number_threads);
+  metacontent=GetVirtualMetacontentFromNexus(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w V i r t u a l P i x e l Q u e u e                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewVirtualPixelQueue() returns the the pixels associated with
+%  the last call to GetCacheViewVirtualPixels().  The pixels are virtual
+%  and therefore cannot be updated.
+%
+%  The format of the GetCacheViewVirtualPixelQueue() method is:
+%
+%      const Quantum *GetCacheViewVirtualPixelQueue(
+%        const CacheView *cache_view)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+*/
+MagickExport const Quantum *GetCacheViewVirtualPixelQueue(
+  const CacheView *cache_view)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *pixels;
+
+  assert(cache_view != (const CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(cache_view->image->cache != (Cache) NULL);
+  assert(id < (int) cache_view->number_threads);
+  pixels=GetVirtualPixelsNexus(cache_view->image->cache,
+    cache_view->nexus_info[id]);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C a c h e V i e w V i r t u a l P i x e l s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCacheViewVirtualPixels() gets virtual pixels from the in-memory or
+%  disk pixel cache as defined by the geometry parameters.   A pointer to the
+%  pixels is returned if the pixels are transferred, otherwise a NULL is
+%  returned.
+%
+%  The format of the GetCacheViewVirtualPixels method is:
+%
+%      const Quantum *GetCacheViewVirtualPixels(
+%        const CacheView *cache_view,const ssize_t x,const ssize_t y,
+%        const size_t columns,const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const Quantum *GetCacheViewVirtualPixels(
+  const CacheView *cache_view,const ssize_t x,const ssize_t y,
+  const size_t columns,const size_t rows,ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *pixels;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(id < (int) cache_view->number_threads);
+  pixels=GetVirtualPixelsFromNexus(cache_view->image,
+    cache_view->virtual_pixel_method,x,y,columns,rows,
+    cache_view->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e C a c h e V i e w A u t h e n t i c P i x e l                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneCacheViewAuthenticPixel() returns a single pixel at the specified (x,y)
+%  location.  The image background color is returned if an error occurs.
+%
+%  The format of the GetOneCacheViewAuthenticPixel method is:
+%
+%      MagickBooleaNType GetOneCacheViewAuthenticPixel(
+%        const CacheView *cache_view,const ssize_t x,const ssize_t y,
+%        PixelPacket *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o x,y:  These values define the offset of the pixel.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneCacheViewAuthenticPixel(
+  const CacheView *cache_view,const ssize_t x,const ssize_t y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *p;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  *pixel=cache_view->image->background_color;
+  assert(id < (int) cache_view->number_threads);
+  p=GetAuthenticPixelCacheNexus(cache_view->image,x,y,1,1,
+    cache_view->nexus_info[id],exception);
+  if (p == (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(cache_view->image,p,pixel);
+  if (GetPixelCacheColorspace(cache_view->image->cache) == CMYKColorspace)
+    pixel->black=GetPixelBlack(cache_view->image,p);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e C a c h e V i e w V i r t u a l P i x e l                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneCacheViewVirtualPixel() returns a single pixel at the specified (x,y)
+%  location.  The image background color is returned if an error occurs.  If
+%  you plan to modify the pixel, use GetOneCacheViewAuthenticPixel() instead.
+%
+%  The format of the GetOneCacheViewVirtualPixel method is:
+%
+%      MagickBooleanType GetOneCacheViewVirtualPixel(
+%        const CacheView *cache_view,const ssize_t x,const ssize_t y,
+%        PixelPacket *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o x,y:  These values define the offset of the pixel.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneCacheViewVirtualPixel(
+  const CacheView *cache_view,const ssize_t x,const ssize_t y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *p;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  *pixel=cache_view->image->background_color;
+  assert(id < (int) cache_view->number_threads);
+  p=GetVirtualPixelsFromNexus(cache_view->image,
+    cache_view->virtual_pixel_method,x,y,1,1,cache_view->nexus_info[id],
+    exception);
+  if (p == (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(cache_view->image,p,pixel);
+  if (GetPixelCacheColorspace(cache_view->image->cache) == CMYKColorspace)
+    pixel->black=GetPixelBlack(cache_view->image,p);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e C a c h e V i e w V i r t u a l P i x e l                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneCacheViewVirtualMethodPixel() returns a single virtual pixel at
+%  the specified (x,y) location.  The image background color is returned if an
+%  error occurs.  If you plan to modify the pixel, use
+%  GetOneCacheViewAuthenticPixel() instead.
+%
+%  The format of the GetOneCacheViewVirtualPixel method is:
+%
+%      MagickBooleanType GetOneCacheViewVirtualMethodPixel(
+%        const CacheView *cache_view,
+%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
+%        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y:  These values define the offset of the pixel.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneCacheViewVirtualMethodPixel(
+  const CacheView *cache_view,const VirtualPixelMethod virtual_pixel_method,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *p;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  *pixel=cache_view->image->background_color;
+  assert(id < (int) cache_view->number_threads);
+  p=GetVirtualPixelsFromNexus(cache_view->image,virtual_pixel_method,x,y,1,1,
+    cache_view->nexus_info[id],exception);
+  if (p == (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(cache_view->image,p,pixel);
+  if (GetPixelCacheColorspace(cache_view->image->cache) == CMYKColorspace)
+    pixel->black=GetPixelBlack(cache_view->image,p);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u e u e C a c h e V i e w A u t h e n t i c P i x e l s                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueueCacheViewAuthenticPixels() queues authentic pixels from the in-memory or
+%  disk pixel cache as defined by the geometry parameters.   A pointer to the
+%  pixels is returned if the pixels are transferred, otherwise a NULL is
+%  returned.
+%
+%  The format of the QueueCacheViewAuthenticPixels method is:
+%
+%      Quantum *QueueCacheViewAuthenticPixels(CacheView *cache_view,
+%        const ssize_t x,const ssize_t y,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Quantum *QueueCacheViewAuthenticPixels(CacheView *cache_view,
+  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(id < (int) cache_view->number_threads);
+  pixels=QueueAuthenticNexus(cache_view->image,x,y,columns,rows,
+    cache_view->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t C a c h e V i e w S t o r a g e C l a s s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCacheViewStorageClass() sets the image storage class associated with
+%  the specified view.
+%
+%  The format of the SetCacheViewStorageClass method is:
+%
+%      MagickBooleanType SetCacheViewStorageClass(CacheView *cache_view,
+%        const ClassType storage_class)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o storage_class: the image storage class: PseudoClass or DirectClass.
+%
+*/
+MagickExport MagickBooleanType SetCacheViewStorageClass(CacheView *cache_view,
+  const ClassType storage_class)
+{
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  return(SetImageStorageClass(cache_view->image,storage_class));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t C a c h e V i e w V i r t u a l P i x e l M e t h o d               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetCacheViewVirtualPixelMethod() sets the virtual pixel method associated
+%  with the specified cache view.
+%
+%  The format of the SetCacheViewVirtualPixelMethod method is:
+%
+%      MagickBooleanType SetCacheViewVirtualPixelMethod(CacheView *cache_view,
+%        const VirtualPixelMethod virtual_pixel_method)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+*/
+MagickExport MagickBooleanType SetCacheViewVirtualPixelMethod(
+  CacheView *cache_view,const VirtualPixelMethod virtual_pixel_method)
+{
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  if (cache_view->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_view->image->filename);
+  cache_view->virtual_pixel_method=virtual_pixel_method;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c C a c h e V i e w A u t h e n t i c P i x e l s                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncCacheViewAuthenticPixels() saves the cache view pixels to the in-memory
+%  or disk cache.  It returns MagickTrue if the pixel region is flushed,
+%  otherwise MagickFalse.
+%
+%  The format of the SyncCacheViewAuthenticPixels method is:
+%
+%      MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *cache_view,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_view: the cache view.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(
+  CacheView *cache_view,ExceptionInfo *exception)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  MagickBooleanType
+    status;
+
+  assert(cache_view != (CacheView *) NULL);
+  assert(cache_view->signature == MagickSignature);
+  assert(id < (int) cache_view->number_threads);
+  status=SyncAuthenticPixelCacheNexus(cache_view->image,
+    cache_view->nexus_info[id],exception);
+  return(status);
+}
diff --git a/MagickCore/cache-view.h b/MagickCore/cache-view.h
new file mode 100644
index 0000000..7be39f1
--- /dev/null
+++ b/MagickCore/cache-view.h
@@ -0,0 +1,102 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore cache view methods.
+*/
+#ifndef _MAGICKCORE_CACHE_VIEW_H
+#define _MAGICKCORE_CACHE_VIEW_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/pixel.h"
+
+typedef enum
+{
+  UndefinedVirtualPixelMethod,
+  BackgroundVirtualPixelMethod,
+  DitherVirtualPixelMethod,
+  EdgeVirtualPixelMethod,
+  MirrorVirtualPixelMethod,
+  RandomVirtualPixelMethod,
+  TileVirtualPixelMethod,
+  TransparentVirtualPixelMethod,
+  MaskVirtualPixelMethod,
+  BlackVirtualPixelMethod,
+  GrayVirtualPixelMethod,
+  WhiteVirtualPixelMethod,
+  HorizontalTileVirtualPixelMethod,
+  VerticalTileVirtualPixelMethod,
+  HorizontalTileEdgeVirtualPixelMethod,
+  VerticalTileEdgeVirtualPixelMethod,
+  CheckerTileVirtualPixelMethod
+} VirtualPixelMethod;
+
+typedef struct _CacheView
+  CacheView;
+
+extern MagickExport CacheView
+  *AcquireCacheView(const Image *),
+  *CloneCacheView(const CacheView *),
+  *DestroyCacheView(CacheView *);
+
+extern MagickExport ClassType
+  GetCacheViewStorageClass(const CacheView *);
+
+extern MagickExport ColorspaceType
+  GetCacheViewColorspace(const CacheView *);
+
+extern MagickExport const Quantum
+  *GetCacheViewVirtualPixels(const CacheView *,const ssize_t,const ssize_t,
+    const size_t,const size_t,ExceptionInfo *),
+  *GetCacheViewVirtualPixelQueue(const CacheView *);
+
+extern MagickExport const void
+  *GetCacheViewVirtualMetacontent(const CacheView *);
+
+extern MagickExport ExceptionInfo
+  *GetCacheViewException(const CacheView *);
+
+extern MagickExport MagickBooleanType
+  GetOneCacheViewVirtualPixel(const CacheView *,const ssize_t,const ssize_t,
+    PixelPacket *,ExceptionInfo *),
+  GetOneCacheViewVirtualMethodPixel(const CacheView *,
+    const VirtualPixelMethod,const ssize_t,const ssize_t,PixelPacket *,
+    ExceptionInfo *),
+  GetOneCacheViewAuthenticPixel(const CacheView *,const ssize_t,const ssize_t,
+    PixelPacket *,ExceptionInfo *),
+  SetCacheViewStorageClass(CacheView *,const ClassType),
+  SetCacheViewVirtualPixelMethod(CacheView *,const VirtualPixelMethod),
+  SyncCacheViewAuthenticPixels(CacheView *,ExceptionInfo *);
+
+extern MagickExport MagickSizeType
+  GetCacheViewExtent(const CacheView *);
+
+extern MagickExport Quantum
+  *GetCacheViewAuthenticPixelQueue(CacheView *),
+  *GetCacheViewAuthenticPixels(CacheView *,const ssize_t,const ssize_t,
+    const size_t,const size_t,ExceptionInfo *),
+  *QueueCacheViewAuthenticPixels(CacheView *,const ssize_t,const ssize_t,
+    const size_t,const size_t,ExceptionInfo *);
+
+extern MagickExport void
+  *GetCacheViewAuthenticMetacontent(CacheView *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/cache.c b/MagickCore/cache.c
new file mode 100644
index 0000000..89cefd4
--- /dev/null
+++ b/MagickCore/cache.c
@@ -0,0 +1,5590 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      CCCC   AAA    CCCC  H   H  EEEEE                       %
+%                     C      A   A  C      H   H  E                           %
+%                     C      AAAAA  C      HHHHH  EEE                         %
+%                     C      A   A  C      H   H  E                           %
+%                      CCCC  A   A   CCCC  H   H  EEEEE                       %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Pixel Cache Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1999                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/utility.h"
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+#include "zlib.h"
+#endif
+
+/*
+  Define declarations.
+*/
+#define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
+
+/*
+  Typedef declarations.
+*/
+typedef struct _MagickModulo
+{
+  ssize_t
+    quotient,
+    remainder;
+} MagickModulo;
+
+struct _NexusInfo
+{
+  MagickBooleanType
+    mapped;
+
+  RectangleInfo
+    region;
+
+  MagickSizeType
+    length;
+
+  Quantum
+    *cache,
+    *pixels;
+
+  void
+    *metacontent;
+
+  size_t
+    signature;
+};
+
+/*
+  Forward declarations.
+*/
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const Quantum
+  *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
+    const ssize_t,const size_t,const size_t,ExceptionInfo *),
+  *GetVirtualPixelsCache(const Image *);
+
+static const void
+  *GetVirtualMetacontentFromCache(const Image *);
+
+static MagickBooleanType
+  GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
+    PixelPacket *,ExceptionInfo *),
+  GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
+    const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
+  OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
+  ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
+  WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
+
+static Quantum
+  *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,ExceptionInfo *),
+  *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,ExceptionInfo *),
+  *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
+    ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+/*
+  Global declarations.
+*/
+static volatile MagickBooleanType
+  instantiate_cache = MagickFalse;
+
+static SemaphoreInfo
+  *cache_semaphore = (SemaphoreInfo *) NULL;
+
+static SplayTreeInfo
+  *cache_resources = (SplayTreeInfo *) NULL;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e P i x e l C a c h e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquirePixelCache() acquires a pixel cache.
+%
+%  The format of the AcquirePixelCache() method is:
+%
+%      Cache AcquirePixelCache(const size_t number_threads)
+%
+%  A description of each parameter follows:
+%
+%    o number_threads: the number of nexus threads.
+%
+*/
+MagickExport Cache AcquirePixelCache(const size_t number_threads)
+{
+  CacheInfo
+    *cache_info;
+
+  cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
+  if (cache_info == (CacheInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
+  cache_info->type=UndefinedCache;
+  cache_info->mode=IOMode;
+  cache_info->colorspace=RGBColorspace;
+  cache_info->file=(-1);
+  cache_info->id=GetMagickThreadId();
+  cache_info->number_threads=number_threads;
+  if (number_threads == 0)
+    cache_info->number_threads=GetOpenMPMaximumThreads();
+  cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
+  if (cache_info->nexus_info == (NexusInfo **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  cache_info->semaphore=AllocateSemaphoreInfo();
+  cache_info->reference_count=1;
+  cache_info->disk_semaphore=AllocateSemaphoreInfo();
+  cache_info->debug=IsEventLogging();
+  cache_info->signature=MagickSignature;
+  if ((cache_resources == (SplayTreeInfo *) NULL) &&
+      (instantiate_cache == MagickFalse))
+    {
+      if (cache_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&cache_semaphore);
+      LockSemaphoreInfo(cache_semaphore);
+      if ((cache_resources == (SplayTreeInfo *) NULL) &&
+          (instantiate_cache == MagickFalse))
+        {
+          cache_resources=NewSplayTree((int (*)(const void *,const void *))
+            NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
+          instantiate_cache=MagickTrue;
+        }
+      UnlockSemaphoreInfo(cache_semaphore);
+    }
+  (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
+  return((Cache ) cache_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e P i x e l C a c h e N e x u s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquirePixelCacheNexus() allocates the NexusInfo structure.
+%
+%  The format of the AcquirePixelCacheNexus method is:
+%
+%      NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
+%
+%  A description of each parameter follows:
+%
+%    o number_threads: the number of nexus threads.
+%
+*/
+MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
+{
+  NexusInfo
+    **nexus_info;
+
+  register ssize_t
+    i;
+
+  nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
+    sizeof(*nexus_info));
+  if (nexus_info == (NexusInfo **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
+    if (nexus_info[i] == (NexusInfo *) NULL)
+      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+    (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
+    nexus_info[i]->signature=MagickSignature;
+  }
+  return(nexus_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e P i x e l C a c h e P i x e l s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquirePixelCachePixels() returns the pixels associated with the specified
+%  image.
+%
+%  The format of the AcquirePixelCachePixels() method is:
+%
+%      const void *AcquirePixelCachePixels(const Image *image,
+%        MagickSizeType *length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o length: the pixel cache length.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const void *AcquirePixelCachePixels(const Image *image,
+  MagickSizeType *length,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  *length=0;
+  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
+    return((const void *) NULL);
+  *length=cache_info->length;
+  return((const void *) cache_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C a c h e C o m p o n e n t G e n e s i s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CacheComponentGenesis() instantiates the cache component.
+%
+%  The format of the CacheComponentGenesis method is:
+%
+%      MagickBooleanType CacheComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType CacheComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&cache_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C a c h e C o m p o n e n t T e r m i n u s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CacheComponentTerminus() destroys the cache component.
+%
+%  The format of the CacheComponentTerminus() method is:
+%
+%      CacheComponentTerminus(void)
+%
+*/
+MagickExport void CacheComponentTerminus(void)
+{
+  if (cache_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&cache_semaphore);
+  LockSemaphoreInfo(cache_semaphore);
+  if (cache_resources != (SplayTreeInfo *) NULL)
+    cache_resources=DestroySplayTree(cache_resources);
+  instantiate_cache=MagickFalse;
+  UnlockSemaphoreInfo(cache_semaphore);
+  DestroySemaphoreInfo(&cache_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l i p P i x e l C a c h e N e x u s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
+%  mask.  It returns MagickTrue if the pixel region is clipped, otherwise
+%  MagickFalse.
+%
+%  The format of the ClipPixelCacheNexus() method is:
+%
+%      MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o nexus_info: the cache nexus to clip.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType ClipPixelCacheNexus(Image *image,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickSizeType
+    number_pixels;
+
+  NexusInfo
+    **clip_nexus,
+    **image_nexus;
+
+  register const Quantum
+    *restrict p,
+    *restrict r;
+
+  register Quantum
+    *restrict q;
+
+  register ssize_t
+    i;
+
+  /*
+    Apply clip mask.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->clip_mask == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) image->cache;
+  if (cache_info == (Cache) NULL)
+    return(MagickFalse);
+  image_nexus=AcquirePixelCacheNexus(1);
+  clip_nexus=AcquirePixelCacheNexus(1);
+  if ((image_nexus == (NexusInfo **) NULL) ||
+      (clip_nexus == (NexusInfo **) NULL))
+    ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
+  p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
+    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
+    nexus_info->region.height,image_nexus[0],exception);
+  q=nexus_info->pixels;
+  r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
+    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
+    nexus_info->region.height,clip_nexus[0],exception);
+  number_pixels=(MagickSizeType) nexus_info->region.width*
+    nexus_info->region.height;
+  for (i=0; i < (ssize_t) number_pixels; i++)
+  {
+    if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
+      break;
+    if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
+      {
+        SetPixelRed(image,GetPixelRed(image,p),q);
+        SetPixelGreen(image,GetPixelGreen(image,p),q);
+        SetPixelBlue(image,GetPixelBlue(image,p),q);
+        if (cache_info->colorspace == CMYKColorspace)
+          SetPixelBlack(image,GetPixelBlack(image,p),q);
+        SetPixelAlpha(image,GetPixelAlpha(image,p),q);
+      }
+    p+=GetPixelChannels(image);
+    q+=GetPixelChannels(image);
+    r+=GetPixelChannels(image->clip_mask);
+  }
+  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
+  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
+  if (i < (ssize_t) number_pixels)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o n e P i x e l C a c h e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClonePixelCache() clones a pixel cache.
+%
+%  The format of the ClonePixelCache() method is:
+%
+%      Cache ClonePixelCache(const Cache cache)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+*/
+MagickExport Cache ClonePixelCache(const Cache cache)
+{
+  CacheInfo
+    *clone_info;
+
+  const CacheInfo
+    *cache_info;
+
+  assert(cache != (const Cache) NULL);
+  cache_info=(const CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
+  if (clone_info == (Cache) NULL)
+    return((Cache) NULL);
+  clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
+  return((Cache ) clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o n e P i x e l C a c h e P i x e l s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
+%  ClonePixelCachePixels() clones the source pixel cache to the destination
+%  cache.
+%
+%  The format of the ClonePixelCachePixels() method is:
+%
+%      MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
+%        CacheInfo *source_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_info: the pixel cache.
+%
+%    o source_info: the source pixel cache.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
+{
+  int
+    status;
+
+  status=(-1);
+  LockSemaphoreInfo(cache_info->disk_semaphore);
+  if (cache_info->file != -1)
+    {
+      status=close(cache_info->file);
+      cache_info->file=(-1);
+      RelinquishMagickResource(FileResource,1);
+    }
+  UnlockSemaphoreInfo(cache_info->disk_semaphore);
+  return(status == -1 ? MagickFalse : MagickTrue);
+}
+
+static void LimitPixelCacheDescriptors(void)
+{
+  register CacheInfo
+    *p,
+    *q;
+
+  /*
+    Limit # of open file descriptors.
+  */
+  if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
+    return;
+  LockSemaphoreInfo(cache_semaphore);
+  if (cache_resources == (SplayTreeInfo *) NULL)
+    {
+      UnlockSemaphoreInfo(cache_semaphore);
+      return;
+    }
+  ResetSplayTreeIterator(cache_resources);
+  p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
+  while (p != (CacheInfo *) NULL)
+  {
+    if ((p->type == DiskCache) && (p->file != -1))
+      break;
+    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
+  }
+  for (q=p; p != (CacheInfo *) NULL; )
+  {
+    if ((p->type == DiskCache) && (p->file != -1) &&
+        (p->timestamp < q->timestamp))
+      q=p;
+    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
+  }
+  if (q != (CacheInfo *) NULL)
+    {
+      /*
+        Close least recently used cache.
+      */
+      (void) close(q->file);
+      q->file=(-1);
+    }
+  UnlockSemaphoreInfo(cache_semaphore);
+}
+
+static inline MagickSizeType MagickMax(const MagickSizeType x,
+  const MagickSizeType y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline MagickSizeType MagickMin(const MagickSizeType x,
+  const MagickSizeType y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
+  const MapMode mode)
+{
+  int
+    file;
+
+  /*
+    Open pixel cache on disk.
+  */
+  LockSemaphoreInfo(cache_info->disk_semaphore);
+  if (cache_info->file != -1)
+    {
+      UnlockSemaphoreInfo(cache_info->disk_semaphore);
+      return(MagickTrue);  /* cache already open */
+    }
+  LimitPixelCacheDescriptors();
+  if (*cache_info->cache_filename == '\0')
+    file=AcquireUniqueFileResource(cache_info->cache_filename);
+  else
+    switch (mode)
+    {
+      case ReadMode:
+      {
+        file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
+        break;
+      }
+      case WriteMode:
+      {
+        file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
+          O_EXCL,S_MODE);
+        if (file == -1)
+          file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
+        break;
+      }
+      case IOMode:
+      default:
+      {
+        file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
+          O_EXCL,S_MODE);
+        if (file == -1)
+          file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
+        break;
+      }
+    }
+  if (file == -1)
+    {
+      UnlockSemaphoreInfo(cache_info->disk_semaphore);
+      return(MagickFalse);
+    }
+  (void) AcquireMagickResource(FileResource,1);
+  cache_info->file=file;
+  cache_info->timestamp=time(0);
+  UnlockSemaphoreInfo(cache_info->disk_semaphore);
+  return(MagickTrue);
+}
+
+static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
+  const MagickOffsetType offset,const MagickSizeType length,
+  unsigned char *restrict buffer)
+{
+  register MagickOffsetType
+    i;
+
+  ssize_t
+    count;
+
+  cache_info->timestamp=time(0);
+#if !defined(MAGICKCORE_HAVE_PREAD)
+  LockSemaphoreInfo(cache_info->disk_semaphore);
+  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
+    {
+      UnlockSemaphoreInfo(cache_info->disk_semaphore);
+      return((MagickOffsetType) -1);
+    }
+#endif
+  count=0;
+  for (i=0; i < (MagickOffsetType) length; i+=count)
+  {
+#if !defined(MAGICKCORE_HAVE_PREAD)
+    count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
+      (MagickSizeType) SSIZE_MAX));
+#else
+    count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
+      (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
+#endif
+    if (count > 0)
+      continue;
+    count=0;
+    if (errno != EINTR)
+      {
+        i=(-1);
+        break;
+      }
+  }
+#if !defined(MAGICKCORE_HAVE_PREAD)
+  UnlockSemaphoreInfo(cache_info->disk_semaphore);
+#endif
+  return(i);
+}
+
+static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
+  const MagickOffsetType offset,const MagickSizeType length,
+  const unsigned char *restrict buffer)
+{
+  register MagickOffsetType
+    i;
+
+  ssize_t
+    count;
+
+  cache_info->timestamp=time(0);
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+  LockSemaphoreInfo(cache_info->disk_semaphore);
+  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
+    {
+      UnlockSemaphoreInfo(cache_info->disk_semaphore);
+      return((MagickOffsetType) -1);
+    }
+#endif
+  count=0;
+  for (i=0; i < (MagickOffsetType) length; i+=count)
+  {
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+    count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
+      (MagickSizeType) SSIZE_MAX));
+#else
+    count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
+      (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
+#endif
+    if (count > 0)
+      continue;
+    count=0;
+    if (errno != EINTR)
+      {
+        i=(-1);
+        break;
+      }
+  }
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+  UnlockSemaphoreInfo(cache_info->disk_semaphore);
+#endif
+  return(i);
+}
+
+static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count;
+
+  register MagickOffsetType
+    i;
+
+  size_t
+    length;
+
+  unsigned char
+    *blob;
+
+  /*
+    Clone pixel cache (both caches on disk).
+  */
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
+  blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
+    sizeof(*blob));
+  if (blob == (unsigned char *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        cache_info->filename);
+      return(MagickFalse);
+    }
+  if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
+    {
+      blob=(unsigned char *) RelinquishMagickMemory(blob);
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        cache_info->cache_filename);
+      return(MagickFalse);
+    }
+  if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
+    {
+      (void) ClosePixelCacheOnDisk(cache_info);
+      blob=(unsigned char *) RelinquishMagickMemory(blob);
+      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+        clone_info->cache_filename);
+      return(MagickFalse);
+    }
+  count=0;
+  for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
+  {
+    count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
+      MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
+      blob);
+    if (count <= 0)
+      {
+        ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
+          cache_info->cache_filename);
+        break;
+      }
+    length=(size_t) count;
+    count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
+    if ((MagickSizeType) count != length)
+      {
+        ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+          clone_info->cache_filename);
+        break;
+      }
+  }
+  (void) ClosePixelCacheOnDisk(clone_info);
+  (void) ClosePixelCacheOnDisk(cache_info);
+  blob=(unsigned char *) RelinquishMagickMemory(blob);
+  if (i < (MagickOffsetType) cache_info->length)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count;
+
+  if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
+    {
+      /*
+        Clone pixel cache (both caches in memory).
+      */
+      if (cache_info->debug != MagickFalse)
+        (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
+      (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
+        cache_info->length);
+      return(MagickTrue);
+    }
+  if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
+    {
+      /*
+        Clone pixel cache (one cache on disk, one in memory).
+      */
+      if (cache_info->debug != MagickFalse)
+        (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
+      if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      count=ReadPixelCacheRegion(cache_info,cache_info->offset,
+        cache_info->length,(unsigned char *) clone_info->pixels);
+      (void) ClosePixelCacheOnDisk(cache_info);
+      if ((MagickSizeType) count != cache_info->length)
+        {
+          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      return(MagickTrue);
+    }
+  if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
+    {
+      /*
+        Clone pixel cache (one cache on disk, one in memory).
+      */
+      if (clone_info->debug != MagickFalse)
+        (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
+      if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            clone_info->cache_filename);
+          return(MagickFalse);
+        }
+      count=WritePixelCacheRegion(clone_info,clone_info->offset,
+        clone_info->length,(unsigned char *) cache_info->pixels);
+      (void) ClosePixelCacheOnDisk(clone_info);
+      if ((MagickSizeType) count != clone_info->length)
+        {
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            clone_info->cache_filename);
+          return(MagickFalse);
+        }
+      return(MagickTrue);
+    }
+  /*
+    Clone pixel cache (both caches on disk).
+  */
+  return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
+}
+
+static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    cache_offset,
+    clone_offset,
+    count;
+
+  register ssize_t
+    x;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  unsigned char
+    *blob;
+
+  /*
+    Clone pixel cache (unoptimized).
+  */
+  if (cache_info->debug != MagickFalse)
+    {
+      if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
+        (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
+      else
+       if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
+         (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
+       else
+         if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
+           (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
+         else
+           (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
+    }
+  length=(size_t) MagickMax(MagickMax(cache_info->pixel_channels,
+    clone_info->pixel_channels)*sizeof(Quantum),MagickMax(
+    cache_info->metacontent_extent,clone_info->metacontent_extent));
+  blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
+  if (blob == (unsigned char *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        cache_info->filename);
+      return(MagickFalse);
+    }
+  (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
+  cache_offset=0;
+  clone_offset=0;
+  if (cache_info->type == DiskCache)
+    {
+      if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
+        {
+          blob=(unsigned char *) RelinquishMagickMemory(blob);
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      cache_offset=cache_info->offset;
+    }
+  if (clone_info->type == DiskCache)
+    {
+      if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
+        {
+          if (cache_info->type == DiskCache)
+            (void) ClosePixelCacheOnDisk(cache_info);
+          blob=(unsigned char *) RelinquishMagickMemory(blob);
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            clone_info->cache_filename);
+          return(MagickFalse);
+        }
+      clone_offset=clone_info->offset;
+    }
+  /*
+    Clone pixel channels.
+  */
+  status=MagickTrue;
+  for (y=0; y < (ssize_t) cache_info->rows; y++)
+  {
+    for (x=0; x < (ssize_t) cache_info->columns; x++)
+    {
+      /*
+        Read a set of pixel channels.
+      */
+      length=cache_info->pixel_channels*sizeof(Quantum);
+      if (cache_info->type != DiskCache)
+        (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
+          length);
+      else
+        {
+          count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
+          if ((MagickSizeType) count != length)
+            {
+              status=MagickFalse;
+              break;
+            }
+        }
+      cache_offset+=length;
+      if ((y < (ssize_t) clone_info->rows) &&
+          (x < (ssize_t) clone_info->columns))
+        {
+          /*
+            Write a set of pixel channels.
+          */
+          length=clone_info->pixel_channels*sizeof(Quantum);
+          if (clone_info->type != DiskCache)
+            (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
+              blob,length);
+          else
+            {
+              count=WritePixelCacheRegion(clone_info,clone_offset,length,
+                blob);
+              if ((MagickSizeType) count != length)
+                {
+                  status=MagickFalse;
+                  break;
+                }
+            }
+          clone_offset+=length;
+        }
+    }
+    length=clone_info->pixel_channels*sizeof(Quantum);
+    (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
+    for ( ; x < (ssize_t) clone_info->columns; x++)
+    {
+      /*
+        Set remaining columns with transparent pixel channels.
+      */
+      if (clone_info->type != DiskCache)
+        (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
+          length);
+      else
+        {
+          count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
+          if ((MagickSizeType) count != length)
+            {
+              status=MagickFalse;
+              break;
+            }
+        }
+      clone_offset+=length;
+    }
+  }
+  length=clone_info->pixel_channels*sizeof(Quantum);
+  (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
+  for ( ; y < (ssize_t) clone_info->rows; y++)
+  {
+    /*
+      Set remaining rows with transparent pixels.
+    */
+    for (x=0; x < (ssize_t) clone_info->columns; x++)
+    {
+      if (clone_info->type != DiskCache)
+        (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
+          length);
+      else
+        {
+          count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
+          if ((MagickSizeType) count != length)
+            {
+              status=MagickFalse;
+              break;
+            }
+        }
+      clone_offset+=length;
+    }
+  }
+  if ((cache_info->metacontent_extent != 0) &&
+      (clone_info->metacontent_extent != 0))
+    {
+      /*
+        Clone metacontent.
+      */
+      for (y=0; y < (ssize_t) cache_info->rows; y++)
+      {
+        for (x=0; x < (ssize_t) cache_info->columns; x++)
+        {
+          /*
+            Read a set of metacontent.
+          */
+          length=cache_info->metacontent_extent;
+          if (cache_info->type != DiskCache)
+            (void) memcpy(blob,(unsigned char *) cache_info->pixels+
+              cache_offset,length);
+          else
+            {
+              count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
+              if ((MagickSizeType) count != length)
+                {
+                  status=MagickFalse;
+                  break;
+                }
+            }
+          cache_offset+=length;
+          if ((y < (ssize_t) clone_info->rows) &&
+              (x < (ssize_t) clone_info->columns))
+            {
+              /*
+                Write a set of metacontent.
+              */
+              length=clone_info->metacontent_extent;
+              if (clone_info->type != DiskCache)
+                (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
+                  blob,length);
+              else
+                {
+                  count=WritePixelCacheRegion(clone_info,clone_offset,length,
+                    blob);
+                  if ((MagickSizeType) count != length)
+                    {
+                      status=MagickFalse;
+                      break;
+                    }
+                }
+              clone_offset+=length;
+            }
+        }
+        length=clone_info->metacontent_extent;
+        (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
+        for ( ; x < (ssize_t) clone_info->columns; x++)
+        {
+          /*
+            Set remaining columns with metacontent.
+          */
+          if (clone_info->type != DiskCache)
+            (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
+              blob,length);
+          else
+            {
+              count=WritePixelCacheRegion(clone_info,clone_offset,length,
+                blob);
+              if ((MagickSizeType) count != length)
+                {
+                  status=MagickFalse;
+                  break;
+                }
+            }
+          clone_offset+=length;
+        }
+      }
+      length=clone_info->metacontent_extent;
+      (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
+      for ( ; y < (ssize_t) clone_info->rows; y++)
+      {
+        /*
+          Set remaining rows with metacontent.
+        */
+        for (x=0; x < (ssize_t) clone_info->columns; x++)
+        {
+          if (clone_info->type != DiskCache)
+            (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
+              blob,length);
+          else
+            {
+              count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
+              if ((MagickSizeType) count != length)
+                {
+                  status=MagickFalse;
+                  break;
+                }
+            }
+          clone_offset+=length;
+        }
+      }
+    }
+  if (clone_info->type == DiskCache)
+    (void) ClosePixelCacheOnDisk(clone_info);
+  if (cache_info->type == DiskCache)
+    (void) ClosePixelCacheOnDisk(cache_info);
+  blob=(unsigned char *) RelinquishMagickMemory(blob);
+  return(status);
+}
+
+static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
+  CacheInfo *cache_info,ExceptionInfo *exception)
+{
+  if (cache_info->type == PingCache)
+    return(MagickTrue);
+  if ((cache_info->columns == clone_info->columns) &&
+      (cache_info->rows == clone_info->rows) &&
+      (cache_info->pixel_channels == clone_info->pixel_channels) &&
+      (cache_info->metacontent_extent == clone_info->metacontent_extent))
+    return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
+  return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o n e P i x e l C a c h e M e t h o d s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClonePixelCacheMethods() clones the pixel cache methods from one cache to
+%  another.
+%
+%  The format of the ClonePixelCacheMethods() method is:
+%
+%      void ClonePixelCacheMethods(Cache clone,const Cache cache)
+%
+%  A description of each parameter follows:
+%
+%    o clone: Specifies a pointer to a Cache structure.
+%
+%    o cache: the pixel cache.
+%
+*/
+MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
+{
+  CacheInfo
+    *cache_info,
+    *source_info;
+
+  assert(clone != (Cache) NULL);
+  source_info=(CacheInfo *) clone;
+  assert(source_info->signature == MagickSignature);
+  if (source_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      source_info->filename);
+  assert(cache != (Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  source_info->methods=cache_info->methods;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y I m a g e P i x e l C a c h e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImagePixelCache() deallocates memory associated with the pixel cache.
+%
+%  The format of the DestroyImagePixelCache() method is:
+%
+%      void DestroyImagePixelCache(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static void DestroyImagePixelCache(Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->cache == (void *) NULL)
+    return;
+  image->cache=DestroyPixelCache(image->cache);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y I m a g e P i x e l s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImagePixels() deallocates memory associated with the pixel cache.
+%
+%  The format of the DestroyImagePixels() method is:
+%
+%      void DestroyImagePixels(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DestroyImagePixels(Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
+    {
+      cache_info->methods.destroy_pixel_handler(image);
+      return;
+    }
+  image->cache=DestroyPixelCache(image->cache);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P i x e l C a c h e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPixelCache() deallocates memory associated with the pixel cache.
+%
+%  The format of the DestroyPixelCache() method is:
+%
+%      Cache DestroyPixelCache(Cache cache)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+*/
+
+static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
+{
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    {
+      if (cache_info->mapped == MagickFalse)
+        cache_info->pixels=(Quantum *) RelinquishMagickMemory(
+          cache_info->pixels);
+      else
+        cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
+          (size_t) cache_info->length);
+      RelinquishMagickResource(MemoryResource,cache_info->length);
+      break;
+    }
+    case MapCache:
+    {
+      cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
+        cache_info->length);
+      RelinquishMagickResource(MapResource,cache_info->length);
+    }
+    case DiskCache:
+    {
+      if (cache_info->file != -1)
+        (void) ClosePixelCacheOnDisk(cache_info);
+      RelinquishMagickResource(DiskResource,cache_info->length);
+      break;
+    }
+    default:
+      break;
+  }
+  cache_info->type=UndefinedCache;
+  cache_info->mapped=MagickFalse;
+  cache_info->metacontent=(void *) NULL;
+}
+
+MagickExport Cache DestroyPixelCache(Cache cache)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  LockSemaphoreInfo(cache_info->semaphore);
+  cache_info->reference_count--;
+  if (cache_info->reference_count != 0)
+    {
+      UnlockSemaphoreInfo(cache_info->semaphore);
+      return((Cache) NULL);
+    }
+  UnlockSemaphoreInfo(cache_info->semaphore);
+  if (cache_resources != (SplayTreeInfo *) NULL)
+    (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
+  if (cache_info->debug != MagickFalse)
+    {
+      char
+        message[MaxTextExtent];
+
+      (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
+        cache_info->filename);
+      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
+    }
+  if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
+      (cache_info->type != DiskCache)))
+    RelinquishPixelCachePixels(cache_info);
+  else
+    {
+      RelinquishPixelCachePixels(cache_info);
+      (void) RelinquishUniqueFileResource(cache_info->cache_filename);
+    }
+  *cache_info->cache_filename='\0';
+  if (cache_info->nexus_info != (NexusInfo **) NULL)
+    cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
+      cache_info->number_threads);
+  if (cache_info->random_info != (RandomInfo *) NULL)
+    cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
+  if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&cache_info->disk_semaphore);
+  if (cache_info->semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&cache_info->semaphore);
+  cache_info->signature=(~MagickSignature);
+  cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
+  cache=(Cache) NULL;
+  return(cache);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P i x e l C a c h e N e x u s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPixelCacheNexus() destroys a pixel cache nexus.
+%
+%  The format of the DestroyPixelCacheNexus() method is:
+%
+%      NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
+%        const size_t number_threads)
+%
+%  A description of each parameter follows:
+%
+%    o nexus_info: the nexus to destroy.
+%
+%    o number_threads: the number of nexus threads.
+%
+*/
+
+static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
+{
+  if (nexus_info->mapped == MagickFalse)
+    (void) RelinquishMagickMemory(nexus_info->cache);
+  else
+    (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
+  nexus_info->cache=(Quantum *) NULL;
+  nexus_info->pixels=(Quantum *) NULL;
+  nexus_info->metacontent=(void *) NULL;
+  nexus_info->length=0;
+  nexus_info->mapped=MagickFalse;
+}
+
+MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
+  const size_t number_threads)
+{
+  register ssize_t
+    i;
+
+  assert(nexus_info != (NexusInfo **) NULL);
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    if (nexus_info[i]->cache != (Quantum *) NULL)
+      RelinquishCacheNexusPixels(nexus_info[i]);
+    nexus_info[i]->signature=(~MagickSignature);
+    nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
+  }
+  nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
+  return(nexus_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t A u t h e n t i c M e t a c o n t e n t                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticMetacontent() returns the authentic metacontent corresponding
+%  with the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
+%  returned if the associated pixels are not available.
+%
+%  The format of the GetAuthenticMetacontent() method is:
+%
+%      void *GetAuthenticMetacontent(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void *GetAuthenticMetacontent(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  void
+    *metacontent;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.get_authentic_metacontent_from_handler !=
+      (GetAuthenticMetacontentFromHandler) NULL)
+    {
+      metacontent=cache_info->methods.
+        get_authentic_metacontent_from_handler(image);
+      return(metacontent);
+    }
+  assert(id < (int) cache_info->number_threads);
+  metacontent=GetPixelCacheNexusMetacontent(cache_info,
+    cache_info->nexus_info[id]);
+  return(metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticMetacontentFromCache() returns the meta-content corresponding
+%  with the last call to QueueAuthenticPixelsCache() or
+%  GetAuthenticPixelsCache().
+%
+%  The format of the GetAuthenticMetacontentFromCache() method is:
+%
+%      void *GetAuthenticMetacontentFromCache(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static void *GetAuthenticMetacontentFromCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  void
+    *metacontent;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  metacontent=GetPixelCacheNexusMetacontent(image->cache,
+    cache_info->nexus_info[id]);
+  return(metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c P i x e l C a c h e N e x u s                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
+%  disk pixel cache as defined by the geometry parameters.   A pointer to the
+%  pixels is returned if the pixels are transferred, otherwise a NULL is
+%  returned.
+%
+%  The format of the GetAuthenticPixelCacheNexus() method is:
+%
+%      Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o nexus_info: the cache nexus to return.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
+  NexusInfo *nexus_info)
+{
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    offset;
+
+  if (cache_info->type == PingCache)
+    return(MagickTrue);
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  status=nexus_info->pixels == (cache_info->pixels+offset*
+    cache_info->pixel_channels) ? MagickTrue : MagickFalse;
+  return(status);
+}
+
+MagickExport Quantum *GetAuthenticPixelCacheNexus(Image *image,
+  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  Quantum
+    *pixels;
+
+  /*
+    Transfer pixels from the cache.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
+  if (pixels == (Quantum *) NULL)
+    return((Quantum *) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+    return(pixels);
+  if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
+    return((Quantum *) NULL);
+  if (cache_info->metacontent_extent != 0)
+    if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
+      return((Quantum *) NULL);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c P i x e l s F r o m C a c h e                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixelsFromCache() returns the pixels associated with the last
+%  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
+%
+%  The format of the GetAuthenticPixelsFromCache() method is:
+%
+%      Quantum *GetAuthenticPixelsFromCache(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static Quantum *GetAuthenticPixelsFromCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t A u t h e n t i c P i x e l Q u e u e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixelQueue() returns the authentic pixels associated
+%  corresponding with the last call to QueueAuthenticPixels() or
+%  GetAuthenticPixels().
+%
+%  The format of the GetAuthenticPixelQueue() method is:
+%
+%      Quantum *GetAuthenticPixelQueue(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.get_authentic_pixels_from_handler !=
+       (GetAuthenticPixelsFromHandler) NULL)
+    return(cache_info->methods.get_authentic_pixels_from_handler(image));
+  assert(id < (int) cache_info->number_threads);
+  return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t A u t h e n t i c P i x e l s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixels() obtains a pixel region for read/write access. If the
+%  region is successfully accessed, a pointer to a Quantum array
+%  representing the region is returned, otherwise NULL is returned.
+%
+%  The returned pointer may point to a temporary working copy of the pixels
+%  or it may point to the original pixels in memory. Performance is maximized
+%  if the selected region is part of one row, or one or more full rows, since
+%  then there is opportunity to access the pixels in-place (without a copy)
+%  if the image is in memory, or in a memory-mapped file. The returned pointer
+%  must *never* be deallocated by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  Quantum.  If the image has corresponding metacontent,call
+%  GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
+%  meta-content corresponding to the region.  Once the Quantum array has
+%  been updated, the changes must be saved back to the underlying image using
+%  SyncAuthenticPixels() or they may be lost.
+%
+%  The format of the GetAuthenticPixels() method is:
+%
+%      Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.get_authentic_pixels_handler !=
+      (GetAuthenticPixelsHandler) NULL)
+    {
+      pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
+        rows,exception);
+      return(pixels);
+    }
+  assert(id < (int) cache_info->number_threads);
+  pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
+    cache_info->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c P i x e l s C a c h e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
+%  as defined by the geometry parameters.   A pointer to the pixels is returned
+%  if the pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the GetAuthenticPixelsCache() method is:
+%
+%      Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  if (cache_info == (Cache) NULL)
+    return((Quantum *) NULL);
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
+    cache_info->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e E x t e n t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageExtent() returns the extent of the pixels associated corresponding
+%  with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
+%
+%  The format of the GetImageExtent() method is:
+%
+%      MagickSizeType GetImageExtent(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickSizeType GetImageExtent(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e P i x e l C a c h e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImagePixelCache() ensures that there is only a single reference to the
+%  pixel cache to be modified, updating the provided cache pointer to point to
+%  a clone of the original pixel cache if necessary.
+%
+%  The format of the GetImagePixelCache method is:
+%
+%      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o clone: any value other than MagickFalse clones the cache pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  /*
+    Does the image match the pixel cache morphology?
+  */
+  cache_info=(CacheInfo *) image->cache;
+  if ((image->storage_class != cache_info->storage_class) ||
+      (image->colorspace != cache_info->colorspace) ||
+      (image->columns != cache_info->columns) ||
+      (image->rows != cache_info->rows) ||
+      (image->pixel_channels != cache_info->pixel_channels) ||
+      (image->metacontent_extent != cache_info->metacontent_extent) ||
+      (cache_info->nexus_info == (NexusInfo **) NULL) ||
+      (cache_info->number_threads < GetOpenMPMaximumThreads()))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    destroy,
+    status;
+
+  static MagickSizeType
+    cpu_throttle = 0,
+    cycles = 0,
+    time_limit = 0;
+
+  static time_t
+    cache_genesis = 0;
+
+  status=MagickTrue;
+  LockSemaphoreInfo(image->semaphore);
+  if (cpu_throttle == 0)
+    {
+      char
+        *limit;
+
+      /*
+        Set CPU throttle in milleseconds.
+      */
+      cpu_throttle=MagickResourceInfinity;
+      limit=GetEnvironmentValue("MAGICK_THROTTLE");
+      if (limit == (char *) NULL)
+        limit=GetPolicyValue("throttle");
+      if (limit != (char *) NULL)
+        {
+          cpu_throttle=(MagickSizeType) StringToInteger(limit);
+          limit=DestroyString(limit);
+        }
+    }
+  if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
+    MagickDelay(cpu_throttle);
+  if (time_limit == 0)
+    {
+      /*
+        Set the exire time in seconds.
+      */
+      time_limit=GetMagickResourceLimit(TimeResource);
+      cache_genesis=time((time_t *) NULL);
+    }
+  if ((time_limit != MagickResourceInfinity) &&
+      ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
+    ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  destroy=MagickFalse;
+  if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
+    {
+      LockSemaphoreInfo(cache_info->semaphore);
+      if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
+        {
+          Image
+            clone_image;
+
+          CacheInfo
+            *clone_info;
+
+          /*
+            Clone pixel cache.
+          */
+          clone_image=(*image);
+          clone_image.semaphore=AllocateSemaphoreInfo();
+          clone_image.reference_count=1;
+          clone_image.cache=ClonePixelCache(cache_info);
+          clone_info=(CacheInfo *) clone_image.cache;
+          status=OpenPixelCache(&clone_image,IOMode,exception);
+          if (status != MagickFalse)
+            {
+              if (clone != MagickFalse)
+                status=ClonePixelCachePixels(clone_info,cache_info,exception);
+              if (status != MagickFalse)
+                {
+                  destroy=MagickTrue;
+                  image->cache=clone_image.cache;
+                }
+            }
+          DestroySemaphoreInfo(&clone_image.semaphore);
+        }
+      UnlockSemaphoreInfo(cache_info->semaphore);
+    }
+  if (destroy != MagickFalse)
+    cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
+  if (status != MagickFalse)
+    {
+      /*
+        Ensure the image matches the pixel cache morphology.
+      */
+      image->taint=MagickTrue;
+      image->type=UndefinedType;
+      if (image->colorspace == GRAYColorspace)
+        image->colorspace=RGBColorspace;
+      if (ValidatePixelCacheMorphology(image) == MagickFalse)
+        status=OpenPixelCache(image,IOMode,exception);
+    }
+  UnlockSemaphoreInfo(image->semaphore);
+  if (status == MagickFalse)
+    return((Cache) NULL);
+  return(image->cache);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e A u t h e n t i c P i x e l                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
+%  location.  The image background color is returned if an error occurs.
+%
+%  The format of the GetOneAuthenticPixel() method is:
+%
+%      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
+%        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  register Quantum
+    *q;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  *pixel=image->background_color;
+  if (cache_info->methods.get_one_authentic_pixel_from_handler !=
+       (GetOneAuthenticPixelFromHandler) NULL)
+    return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
+      pixel,exception));
+  q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
+  if (q == (Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,q,pixel);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t O n e A u t h e n t i c P i x e l F r o m C a c h e                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
+%  location.  The image background color is returned if an error occurs.
+%
+%  The format of the GetOneAuthenticPixelFromCache() method is:
+%
+%      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
+%        const ssize_t x,const ssize_t y,PixelPacket *pixel,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  register Quantum
+    *q;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  *pixel=image->background_color;
+  q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
+    exception);
+  if (q == (Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,q,pixel);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e V i r t u a l M a g i c k P i x e l                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
+%  location.  The image background color is returned if an error occurs.  If
+%  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
+%
+%  The format of the GetOneVirtualMagickPixel() method is:
+%
+%      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
+%        const ssize_t x,const ssize_t y,PixelInfo *pixel,
+%        ExceptionInfo exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y:  these values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
+  const ssize_t x,const ssize_t y,PixelInfo *pixel,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  register const Quantum
+    *pixels;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
+    1UL,1UL,cache_info->nexus_info[id],exception);
+  GetPixelInfo(image,pixel);
+  if (pixels == (const Quantum *) NULL)
+    return(MagickFalse);
+  SetPixelInfo(image,pixels,pixel);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e V i r t u a l M e t h o d P i x e l                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
+%  location as defined by specified pixel method.  The image background color
+%  is returned if an error occurs.  If you plan to modify the pixel, use
+%  GetOneAuthenticPixel() instead.
+%
+%  The format of the GetOneVirtualMethodPixel() method is:
+%
+%      MagickBooleanType GetOneVirtualMethodPixel(const Image image,
+%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
+%        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *p;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  *pixel=image->background_color;
+  if (cache_info->methods.get_one_virtual_pixel_from_handler !=
+       (GetOneVirtualPixelFromHandler) NULL)
+    return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
+      virtual_pixel_method,x,y,pixel,exception));
+  assert(id < (int) cache_info->number_threads);
+  p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
+    cache_info->nexus_info[id],exception);
+  if (p == (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,p,pixel);
+  if (image->colorspace == CMYKColorspace)
+    pixel->black=GetPixelBlack(image,p);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O n e V i r t u a l P i x e l                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneVirtualPixel() returns a single virtual pixel at the specified
+%  (x,y) location.  The image background color is returned if an error occurs.
+%  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
+%
+%  The format of the GetOneVirtualPixel() method is:
+%
+%      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
+%        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *p;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  *pixel=image->background_color;
+  if (cache_info->methods.get_one_virtual_pixel_from_handler !=
+       (GetOneVirtualPixelFromHandler) NULL)
+    return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
+      GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
+  assert(id < (int) cache_info->number_threads);
+  p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
+    1UL,1UL,cache_info->nexus_info[id],exception);
+  if (p == (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,p,pixel);
+  if (image->colorspace == CMYKColorspace)
+    pixel->black=GetPixelBlack(image,p);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t O n e V i r t u a l P i x e l F r o m C a c h e                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
+%  specified (x,y) location.  The image background color is returned if an
+%  error occurs.
+%
+%  The format of the GetOneVirtualPixelFromCache() method is:
+%
+%      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
+%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
+%        PixelPacket *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *p;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  *pixel=image->background_color;
+  p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
+    cache_info->nexus_info[id],exception);
+  if (p == (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,p,pixel);
+  if (image->colorspace == CMYKColorspace)
+    pixel->black=GetPixelBlack(image,p);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e C o l o r s p a c e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheColorspace() returns the class type of the pixel cache.
+%
+%  The format of the GetPixelCacheColorspace() method is:
+%
+%      Colorspace GetPixelCacheColorspace(Cache cache)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+*/
+MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  return(cache_info->colorspace);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e M e t h o d s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheMethods() initializes the CacheMethods structure.
+%
+%  The format of the GetPixelCacheMethods() method is:
+%
+%      void GetPixelCacheMethods(CacheMethods *cache_methods)
+%
+%  A description of each parameter follows:
+%
+%    o cache_methods: Specifies a pointer to a CacheMethods structure.
+%
+*/
+MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
+{
+  assert(cache_methods != (CacheMethods *) NULL);
+  (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
+  cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
+  cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
+  cache_methods->get_virtual_metacontent_from_handler=
+    GetVirtualMetacontentFromCache;
+  cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
+  cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
+  cache_methods->get_authentic_metacontent_from_handler=
+    GetAuthenticMetacontentFromCache;
+  cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
+  cache_methods->get_one_authentic_pixel_from_handler=
+    GetOneAuthenticPixelFromCache;
+  cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
+  cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
+  cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e N e x u s E x t e n t                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheNexusExtent() returns the extent of the pixels associated
+%  corresponding with the last call to SetPixelCacheNexusPixels() or
+%  GetPixelCacheNexusPixels().
+%
+%  The format of the GetPixelCacheNexusExtent() method is:
+%
+%      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
+%        NexusInfo *nexus_info)
+%
+%  A description of each parameter follows:
+%
+%    o nexus_info: the nexus info.
+%
+*/
+MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickSizeType
+    extent;
+
+  assert(cache != (const Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
+  if (extent == 0)
+    return((MagickSizeType) cache_info->columns*cache_info->rows);
+  return(extent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e N e x u s M e t a c o n t e n t                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheNexusMetacontent() returns the meta-content for the specified
+%  cache nexus.
+%
+%  The format of the GetPixelCacheNexusMetacontent() method is:
+%
+%      void *GetPixelCacheNexusMetacontent(const Cache cache,
+%        NexusInfo *nexus_info)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+%    o nexus_info: the cache nexus to return the meta-content.
+%
+*/
+MagickExport void *GetPixelCacheNexusMetacontent(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (const Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((void *) NULL);
+  return(nexus_info->metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e N e x u s P i x e l s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheNexusPixels() returns the pixels associated with the specified
+%  cache nexus.
+%
+%  The format of the GetPixelCacheNexusPixels() method is:
+%
+%      Quantum *GetPixelCacheNexusPixels(const Cache cache,
+%        NexusInfo *nexus_info)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+%    o nexus_info: the cache nexus to return the pixels.
+%
+*/
+MagickExport Quantum *GetPixelCacheNexusPixels(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (const Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((Quantum *) NULL);
+  return(nexus_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e P i x e l s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCachePixels() returns the pixels associated with the specified image.
+%
+%  The format of the GetPixelCachePixels() method is:
+%
+%      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o length: the pixel cache length.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  assert(length != (MagickSizeType *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  *length=0;
+  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
+    return((void *) NULL);
+  *length=cache_info->length;
+  return((void *) cache_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e S t o r a g e C l a s s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheStorageClass() returns the class type of the pixel cache.
+%
+%  The format of the GetPixelCacheStorageClass() method is:
+%
+%      ClassType GetPixelCacheStorageClass(Cache cache)
+%
+%  A description of each parameter follows:
+%
+%    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
+%
+%    o cache: the pixel cache.
+%
+*/
+MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  return(cache_info->storage_class);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e T i l e S i z e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheTileSize() returns the pixel cache tile size.
+%
+%  The format of the GetPixelCacheTileSize() method is:
+%
+%      void GetPixelCacheTileSize(const Image *image,size_t *width,
+%        size_t *height)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o width: the optimize cache tile width in pixels.
+%
+%    o height: the optimize cache tile height in pixels.
+%
+*/
+MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
+  size_t *height)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  *width=2048UL/(cache_info->pixel_channels*sizeof(Quantum));
+  if (GetPixelCacheType(image) == DiskCache)
+    *width=8192UL/(cache_info->pixel_channels*sizeof(Quantum));
+  *height=(*width);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e T y p e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
+%
+%  The format of the GetPixelCacheType() method is:
+%
+%      CacheType GetPixelCacheType(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport CacheType GetPixelCacheType(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  return(cache_info->type);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P i x e l C a c h e V i r t u a l M e t h o d                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
+%  pixel cache.  A virtual pixel is any pixel access that is outside the
+%  boundaries of the image cache.
+%
+%  The format of the GetPixelCacheVirtualMethod() method is:
+%
+%      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  return(cache_info->virtual_pixel_method);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualMetacontentFromCache() returns the meta-content corresponding with
+%  the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
+%
+%  The format of the GetVirtualMetacontentFromCache() method is:
+%
+%      void *GetVirtualMetacontentFromCache(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static const void *GetVirtualMetacontentFromCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const void
+    *metacontent;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  metacontent=GetVirtualMetacontentFromNexus(cache_info,
+    cache_info->nexus_info[id]);
+  return(metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualMetacontentFromNexus() returns the meta-content for the specified
+%  cache nexus.
+%
+%  The format of the GetVirtualMetacontentFromNexus() method is:
+%
+%      const void *GetVirtualMetacontentFromNexus(const Cache cache,
+%        NexusInfo *nexus_info)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+%    o nexus_info: the cache nexus to return the meta-content.
+%
+*/
+MagickExport const void *GetVirtualMetacontentFromNexus(
+  const Cache cache,NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((void *) NULL);
+  return(nexus_info->metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V i r t u a l M e t a c o n t e n t                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualMetacontent() returns the virtual metacontent corresponding with
+%  the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
+%  returned if the meta-content are not available.
+%
+%  The format of the GetVirtualMetacontent() method is:
+%
+%      const void *GetVirtualMetacontent(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const void *GetVirtualMetacontent(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const void
+    *metacontent;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.get_virtual_metacontent_from_handler !=
+       (GetVirtualMetacontentFromHandler) NULL)
+    {
+      metacontent=cache_info->methods.
+        get_virtual_metacontent_from_handler(image);
+      return(metacontent);
+    }
+  assert(id < (int) cache_info->number_threads);
+  metacontent=GetVirtualMetacontentFromNexus(cache_info,
+    cache_info->nexus_info[id]);
+  return(metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l P i x e l s F r o m N e x u s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
+%  pixel cache as defined by the geometry parameters.   A pointer to the pixels
+%  is returned if the pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the GetVirtualPixelsFromNexus() method is:
+%
+%      Quantum *GetVirtualPixelsFromNexus(const Image *image,
+%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
+%        const size_t columns,const size_t rows,NexusInfo *nexus_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o nexus_info: the cache nexus to acquire.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static ssize_t
+  DitherMatrix[64] =
+  {
+     0,  48,  12,  60,   3,  51,  15,  63,
+    32,  16,  44,  28,  35,  19,  47,  31,
+     8,  56,   4,  52,  11,  59,   7,  55,
+    40,  24,  36,  20,  43,  27,  39,  23,
+     2,  50,  14,  62,   1,  49,  13,  61,
+    34,  18,  46,  30,  33,  17,  45,  29,
+    10,  58,   6,  54,   9,  57,   5,  53,
+    42,  26,  38,  22,  41,  25,  37,  21
+  };
+
+static inline ssize_t DitherX(const ssize_t x,const size_t columns)
+{
+  ssize_t
+    index;
+
+  index=x+DitherMatrix[x & 0x07]-32L;
+  if (index < 0L)
+    return(0L);
+  if (index >= (ssize_t) columns)
+    return((ssize_t) columns-1L);
+  return(index);
+}
+
+static inline ssize_t DitherY(const ssize_t y,const size_t rows)
+{
+  ssize_t
+    index;
+
+  index=y+DitherMatrix[y & 0x07]-32L;
+  if (index < 0L)
+    return(0L);
+  if (index >= (ssize_t) rows)
+    return((ssize_t) rows-1L);
+  return(index);
+}
+
+static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
+{
+  if (x < 0L)
+    return(0L);
+  if (x >= (ssize_t) columns)
+    return((ssize_t) (columns-1));
+  return(x);
+}
+
+static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
+{
+  if (y < 0L)
+    return(0L);
+  if (y >= (ssize_t) rows)
+    return((ssize_t) (rows-1));
+  return(y);
+}
+
+static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
+{
+  return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
+}
+
+static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
+{
+  return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
+}
+
+/*
+  VirtualPixelModulo() computes the remainder of dividing offset by extent.  It
+  returns not only the quotient (tile the offset falls in) but also the positive
+  remainer within that tile such that 0 <= remainder < extent.  This method is
+  essentially a ldiv() using a floored modulo division rather than the normal
+  default truncated modulo division.
+*/
+static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
+  const size_t extent)
+{
+  MagickModulo
+    modulo;
+
+  modulo.quotient=offset/(ssize_t) extent;
+  if (offset < 0L)
+    modulo.quotient--;
+  modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
+  return(modulo);
+}
+
+MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
+  const size_t columns,const size_t rows,NexusInfo *nexus_info,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  NexusInfo
+    **virtual_nexus;
+
+  Quantum
+    *pixels,
+    *virtual_pixel;
+
+  RectangleInfo
+    region;
+
+  register const Quantum
+    *restrict p;
+
+  register const void
+    *restrict r;
+
+  register Quantum
+    *restrict q;
+
+  register ssize_t
+    u,
+    v;
+
+  register unsigned char
+    *restrict s;
+
+  void
+    *virtual_associated_pixel;
+
+  /*
+    Acquire pixels.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->type == UndefinedCache)
+    return((const Quantum *) NULL);
+  region.x=x;
+  region.y=y;
+  region.width=columns;
+  region.height=rows;
+  pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
+  if (pixels == (Quantum *) NULL)
+    return((const Quantum *) NULL);
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
+    nexus_info->region.width-1L;
+  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+  if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
+    if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
+        (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
+      {
+        MagickBooleanType
+          status;
+
+        /*
+          Pixel request is inside cache extents.
+        */
+        if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+          return(pixels);
+        status=ReadPixelCachePixels(cache_info,nexus_info,exception);
+        if (status == MagickFalse)
+          return((const Quantum *) NULL);
+        if (cache_info->metacontent_extent != 0)
+          {
+            status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
+            if (status == MagickFalse)
+              return((const Quantum *) NULL);
+          }
+        return(pixels);
+      }
+  /*
+    Pixel request is outside cache extents.
+  */
+  q=pixels;
+  s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
+  virtual_nexus=AcquirePixelCacheNexus(1);
+  if (virtual_nexus == (NexusInfo **) NULL)
+    {
+      if (virtual_nexus != (NexusInfo **) NULL)
+        virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "UnableToGetCacheNexus","`%s'",image->filename);
+      return((const Quantum *) NULL);
+    }
+  virtual_pixel=(Quantum *) NULL;
+  virtual_associated_pixel=(void *) NULL;
+  switch (virtual_pixel_method)
+  {
+    case BackgroundVirtualPixelMethod:
+    case BlackVirtualPixelMethod:
+    case GrayVirtualPixelMethod:
+    case TransparentVirtualPixelMethod:
+    case MaskVirtualPixelMethod:
+    case WhiteVirtualPixelMethod:
+    case EdgeVirtualPixelMethod:
+    case CheckerTileVirtualPixelMethod:
+    case HorizontalTileVirtualPixelMethod:
+    case VerticalTileVirtualPixelMethod:
+    {
+      /*
+        Acquire virtual pixel and associated channels.
+      */
+      virtual_pixel=(Quantum *) AcquireQuantumMemory(
+        cache_info->pixel_channels,sizeof(*virtual_pixel));
+      if (virtual_pixel == (Quantum *) NULL)
+        {
+          virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
+          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+            "UnableToGetCacheNexus","`%s'",image->filename);
+          return((const Quantum *) NULL);
+        }
+      (void) ResetMagickMemory(virtual_pixel,0,cache_info->pixel_channels*
+        sizeof(*virtual_pixel));
+      if (cache_info->metacontent_extent != 0)
+        {
+          virtual_associated_pixel=(void *) AcquireMagickMemory(
+            cache_info->metacontent_extent);
+          if (virtual_associated_pixel == (void *) NULL)
+            {
+              virtual_pixel=(Quantum *) RelinquishMagickMemory(
+                virtual_pixel);
+              virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
+              return((const Quantum *) NULL);
+            }
+          (void) ResetMagickMemory(virtual_associated_pixel,0,
+            cache_info->metacontent_extent);
+        }
+      switch (virtual_pixel_method)
+      {
+        case BlackVirtualPixelMethod:
+        {
+          SetPixelRed(image,0,virtual_pixel);
+          SetPixelGreen(image,0,virtual_pixel);
+          SetPixelBlue(image,0,virtual_pixel);
+          SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
+          break;
+        }
+        case GrayVirtualPixelMethod:
+        {
+          SetPixelRed(image,QuantumRange/2,virtual_pixel);
+          SetPixelGreen(image,QuantumRange/2,virtual_pixel);
+          SetPixelBlue(image,QuantumRange/2,virtual_pixel);
+          SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
+          break;
+        }
+        case TransparentVirtualPixelMethod:
+        {
+          SetPixelRed(image,0,virtual_pixel);
+          SetPixelGreen(image,0,virtual_pixel);
+          SetPixelBlue(image,0,virtual_pixel);
+          SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
+          break;
+        }
+        case MaskVirtualPixelMethod:
+        case WhiteVirtualPixelMethod:
+        {
+          SetPixelRed(image,(Quantum) QuantumRange,virtual_pixel);
+          SetPixelGreen(image,(Quantum) QuantumRange,virtual_pixel);
+          SetPixelBlue(image,(Quantum) QuantumRange,virtual_pixel);
+          SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
+          break;
+        }
+        default:
+        {
+          SetPixelRed(image,image->background_color.red,virtual_pixel);
+          SetPixelGreen(image,image->background_color.green,virtual_pixel);
+          SetPixelBlue(image,image->background_color.blue,virtual_pixel);
+          SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
+          break;
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  for (v=0; v < (ssize_t) rows; v++)
+  {
+    for (u=0; u < (ssize_t) columns; u+=length)
+    {
+      length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
+      if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
+          (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
+          (length == 0))
+        {
+          MagickModulo
+            x_modulo,
+            y_modulo;
+
+          /*
+            Transfer a single pixel.
+          */
+          length=(MagickSizeType) 1;
+          switch (virtual_pixel_method)
+          {
+            default:
+            {
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
+                1UL,1UL,*virtual_nexus,exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case RandomVirtualPixelMethod:
+            {
+              if (cache_info->random_info == (RandomInfo *) NULL)
+                cache_info->random_info=AcquireRandomInfo();
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                RandomX(cache_info->random_info,cache_info->columns),
+                RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
+                *virtual_nexus,exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case DitherVirtualPixelMethod:
+            {
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
+                1UL,1UL,*virtual_nexus,exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case TileVirtualPixelMethod:
+            {
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
+                exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case MirrorVirtualPixelMethod:
+            {
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              if ((x_modulo.quotient & 0x01) == 1L)
+                x_modulo.remainder=(ssize_t) cache_info->columns-
+                  x_modulo.remainder-1L;
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              if ((y_modulo.quotient & 0x01) == 1L)
+                y_modulo.remainder=(ssize_t) cache_info->rows-
+                  y_modulo.remainder-1L;
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
+                exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case HorizontalTileEdgeVirtualPixelMethod:
+            {
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
+                *virtual_nexus,exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case VerticalTileEdgeVirtualPixelMethod:
+            {
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
+                *virtual_nexus,exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case BackgroundVirtualPixelMethod:
+            case BlackVirtualPixelMethod:
+            case GrayVirtualPixelMethod:
+            case TransparentVirtualPixelMethod:
+            case MaskVirtualPixelMethod:
+            case WhiteVirtualPixelMethod:
+            {
+              p=virtual_pixel;
+              r=virtual_associated_pixel;
+              break;
+            }
+            case EdgeVirtualPixelMethod:
+            case CheckerTileVirtualPixelMethod:
+            {
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
+                {
+                  p=virtual_pixel;
+                  r=virtual_associated_pixel;
+                  break;
+                }
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
+                exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case HorizontalTileVirtualPixelMethod:
+            {
+              if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
+                {
+                  p=virtual_pixel;
+                  r=virtual_associated_pixel;
+                  break;
+                }
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
+                exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+            case VerticalTileVirtualPixelMethod:
+            {
+              if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
+                {
+                  p=virtual_pixel;
+                  r=virtual_associated_pixel;
+                  break;
+                }
+              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
+              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
+              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
+                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
+                exception);
+              r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+              break;
+            }
+          }
+          if (p == (const Quantum *) NULL)
+            break;
+          (void) memcpy(q,p,(size_t) length*cache_info->pixel_channels*
+            sizeof(*p));
+          q+=cache_info->pixel_channels;
+          if ((s != (void *) NULL) &&
+              (r != (const void *) NULL))
+            {
+              (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
+              s+=cache_info->metacontent_extent;
+            }
+          continue;
+        }
+      /*
+        Transfer a run of pixels.
+      */
+      p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
+        length,1UL,*virtual_nexus,exception);
+      if (p == (const Quantum *) NULL)
+        break;
+      r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
+      (void) memcpy(q,p,(size_t) length*cache_info->pixel_channels*sizeof(*p));
+      q+=length*cache_info->pixel_channels;
+      if ((s != (void *) NULL) && (r != (const void *) NULL))
+        {
+          (void) memcpy(s,r,(size_t) length);
+          s+=length*cache_info->metacontent_extent;
+        }
+    }
+  }
+  /*
+    Free resources.
+  */
+  if (virtual_associated_pixel != (void *) NULL)
+    virtual_associated_pixel=(void *) RelinquishMagickMemory(
+      virtual_associated_pixel);
+  if (virtual_pixel != (Quantum *) NULL)
+    virtual_pixel=(Quantum *) RelinquishMagickMemory(virtual_pixel);
+  virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l P i x e l C a c h e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
+%  cache as defined by the geometry parameters.   A pointer to the pixels
+%  is returned if the pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the GetVirtualPixelCache() method is:
+%
+%      const Quantum *GetVirtualPixelCache(const Image *image,
+%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static const Quantum *GetVirtualPixelCache(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
+  const size_t columns,const size_t rows,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *pixels;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
+    cache_info->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V i r t u a l P i x e l Q u e u e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
+%  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
+%
+%  The format of the GetVirtualPixelQueue() method is:
+%
+%      const Quantum *GetVirtualPixelQueue(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.get_virtual_pixels_handler !=
+       (GetVirtualPixelsHandler) NULL)
+    return(cache_info->methods.get_virtual_pixels_handler(image));
+  assert(id < (int) cache_info->number_threads);
+  return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V i r t u a l P i x e l s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixels() returns an immutable pixel region. If the
+%  region is successfully accessed, a pointer to it is returned, otherwise
+%  NULL is returned.  The returned pointer may point to a temporary working
+%  copy of the pixels or it may point to the original pixels in memory.
+%  Performance is maximized if the selected region is part of one row, or one
+%  or more full rows, since there is opportunity to access the pixels in-place
+%  (without a copy) if the image is in memory, or in a memory-mapped file.  The
+%  returned pointer must *never* be deallocated by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
+%  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
+%  access the meta-content (of type void) corresponding to the the
+%  region.
+%
+%  If you plan to modify the pixels, use GetAuthenticPixels() instead.
+%
+%  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
+%  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
+%  GetCacheViewAuthenticPixels() instead.
+%
+%  The format of the GetVirtualPixels() method is:
+%
+%      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const Quantum *GetVirtualPixels(const Image *image,
+  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  const Quantum
+    *pixels;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.get_virtual_pixel_handler !=
+       (GetVirtualPixelHandler) NULL)
+    return(cache_info->methods.get_virtual_pixel_handler(image,
+      GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
+  assert(id < (int) cache_info->number_threads);
+  pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
+    columns,rows,cache_info->nexus_info[id],exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l P i x e l s F r o m C a c h e                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelsCache() returns the pixels associated corresponding with the
+%  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
+%
+%  The format of the GetVirtualPixelsCache() method is:
+%
+%      Quantum *GetVirtualPixelsCache(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static const Quantum *GetVirtualPixelsCache(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l P i x e l s N e x u s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelsNexus() returns the pixels associated with the specified
+%  cache nexus.
+%
+%  The format of the GetVirtualPixelsNexus() method is:
+%
+%      const Quantum *GetVirtualPixelsNexus(const Cache cache,
+%        NexusInfo *nexus_info)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+%    o nexus_info: the cache nexus to return the colormap pixels.
+%
+*/
+MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
+  NexusInfo *nexus_info)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (Cache) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->storage_class == UndefinedClass)
+    return((Quantum *) NULL);
+  return((const Quantum *) nexus_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M a s k P i x e l C a c h e N e x u s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
+%  The method returns MagickTrue if the pixel region is masked, otherwise
+%  MagickFalse.
+%
+%  The format of the MaskPixelCacheNexus() method is:
+%
+%      MagickBooleanType MaskPixelCacheNexus(Image *image,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o nexus_info: the cache nexus to clip.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline void MagickPixelCompositeMask(const PixelInfo *p,
+  const MagickRealType alpha,const PixelInfo *q,
+  const MagickRealType beta,PixelInfo *composite)
+{
+  MagickRealType
+    gamma;
+
+  if (alpha == TransparentAlpha)
+    {
+      *composite=(*q);
+      return;
+    }
+  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
+  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
+  composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
+  composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
+  if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
+    composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
+}
+
+static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  PixelInfo
+    alpha,
+    beta;
+
+  MagickSizeType
+    number_pixels;
+
+  NexusInfo
+    **clip_nexus,
+    **image_nexus;
+
+  register const Quantum
+    *restrict p,
+    *restrict r;
+
+  register Quantum
+    *restrict q;
+
+  register ssize_t
+    i;
+
+  /*
+    Apply clip mask.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->mask == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) image->cache;
+  if (cache_info == (Cache) NULL)
+    return(MagickFalse);
+  image_nexus=AcquirePixelCacheNexus(1);
+  clip_nexus=AcquirePixelCacheNexus(1);
+  if ((image_nexus == (NexusInfo **) NULL) ||
+      (clip_nexus == (NexusInfo **) NULL))
+    ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
+  p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
+    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
+    nexus_info->region.height,image_nexus[0],exception);
+  q=nexus_info->pixels;
+  r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
+    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
+    nexus_info->region.height,clip_nexus[0],&image->exception);
+  GetPixelInfo(image,&alpha);
+  GetPixelInfo(image,&beta);
+  number_pixels=(MagickSizeType) nexus_info->region.width*
+    nexus_info->region.height;
+  for (i=0; i < (ssize_t) number_pixels; i++)
+  {
+    if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
+      break;
+    SetPixelInfo(image,p,&alpha);
+    SetPixelInfo(image,q,&beta);
+    MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
+      &alpha,alpha.alpha,&beta);
+    SetPixelRed(image,ClampToQuantum(beta.red),q);
+    SetPixelGreen(image,ClampToQuantum(beta.green),q);
+    SetPixelBlue(image,ClampToQuantum(beta.blue),q);
+    if (cache_info->colorspace == CMYKColorspace)
+      SetPixelBlack(image,ClampToQuantum(beta.black),q);
+    SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
+    p++;
+    q++;
+    r++;
+  }
+  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
+  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
+  if (i < (ssize_t) number_pixels)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   O p e n P i x e l C a c h e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
+%  dimensions, allocating space for the image pixels and optionally the
+%  metacontent, and memory mapping the cache if it is disk based.  The cache
+%  nexus array is initialized as well.
+%
+%  The format of the OpenPixelCache() method is:
+%
+%      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o mode: ReadMode, WriteMode, or IOMode.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
+{
+  cache_info->mapped=MagickFalse;
+  cache_info->pixels=(Quantum *) AcquireMagickMemory((size_t)
+    cache_info->length);
+  if (cache_info->pixels == (Quantum *) NULL)
+    {
+      cache_info->mapped=MagickTrue;
+      cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
+        cache_info->length);
+    }
+}
+
+static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickOffsetType
+    count,
+    extent,
+    offset;
+
+  cache_info=(CacheInfo *) image->cache;
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        message[MaxTextExtent];
+
+      (void) FormatMagickSize(length,MagickFalse,format);
+      (void) FormatLocaleString(message,MaxTextExtent,
+        "extend %s (%s[%d], disk, %s)",cache_info->filename,
+        cache_info->cache_filename,cache_info->file,format);
+      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
+    }
+  if (length != (MagickSizeType) ((MagickOffsetType) length))
+    return(MagickFalse);
+  extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
+  if (extent < 0)
+    return(MagickFalse);
+  if ((MagickSizeType) extent >= length)
+    return(MagickTrue);
+  offset=(MagickOffsetType) length-1;
+  count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
+  return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
+}
+
+static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info,
+    source_info;
+
+  char
+    format[MaxTextExtent],
+    message[MaxTextExtent];
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  size_t
+    columns,
+    packet_size;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((image->columns == 0) || (image->rows == 0))
+    ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
+  DefinePixelComponentMap(image);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  source_info=(*cache_info);
+  source_info.file=(-1);
+  (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
+    image->filename,(double) GetImageIndexInList(image));
+  cache_info->storage_class=image->storage_class;
+  cache_info->colorspace=image->colorspace;
+  cache_info->mode=mode;
+  cache_info->rows=image->rows;
+  cache_info->columns=image->columns;
+  cache_info->pixel_channels=GetPixelChannels(image);
+  cache_info->metacontent_extent=image->metacontent_extent;
+  if (image->ping != MagickFalse)
+    {
+      cache_info->type=PingCache;
+      cache_info->pixels=(Quantum *) NULL;
+      cache_info->metacontent=(void *) NULL;
+      cache_info->length=0;
+      return(MagickTrue);
+    }
+  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+  packet_size=cache_info->pixel_channels*sizeof(Quantum);
+  if (image->metacontent_extent != 0)
+    packet_size+=cache_info->metacontent_extent;
+  length=number_pixels*packet_size;
+  columns=(size_t) (length/cache_info->rows/packet_size);
+  if (cache_info->columns != columns)
+    ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
+      image->filename);
+  cache_info->length=length;
+  if ((cache_info->type != UndefinedCache) &&
+      (cache_info->columns <= source_info.columns) &&
+      (cache_info->rows <= source_info.rows) &&
+      (cache_info->pixel_channels <= source_info.pixel_channels) &&
+      (cache_info->metacontent_extent <= source_info.metacontent_extent))
+    {
+      /*
+        Inline pixel cache clone optimization.
+      */
+      if ((cache_info->columns == source_info.columns) &&
+          (cache_info->rows == source_info.rows) &&
+          (cache_info->pixel_channels == source_info.pixel_channels) &&
+          (cache_info->metacontent_extent == source_info.metacontent_extent))
+        return(MagickTrue);
+      return(ClonePixelCachePixels(cache_info,&source_info,exception));
+    }
+  status=AcquireMagickResource(AreaResource,cache_info->length);
+  length=number_pixels*(cache_info->pixel_channels*sizeof(Quantum)+
+    cache_info->metacontent_extent);
+  if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
+    {
+      status=AcquireMagickResource(MemoryResource,cache_info->length);
+      if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
+          (cache_info->type == MemoryCache))
+        {
+          AllocatePixelCachePixels(cache_info);
+          if (cache_info->pixels == (Quantum *) NULL)
+            cache_info->pixels=source_info.pixels;
+          else
+            {
+              /*
+                Create memory pixel cache.
+              */
+              status=MagickTrue;
+              if (image->debug != MagickFalse)
+                {
+                  (void) FormatMagickSize(cache_info->length,MagickTrue,
+                    format);
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "open %s (%s memory, %.20gx%.20gx%.20g %s)",
+                    cache_info->filename,cache_info->mapped != MagickFalse ?
+                    "anonymous" : "heap",(double) cache_info->columns,(double)
+                    cache_info->rows,(double) cache_info->pixel_channels,
+                    format);
+                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
+                    message);
+                }
+              cache_info->type=MemoryCache;
+              cache_info->metacontent=(void *) NULL;
+              if (cache_info->metacontent_extent != 0)
+                cache_info->metacontent=(void *) (cache_info->pixels+
+                  number_pixels*cache_info->pixel_channels);
+              if (source_info.storage_class != UndefinedClass)
+                {
+                  status=ClonePixelCachePixels(cache_info,&source_info,
+                    exception);
+                  RelinquishPixelCachePixels(&source_info);
+                }
+              return(status);
+            }
+        }
+      RelinquishMagickResource(MemoryResource,cache_info->length);
+    }
+  /*
+    Create pixel cache on disk.
+  */
+  status=AcquireMagickResource(DiskResource,cache_info->length);
+  if (status == MagickFalse)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "CacheResourcesExhausted","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  if (cache_info->type == DiskCache)
+    {
+      (void) ClosePixelCacheOnDisk(cache_info);
+      *cache_info->cache_filename='\0';
+      status=DiskToDiskPixelCacheClone(cache_info,&source_info,exception);
+    }
+  if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
+    {
+      RelinquishMagickResource(DiskResource,cache_info->length);
+      ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
+        image->filename);
+      return(MagickFalse);
+    }
+  status=ExtendCache(image,(MagickSizeType) cache_info->offset+
+    cache_info->length);
+  if (status == MagickFalse)
+    {
+      ThrowFileException(exception,CacheError,"UnableToExtendCache",
+        image->filename);
+      return(MagickFalse);
+    }
+  length=number_pixels*(cache_info->pixel_channels*sizeof(Quantum)+
+    cache_info->metacontent_extent);
+  status=AcquireMagickResource(AreaResource,cache_info->length);
+  if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
+    cache_info->type=DiskCache;
+  else
+    {
+      status=AcquireMagickResource(MapResource,cache_info->length);
+      if ((status == MagickFalse) && (cache_info->type != MapCache) &&
+          (cache_info->type != MemoryCache))
+        cache_info->type=DiskCache;
+      else
+        {
+          cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
+            cache_info->offset,(size_t) cache_info->length);
+          if (cache_info->pixels == (Quantum *) NULL)
+            {
+              cache_info->type=DiskCache;
+              cache_info->pixels=source_info.pixels;
+            }
+          else
+            {
+              /*
+                Create file-backed memory-mapped pixel cache.
+              */
+              status=MagickTrue;
+              (void) ClosePixelCacheOnDisk(cache_info);
+              cache_info->type=MapCache;
+              cache_info->mapped=MagickTrue;
+              cache_info->metacontent=(void *) NULL;
+              if (cache_info->metacontent_extent != 0)
+                cache_info->metacontent=(void *) (cache_info->pixels+
+                  number_pixels*cache_info->pixel_channels);
+              if (source_info.storage_class != UndefinedClass)
+                {
+                  status=ClonePixelCachePixels(cache_info,&source_info,
+                    exception);
+                  RelinquishPixelCachePixels(&source_info);
+                }
+              if (image->debug != MagickFalse)
+                {
+                  (void) FormatMagickSize(cache_info->length,MagickTrue,
+                    format);
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
+                    cache_info->filename,cache_info->cache_filename,
+                    cache_info->file,(double) cache_info->columns,(double)
+                    cache_info->rows,(double) cache_info->pixel_channels,
+                    format);
+                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
+                    message);
+                }
+              return(status);
+            }
+        }
+      RelinquishMagickResource(MapResource,cache_info->length);
+    }
+  status=MagickTrue;
+  if ((source_info.type != UndefinedCache) && (mode != ReadMode))
+    {
+      status=ClonePixelCachePixels(cache_info,&source_info,exception);
+      RelinquishPixelCachePixels(&source_info);
+    }
+  if (image->debug != MagickFalse)
+    {
+      (void) FormatMagickSize(cache_info->length,MagickFalse,format);
+      (void) FormatLocaleString(message,MaxTextExtent,
+        "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
+        cache_info->cache_filename,cache_info->file,(double)
+        cache_info->columns,(double) cache_info->rows,(double)
+        cache_info->pixel_channels,format);
+      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
+    }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P e r s i s t P i x e l C a c h e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
+%  persistent pixel cache is one that resides on disk and is not destroyed
+%  when the program exits.
+%
+%  The format of the PersistPixelCache() method is:
+%
+%      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
+%        const MagickBooleanType attach,MagickOffsetType *offset,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o filename: the persistent pixel cache filename.
+%
+%    o attach: A value other than zero initializes the persistent pixel cache.
+%
+%    o initialize: A value other than zero initializes the persistent pixel
+%      cache.
+%
+%    o offset: the offset in the persistent cache to store pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType PersistPixelCache(Image *image,
+  const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info,
+    *clone_info;
+
+  Image
+    clone_image;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    page_size;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->cache != (void *) NULL);
+  assert(filename != (const char *) NULL);
+  assert(offset != (MagickOffsetType *) NULL);
+  page_size=GetMagickPageSize();
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (attach != MagickFalse)
+    {
+      /*
+        Attach existing persistent pixel cache.
+      */
+      if (image->debug != MagickFalse)
+        (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+          "attach persistent cache");
+      (void) CopyMagickString(cache_info->cache_filename,filename,
+        MaxTextExtent);
+      cache_info->type=DiskCache;
+      cache_info->offset=(*offset);
+      if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
+        return(MagickFalse);
+      *offset+=cache_info->length+page_size-(cache_info->length % page_size);
+      return(MagickTrue);
+    }
+  if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
+      (cache_info->reference_count == 1))
+    {
+      LockSemaphoreInfo(cache_info->semaphore);
+      if ((cache_info->mode != ReadMode) &&
+          (cache_info->type != MemoryCache) &&
+          (cache_info->reference_count == 1))
+        {
+          int
+            status;
+
+          /*
+            Usurp existing persistent pixel cache.
+          */
+          status=rename(cache_info->cache_filename,filename);
+          if (status == 0)
+            {
+              (void) CopyMagickString(cache_info->cache_filename,filename,
+                MaxTextExtent);
+              *offset+=cache_info->length+page_size-(cache_info->length %
+                page_size);
+              UnlockSemaphoreInfo(cache_info->semaphore);
+              cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
+              if (image->debug != MagickFalse)
+                (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+                  "Usurp resident persistent cache");
+              return(MagickTrue);
+            }
+        }
+      UnlockSemaphoreInfo(cache_info->semaphore);
+    }
+  /*
+    Clone persistent pixel cache.
+  */
+  clone_image=(*image);
+  clone_info=(CacheInfo *) clone_image.cache;
+  image->cache=ClonePixelCache(cache_info);
+  cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
+  (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
+  cache_info->type=DiskCache;
+  cache_info->offset=(*offset);
+  cache_info=(CacheInfo *) image->cache;
+  status=OpenPixelCache(image,IOMode,exception);
+  if (status != MagickFalse)
+    status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
+  *offset+=cache_info->length+page_size-(cache_info->length % page_size);
+  clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   Q u e u e A u t h e n t i c N e x u s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueueAuthenticNexus() allocates an region to store image pixels as defined
+%  by the region rectangle and returns a pointer to the region.  This region is
+%  subsequently transferred from the pixel cache with
+%  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
+%  pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the QueueAuthenticNexus() method is:
+%
+%      Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o nexus_info: the cache nexus to set.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    number_pixels;
+
+  RectangleInfo
+    region;
+
+  /*
+    Validate pixel cache geometry.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info == (Cache) NULL)
+    return((Quantum *) NULL);
+  if ((cache_info->columns == 0) && (cache_info->rows == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "NoPixelsDefinedInCache","`%s'",image->filename);
+      return((Quantum *) NULL);
+    }
+  if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
+      (y >= (ssize_t) cache_info->rows))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "PixelsAreNotAuthentic","`%s'",image->filename);
+      return((Quantum *) NULL);
+    }
+  offset=(MagickOffsetType) y*cache_info->columns+x;
+  if (offset < 0)
+    return((Quantum *) NULL);
+  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
+  offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
+  if ((MagickSizeType) offset >= number_pixels)
+    return((Quantum *) NULL);
+  /*
+    Return pixel cache.
+  */
+  region.x=x;
+  region.y=y;
+  region.width=columns;
+  region.height=rows;
+  return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   Q u e u e A u t h e n t i c P i x e l s C a c h e                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueueAuthenticPixelsCache() allocates an region to store image pixels as
+%  defined by the region rectangle and returns a pointer to the region.  This
+%  region is subsequently transferred from the pixel cache with
+%  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
+%  pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the QueueAuthenticPixelsCache() method is:
+%
+%      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
+    exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u e u e A u t h e n t i c P i x e l s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
+%  successfully initialized a pointer to a Quantum array representing the
+%  region is returned, otherwise NULL is returned.  The returned pointer may
+%  point to a temporary working buffer for the pixels or it may point to the
+%  final location of the pixels in memory.
+%
+%  Write-only access means that any existing pixel values corresponding to
+%  the region are ignored.  This is useful if the initial image is being
+%  created from scratch, or if the existing pixel values are to be
+%  completely replaced without need to refer to their pre-existing values.
+%  The application is free to read and write the pixel buffer returned by
+%  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
+%  initialize the pixel array values. Initializing pixel array values is the
+%  application's responsibility.
+%
+%  Performance is maximized if the selected region is part of one row, or
+%  one or more full rows, since then there is opportunity to access the
+%  pixels in-place (without a copy) if the image is in memory, or in a
+%  memory-mapped file. The returned pointer must *never* be deallocated
+%  by the user.
+%
+%  Pixels accessed via the returned pointer represent a simple array of type
+%  Quantum. If the image type is CMYK or the storage class is PseudoClass,
+%  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
+%  obtain the meta-content (of type void) corresponding to the region.
+%  Once the Quantum (and/or Quantum) array has been updated, the
+%  changes must be saved back to the underlying image using
+%  SyncAuthenticPixels() or they may be lost.
+%
+%  The format of the QueueAuthenticPixels() method is:
+%
+%      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  Quantum
+    *pixels;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.queue_authentic_pixels_handler !=
+       (QueueAuthenticPixelsHandler) NULL)
+    {
+      pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
+        columns,rows,exception);
+      return(pixels);
+    }
+  assert(id < (int) cache_info->number_threads);
+  pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
+    exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e a d P i x e l C a c h e M e t a c o n t e n t                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadPixelCacheMetacontent() reads metacontent from the specified region of
+%  the pixel cache.
+%
+%  The format of the ReadPixelCacheMetacontent() method is:
+%
+%      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_info: the pixel cache.
+%
+%    o nexus_info: the cache nexus to read the metacontent.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    extent,
+    length;
+
+  register ssize_t
+    y;
+
+  register unsigned char
+    *restrict q;
+
+  size_t
+    rows;
+
+  if (cache_info->metacontent_extent == 0)
+    return(MagickFalse);
+  if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+    return(MagickTrue);
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  length=(MagickSizeType) nexus_info->region.width*
+    cache_info->metacontent_extent;
+  rows=nexus_info->region.height;
+  extent=length*rows;
+  q=(unsigned char *) nexus_info->metacontent;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register unsigned char
+        *restrict p;
+
+      /*
+        Read meta-content from memory.
+      */
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent == (MagickSizeType) ((size_t) extent)))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      p=(unsigned char *) cache_info->metacontent+offset*
+        cache_info->metacontent_extent;
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        (void) memcpy(q,p,(size_t) length);
+        p+=cache_info->metacontent_extent*cache_info->columns;
+        q+=cache_info->metacontent_extent*nexus_info->region.width;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Read meta content from disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent <= MagickMaxBufferExtent))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      extent=(MagickSizeType) cache_info->columns*cache_info->rows;
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
+          cache_info->pixel_channels*sizeof(Quantum)+offset*
+          cache_info->metacontent_extent,length,(unsigned char *) q);
+        if ((MagickSizeType) count != length)
+          break;
+        offset+=cache_info->columns;
+        q+=cache_info->metacontent_extent*nexus_info->region.width;
+      }
+      if (y < (ssize_t) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
+      nexus_info->region.width,(double) nexus_info->region.height,(double)
+      nexus_info->region.x,(double) nexus_info->region.y);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e a d P i x e l C a c h e P i x e l s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadPixelCachePixels() reads pixels from the specified region of the pixel
+%  cache.
+%
+%  The format of the ReadPixelCachePixels() method is:
+%
+%      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_info: the pixel cache.
+%
+%    o nexus_info: the cache nexus to read the pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    extent,
+    length;
+
+  register Quantum
+    *restrict q;
+
+  register ssize_t
+    y;
+
+  size_t
+    rows;
+
+  if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+    return(MagickTrue);
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  length=(MagickSizeType) nexus_info->region.width*cache_info->pixel_channels*
+    sizeof(Quantum);
+  rows=nexus_info->region.height;
+  extent=length*rows;
+  q=nexus_info->pixels;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register Quantum
+        *restrict p;
+
+      /*
+        Read pixels from memory.
+      */
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent == (MagickSizeType) ((size_t) extent)))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      p=cache_info->pixels+offset*cache_info->pixel_channels;
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        (void) memcpy(q,p,(size_t) length);
+        p+=cache_info->pixel_channels*cache_info->columns;
+        q+=cache_info->pixel_channels*nexus_info->region.width;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Read pixels from disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent <= MagickMaxBufferExtent))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
+          cache_info->pixel_channels*sizeof(*q),length,(unsigned char *) q);
+        if ((MagickSizeType) count != length)
+          break;
+        offset+=cache_info->columns;
+        q+=cache_info->pixel_channels*nexus_info->region.width;
+      }
+      if (y < (ssize_t) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
+      nexus_info->region.width,(double) nexus_info->region.height,(double)
+      nexus_info->region.x,(double) nexus_info->region.y);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e f e r e n c e P i x e l C a c h e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReferencePixelCache() increments the reference count associated with the
+%  pixel cache returning a pointer to the cache.
+%
+%  The format of the ReferencePixelCache method is:
+%
+%      Cache ReferencePixelCache(Cache cache_info)
+%
+%  A description of each parameter follows:
+%
+%    o cache_info: the pixel cache.
+%
+*/
+MagickExport Cache ReferencePixelCache(Cache cache)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(cache != (Cache *) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  LockSemaphoreInfo(cache_info->semaphore);
+  cache_info->reference_count++;
+  UnlockSemaphoreInfo(cache_info->semaphore);
+  return(cache_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t P i x e l C a c h e M e t h o d s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
+%
+%  The format of the SetPixelCacheMethods() method is:
+%
+%      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
+%
+%  A description of each parameter follows:
+%
+%    o cache: the pixel cache.
+%
+%    o cache_methods: Specifies a pointer to a CacheMethods structure.
+%
+*/
+MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
+{
+  CacheInfo
+    *cache_info;
+
+  GetOneAuthenticPixelFromHandler
+    get_one_authentic_pixel_from_handler;
+
+  GetOneVirtualPixelFromHandler
+    get_one_virtual_pixel_from_handler;
+
+  /*
+    Set cache pixel methods.
+  */
+  assert(cache != (Cache) NULL);
+  assert(cache_methods != (CacheMethods *) NULL);
+  cache_info=(CacheInfo *) cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      cache_info->filename);
+  if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
+    cache_info->methods.get_virtual_pixel_handler=
+      cache_methods->get_virtual_pixel_handler;
+  if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
+    cache_info->methods.destroy_pixel_handler=
+      cache_methods->destroy_pixel_handler;
+  if (cache_methods->get_virtual_metacontent_from_handler !=
+      (GetVirtualMetacontentFromHandler) NULL)
+    cache_info->methods.get_virtual_metacontent_from_handler=
+      cache_methods->get_virtual_metacontent_from_handler;
+  if (cache_methods->get_authentic_pixels_handler !=
+      (GetAuthenticPixelsHandler) NULL)
+    cache_info->methods.get_authentic_pixels_handler=
+      cache_methods->get_authentic_pixels_handler;
+  if (cache_methods->queue_authentic_pixels_handler !=
+      (QueueAuthenticPixelsHandler) NULL)
+    cache_info->methods.queue_authentic_pixels_handler=
+      cache_methods->queue_authentic_pixels_handler;
+  if (cache_methods->sync_authentic_pixels_handler !=
+      (SyncAuthenticPixelsHandler) NULL)
+    cache_info->methods.sync_authentic_pixels_handler=
+      cache_methods->sync_authentic_pixels_handler;
+  if (cache_methods->get_authentic_pixels_from_handler !=
+      (GetAuthenticPixelsFromHandler) NULL)
+    cache_info->methods.get_authentic_pixels_from_handler=
+      cache_methods->get_authentic_pixels_from_handler;
+  if (cache_methods->get_authentic_metacontent_from_handler !=
+      (GetAuthenticMetacontentFromHandler) NULL)
+    cache_info->methods.get_authentic_metacontent_from_handler=
+      cache_methods->get_authentic_metacontent_from_handler;
+  get_one_virtual_pixel_from_handler=
+    cache_info->methods.get_one_virtual_pixel_from_handler;
+  if (get_one_virtual_pixel_from_handler !=
+      (GetOneVirtualPixelFromHandler) NULL)
+    cache_info->methods.get_one_virtual_pixel_from_handler=
+      cache_methods->get_one_virtual_pixel_from_handler;
+  get_one_authentic_pixel_from_handler=
+    cache_methods->get_one_authentic_pixel_from_handler;
+  if (get_one_authentic_pixel_from_handler !=
+      (GetOneAuthenticPixelFromHandler) NULL)
+    cache_info->methods.get_one_authentic_pixel_from_handler=
+      cache_methods->get_one_authentic_pixel_from_handler;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t P i x e l C a c h e N e x u s P i x e l s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetPixelCacheNexusPixels() defines the region of the cache for the
+%  specified cache nexus.
+%
+%  The format of the SetPixelCacheNexusPixels() method is:
+%
+%      Quantum SetPixelCacheNexusPixels(const Image *image,
+%        const RectangleInfo *region,NexusInfo *nexus_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o region: A pointer to the RectangleInfo structure that defines the
+%      region of this particular cache nexus.
+%
+%    o nexus_info: the cache nexus to set.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
+    return(MagickFalse);
+  nexus_info->mapped=MagickFalse;
+  nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
+    nexus_info->length);
+  if (nexus_info->cache == (Quantum *) NULL)
+    {
+      nexus_info->mapped=MagickTrue;
+      nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
+        nexus_info->length);
+    }
+  if (nexus_info->cache == (Quantum *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        cache_info->filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+static Quantum *SetPixelCacheNexusPixels(const Image *image,
+  const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    length,
+    number_pixels;
+
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->type == UndefinedCache)
+    return((Quantum *) NULL);
+  nexus_info->region=(*region);
+  if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
+      (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
+    {
+      ssize_t
+        x,
+        y;
+
+      x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
+      y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
+      if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
+           (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
+          ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
+           ((nexus_info->region.width == cache_info->columns) ||
+            ((nexus_info->region.width % cache_info->columns) == 0)))))
+        {
+          MagickOffsetType
+            offset;
+
+          /*
+            Pixels are accessed directly from memory.
+          */
+          offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+            nexus_info->region.x;
+          nexus_info->pixels=cache_info->pixels+cache_info->pixel_channels*
+            offset;
+          nexus_info->metacontent=(void *) NULL;
+          if (cache_info->metacontent_extent != 0)
+            nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
+              offset*cache_info->metacontent_extent;
+          return(nexus_info->pixels);
+        }
+    }
+  /*
+    Pixels are stored in a cache region until they are synced to the cache.
+  */
+  number_pixels=(MagickSizeType) nexus_info->region.width*
+    nexus_info->region.height;
+  length=number_pixels*cache_info->pixel_channels*sizeof(Quantum);
+  if (cache_info->metacontent_extent != 0)
+    length+=number_pixels*cache_info->metacontent_extent;
+  if (nexus_info->cache == (Quantum *) NULL)
+    {
+      nexus_info->length=length;
+      status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
+      if (status == MagickFalse)
+        {
+          nexus_info->length=0;
+          return((Quantum *) NULL);
+        }
+    }
+  else
+    if (nexus_info->length != length)
+      {
+        RelinquishCacheNexusPixels(nexus_info);
+        nexus_info->length=length;
+        status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
+        if (status == MagickFalse)
+          {
+            nexus_info->length=0;
+            return((Quantum *) NULL);
+          }
+      }
+  nexus_info->pixels=nexus_info->cache;
+  nexus_info->metacontent=(void *) NULL;
+  if (cache_info->metacontent_extent != 0)
+    nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
+      cache_info->pixel_channels);
+  return(nexus_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t P i x e l C a c h e V i r t u a l M e t h o d                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
+%  pixel cache and returns the previous setting.  A virtual pixel is any pixel
+%  access that is outside the boundaries of the image cache.
+%
+%  The format of the SetPixelCacheVirtualMethod() method is:
+%
+%      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
+%        const VirtualPixelMethod virtual_pixel_method)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: choose the type of virtual pixel.
+%
+*/
+MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method)
+{
+  CacheInfo
+    *cache_info;
+
+  VirtualPixelMethod
+    method;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  method=cache_info->virtual_pixel_method;
+  cache_info->virtual_pixel_method=virtual_pixel_method;
+  return(method);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S y n c A u t h e n t i c P i x e l C a c h e N e x u s                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
+%  in-memory or disk cache.  The method returns MagickTrue if the pixel region
+%  is synced, otherwise MagickFalse.
+%
+%  The format of the SyncAuthenticPixelCacheNexus() method is:
+%
+%      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o nexus_info: the cache nexus to sync.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Transfer pixels to the cache.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->cache == (Cache) NULL)
+    ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->type == UndefinedCache)
+    return(MagickFalse);
+  if ((image->clip_mask != (Image *) NULL) &&
+      (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
+    return(MagickFalse);
+  if ((image->mask != (Image *) NULL) &&
+      (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
+    return(MagickFalse);
+  if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+    return(MagickTrue);
+  assert(cache_info->signature == MagickSignature);
+  status=WritePixelCachePixels(cache_info,nexus_info,exception);
+  if ((cache_info->metacontent_extent != 0) &&
+      (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
+    return(MagickFalse);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S y n c A u t h e n t i c P i x e l C a c h e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
+%  or disk cache.  The method returns MagickTrue if the pixel region is synced,
+%  otherwise MagickFalse.
+%
+%  The format of the SyncAuthenticPixelsCache() method is:
+%
+%      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  assert(id < (int) cache_info->number_threads);
+  status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
+    exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c A u t h e n t i c P i x e l s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
+%  The method returns MagickTrue if the pixel region is flushed, otherwise
+%  MagickFalse.
+%
+%  The format of the SyncAuthenticPixels() method is:
+%
+%      MagickBooleanType SyncAuthenticPixels(Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  const int
+    id = GetOpenMPThreadId();
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if (cache_info->methods.sync_authentic_pixels_handler !=
+       (SyncAuthenticPixelsHandler) NULL)
+    {
+      status=cache_info->methods.sync_authentic_pixels_handler(image,
+        exception);
+      return(status);
+    }
+  assert(id < (int) cache_info->number_threads);
+  status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
+    exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   W r i t e P i x e l C a c h e M e t a c o n t e n t                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WritePixelCacheMetacontent() writes the meta-content to the specified region
+%  of the pixel cache.
+%
+%  The format of the WritePixelCacheMetacontent() method is:
+%
+%      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_info: the pixel cache.
+%
+%    o nexus_info: the cache nexus to write the meta-content.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    extent,
+    length;
+
+  register const unsigned char
+    *restrict p;
+
+  register ssize_t
+    y;
+
+  size_t
+    rows;
+
+  if (cache_info->metacontent_extent == 0)
+    return(MagickFalse);
+  if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+    return(MagickTrue);
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  length=(MagickSizeType) nexus_info->region.width*
+    cache_info->metacontent_extent;
+  rows=nexus_info->region.height;
+  extent=(MagickSizeType) length*rows;
+  p=(unsigned char *) nexus_info->metacontent;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register unsigned char
+        *restrict q;
+
+      /*
+        Write associated pixels to memory.
+      */
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent == (MagickSizeType) ((size_t) extent)))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      q=(unsigned char *) cache_info->metacontent+offset*
+        cache_info->metacontent_extent;
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        (void) memcpy(q,p,(size_t) length);
+        p+=nexus_info->region.width*cache_info->metacontent_extent;
+        q+=cache_info->columns*cache_info->metacontent_extent;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Write associated pixels to disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent <= MagickMaxBufferExtent))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      extent=(MagickSizeType) cache_info->columns*cache_info->rows;
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
+          cache_info->pixel_channels*sizeof(Quantum)+offset*
+          cache_info->metacontent_extent,length,(const unsigned char *) p);
+        if ((MagickSizeType) count != length)
+          break;
+        p+=nexus_info->region.width*cache_info->metacontent_extent;
+        offset+=cache_info->columns;
+      }
+      if (y < (ssize_t) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
+      nexus_info->region.width,(double) nexus_info->region.height,(double)
+      nexus_info->region.x,(double) nexus_info->region.y);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   W r i t e C a c h e P i x e l s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WritePixelCachePixels() writes image pixels to the specified region of the
+%  pixel cache.
+%
+%  The format of the WritePixelCachePixels() method is:
+%
+%      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
+%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o cache_info: the pixel cache.
+%
+%    o nexus_info: the cache nexus to write the pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
+  NexusInfo *nexus_info,ExceptionInfo *exception)
+{
+  MagickOffsetType
+    count,
+    offset;
+
+  MagickSizeType
+    extent,
+    length;
+
+  register const Quantum
+    *restrict p;
+
+  register ssize_t
+    y;
+
+  size_t
+    rows;
+
+  if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
+    return(MagickTrue);
+  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
+    nexus_info->region.x;
+  length=(MagickSizeType) nexus_info->region.width*cache_info->pixel_channels*
+    sizeof(Quantum);
+  rows=nexus_info->region.height;
+  extent=length*rows;
+  p=nexus_info->pixels;
+  switch (cache_info->type)
+  {
+    case MemoryCache:
+    case MapCache:
+    {
+      register Quantum
+        *restrict q;
+
+      /*
+        Write pixels to memory.
+      */
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent == (MagickSizeType) ((size_t) extent)))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      q=cache_info->pixels+offset*cache_info->pixel_channels;
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        (void) memcpy(q,p,(size_t) length);
+        p+=nexus_info->region.width*cache_info->pixel_channels;
+        q+=cache_info->columns*cache_info->pixel_channels;
+      }
+      break;
+    }
+    case DiskCache:
+    {
+      /*
+        Write pixels to disk.
+      */
+      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      if ((cache_info->columns == nexus_info->region.width) &&
+          (extent <= MagickMaxBufferExtent))
+        {
+          length=extent;
+          rows=1UL;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
+          cache_info->pixel_channels*sizeof(*p),length,(const unsigned char *)
+          p);
+        if ((MagickSizeType) count != length)
+          break;
+        p+=nexus_info->region.width*cache_info->pixel_channels;
+        offset+=cache_info->columns;
+      }
+      if (y < (ssize_t) rows)
+        {
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            cache_info->cache_filename);
+          return(MagickFalse);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((cache_info->debug != MagickFalse) &&
+      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
+    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
+      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
+      nexus_info->region.width,(double) nexus_info->region.height,(double)
+      nexus_info->region.x,(double) nexus_info->region.y);
+  return(MagickTrue);
+}
diff --git a/MagickCore/cache.h b/MagickCore/cache.h
new file mode 100644
index 0000000..2b8ed2b
--- /dev/null
+++ b/MagickCore/cache.h
@@ -0,0 +1,73 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore cache methods.
+*/
+#ifndef _MAGICKCORE_CACHE_H
+#define _MAGICKCORE_CACHE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/blob.h"
+
+extern MagickExport const Quantum
+  *GetVirtualPixels(const Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,ExceptionInfo *),
+  *GetVirtualPixelQueue(const Image *);
+
+extern MagickExport const void
+  *AcquirePixelCachePixels(const Image *,MagickSizeType *,ExceptionInfo *),
+  *GetVirtualMetacontent(const Image *);
+
+extern MagickExport MagickBooleanType
+  CacheComponentGenesis(void),
+  GetOneVirtualMagickPixel(const Image *,const ssize_t,const ssize_t,
+    PixelInfo *,ExceptionInfo *),
+  GetOneVirtualPixel(const Image *,const ssize_t,const ssize_t,PixelPacket *,
+    ExceptionInfo *),
+  GetOneVirtualMethodPixel(const Image *,const VirtualPixelMethod,const ssize_t,
+    const ssize_t,PixelPacket *,ExceptionInfo *),
+  GetOneAuthenticPixel(Image *,const ssize_t,const ssize_t,PixelPacket *,
+    ExceptionInfo *),
+  PersistPixelCache(Image *,const char *,const MagickBooleanType,
+    MagickOffsetType *,ExceptionInfo *),
+  SyncAuthenticPixels(Image *,ExceptionInfo *);
+
+extern MagickExport MagickSizeType
+  GetImageExtent(const Image *);
+
+extern MagickExport Quantum
+  *GetAuthenticPixels(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,ExceptionInfo *),
+  *GetAuthenticPixelQueue(const Image *),
+  *QueueAuthenticPixels(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,ExceptionInfo *);
+
+extern MagickExport VirtualPixelMethod
+  GetPixelCacheVirtualMethod(const Image *),
+  SetPixelCacheVirtualMethod(const Image *,const VirtualPixelMethod);
+
+extern MagickExport void
+  CacheComponentTerminus(void),
+  *GetAuthenticMetacontent(const Image *),
+  *GetPixelCachePixels(Image *,MagickSizeType *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/cipher.c b/MagickCore/cipher.c
new file mode 100644
index 0000000..bbc8bee
--- /dev/null
+++ b/MagickCore/cipher.c
@@ -0,0 +1,1151 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                   CCCC  IIIII  PPPP   H   H  EEEEE  RRRR                    %
+%                  C        I    P   P  H   H  E      R   R                   %
+%                  C        I    PPPP   HHHHH  EEE    RRRR                    %
+%                  C        I    P      H   H  E      R R                     %
+%                   CCCC  IIIII  P      H   H  EEEEE  R  R                    %
+%                                                                             %
+%                                                                             %
+%                          MagickCore Cipher Methods                          %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               March  2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cipher.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+
+#if defined(MAGICKCORE_CIPHER_SUPPORT)
+/*
+  Define declarations.
+*/
+#define AESBlocksize 16
+
+/*
+  Typedef declarations.
+*/
+typedef struct _AESInfo
+{
+  StringInfo
+    *key;
+
+  unsigned int
+    blocksize,
+    *encipher_key,
+    *decipher_key;
+
+  ssize_t
+    rounds,
+    timestamp;
+
+  size_t
+    signature;
+} AESInfo;
+
+/*
+  Global declarations.
+*/
+static unsigned char
+  InverseLog[256] =
+  {
+      1,   3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,
+     19,  53,  95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,
+     30,  34, 102, 170, 229,  52,  92, 228,  55,  89, 235,  38, 106, 190,
+    217, 112, 144, 171, 230,  49,  83, 245,   4,  12,  20,  60,  68, 204,
+     79, 209, 104, 184, 211, 110, 178, 205,  76, 212, 103, 169, 224,  59,
+     77, 215,  98, 166, 241,   8,  24,  40, 120, 136, 131, 158, 185, 208,
+    107, 189, 220, 127, 129, 152, 179, 206,  73, 219, 118, 154, 181, 196,
+     87, 249,  16,  48,  80, 240,  11,  29,  39, 105, 187, 214,  97, 163,
+    254,  25,  43, 125, 135, 146, 173, 236,  47, 113, 147, 174, 233,  32,
+     96, 160, 251,  22,  58,  78, 210, 109, 183, 194,  93, 231,  50,  86,
+    250,  21,  63,  65, 195,  94, 226,  61,  71, 201,  64, 192,  91, 237,
+     44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239,  42, 126,
+    130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193,  88, 232,  35,
+    101, 175, 234,  37, 111, 177, 200,  67, 197,  84, 252,  31,  33,  99,
+    165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,  69, 207,
+     74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,
+     18,  54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,
+     13,  23,  57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180,
+    199,  82, 246,   1
+  },
+  Log[256] =
+  {
+      0,   0,  25,   1,  50,   2,  26, 198,  75, 199,  27, 104,  51, 238,
+    223,   3, 100,   4, 224,  14,  52, 141, 129, 239,  76, 113,   8, 200,
+    248, 105,  28, 193, 125, 194,  29, 181, 249, 185,  39, 106,  77, 228,
+    166, 114, 154, 201,   9, 120, 101,  47, 138,   5,  33,  15, 225,  36,
+     18, 240, 130,  69,  53, 147, 218, 142, 150, 143, 219, 189,  54, 208,
+    206, 148,  19,  92, 210, 241,  64,  70, 131,  56, 102, 221, 253,  48,
+    191,   6, 139,  98, 179,  37, 226, 152,  34, 136, 145,  16, 126, 110,
+     72, 195, 163, 182,  30,  66,  58, 107,  40,  84, 250, 133,  61, 186,
+     43, 121,  10,  21, 155, 159,  94, 202,  78, 212, 172, 229, 243, 115,
+    167,  87, 175,  88, 168,  80, 244, 234, 214, 116,  79, 174, 233, 213,
+    231, 230, 173, 232,  44, 215, 117, 122, 235,  22,  11, 245,  89, 203,
+     95, 176, 156, 169,  81, 160, 127,  12, 246, 111,  23, 196,  73, 236,
+    216,  67,  31,  45, 164, 118, 123, 183, 204, 187,  62,  90, 251,  96,
+    177, 134,  59,  82, 161, 108, 170,  85,  41, 157, 151, 178, 135, 144,
+     97, 190, 220, 252, 188, 149, 207, 205,  55,  63,  91, 209,  83,  57,
+    132, 60,   65, 162, 109,  71,  20,  42, 158,  93,  86, 242, 211, 171,
+     68,  17, 146, 217,  35,  32,  46, 137, 180, 124, 184,  38, 119, 153,
+    227, 165, 103,  74, 237, 222, 197,  49, 254,  24,  13,  99, 140, 128,
+    192, 247, 112,   7,
+  },
+  SBox[256] =
+  {
+     99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215,
+    171, 118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175,
+    156, 164, 114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165,
+    229, 241, 113, 216,  49,  21,   4, 199,  35, 195,  24, 150,   5, 154,
+      7,  18, 128, 226, 235,  39, 178, 117,   9, 131,  44,  26,  27, 110,
+     90, 160,  82,  59, 214, 179,  41, 227,  47, 132,  83, 209,   0, 237,
+     32, 252, 177,  91, 106, 203, 190,  57,  74,  76,  88, 207, 208, 239,
+    170, 251,  67,  77,  51, 133,  69, 249,   2, 127,  80,  60, 159, 168,
+     81, 163,  64, 143, 146, 157,  56, 245, 188, 182, 218,  33,  16, 255,
+    243, 210, 205,  12,  19, 236,  95, 151,  68,  23, 196, 167, 126,  61,
+    100,  93,  25, 115,  96, 129,  79, 220,  34,  42, 144, 136,  70, 238,
+    184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,   6,  36,  92,
+    194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 141, 213,
+     78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,  46,
+     28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62,
+    181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158,
+    225, 248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,
+     40, 223, 140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15,
+    176,  84, 187, 22
+  };
+
+/*
+  Forward declarations.
+*/
+static AESInfo
+  *DestroyAESInfo(AESInfo *);
+
+static void
+  EncipherAESBlock(AESInfo *,const unsigned char *,unsigned char *),
+  SetAESKey(AESInfo *,const StringInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e A E S I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireAESInfo() allocate the AESInfo structure.
+%
+%  The format of the AcquireAESInfo method is:
+%
+%      AESInfo *AcquireAESInfo(void)
+%
+*/
+static AESInfo *AcquireAESInfo(void)
+{
+  AESInfo
+    *aes_info;
+
+  aes_info=(AESInfo *) AcquireMagickMemory(sizeof(*aes_info));
+  if (aes_info == (AESInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(aes_info,0,sizeof(*aes_info));
+  aes_info->blocksize=AESBlocksize;
+  aes_info->key=AcquireStringInfo(32);
+  aes_info->encipher_key=(unsigned int *) AcquireQuantumMemory(60UL,sizeof(
+    *aes_info->encipher_key));
+  aes_info->decipher_key=(unsigned int *) AcquireQuantumMemory(60UL,sizeof(
+    *aes_info->decipher_key));
+  if ((aes_info->key == (StringInfo *) NULL) ||
+      (aes_info->encipher_key == (unsigned int *) NULL) ||
+      (aes_info->decipher_key == (unsigned int *) NULL))
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  aes_info->timestamp=(ssize_t) time(0);
+  aes_info->signature=MagickSignature;
+  return(aes_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y A E S I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyAESInfo() zeros memory associated with the AESInfo structure.
+%
+%  The format of the DestroyAESInfo method is:
+%
+%      AESInfo *DestroyAESInfo(AESInfo *aes_info)
+%
+%  A description of each parameter follows:
+%
+%    o aes_info: the cipher context.
+%
+*/
+static AESInfo *DestroyAESInfo(AESInfo *aes_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(aes_info != (AESInfo *) NULL);
+  assert(aes_info->signature == MagickSignature);
+  if (aes_info->decipher_key != (unsigned int *) NULL)
+    aes_info->decipher_key=(unsigned int *) RelinquishMagickMemory(
+      aes_info->decipher_key);
+  if (aes_info->encipher_key != (unsigned int *) NULL)
+    aes_info->encipher_key=(unsigned int *) RelinquishMagickMemory(
+      aes_info->encipher_key);
+  if (aes_info->key != (StringInfo *) NULL)
+    aes_info->key=DestroyStringInfo(aes_info->key);
+  aes_info->signature=(~MagickSignature);
+  aes_info=(AESInfo *) RelinquishMagickMemory(aes_info);
+  return(aes_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E n c i p h e r A E S B l o c k                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EncipherAESBlock() enciphers a single block of plaintext to produce a block
+%  of ciphertext.
+%
+%  The format of the EncipherAESBlock method is:
+%
+%      void EncipherAES(AESInfo *aes_info,const unsigned char *plaintext,
+%        unsigned char *ciphertext)
+%
+%  A description of each parameter follows:
+%
+%    o aes_info: the cipher context.
+%
+%    o plaintext: the plain text.
+%
+%    o ciphertext: the cipher text.
+%
+*/
+
+static inline void AddRoundKey(const unsigned int *ciphertext,
+  const unsigned int *key,unsigned int *plaintext)
+{
+  register ssize_t
+    i;
+
+  /*
+    Xor corresponding text input and round key input bytes.
+  */
+  for (i=0; i < 4; i++)
+    plaintext[i]=key[i] ^ ciphertext[i];
+}
+
+static inline unsigned char ByteMultiply(const unsigned char alpha,
+  const unsigned char beta)
+{
+  /*
+    Byte multiply two elements of GF(2^m) (mix columns and inverse mix columns).
+  */
+  if ((alpha == 0) || (beta == 0))
+    return(0);
+  return(InverseLog[(Log[alpha]+Log[beta]) % 0xff]);
+}
+
+static inline unsigned int ByteSubTransform(unsigned int x,
+  unsigned char *s_box)
+{
+  unsigned int
+    key;
+
+  /*
+    Non-linear layer resists differential and linear cryptoanalysis attacks.
+  */
+  key=(s_box[x & 0xff]) | (s_box[(x >> 8) & 0xff] << 8) |
+    (s_box[(x >> 16) & 0xff] << 16) | (s_box[(x >> 24) & 0xff] << 24);
+  return(key);
+}
+
+static void FinalizeRoundKey(const unsigned int *ciphertext,
+  const unsigned int *key,unsigned char *plaintext)
+{
+  register unsigned char
+    *p;
+
+  register unsigned int
+    i,
+    j;
+
+  unsigned int
+    value;
+
+  /*
+    The round key is XORed with the result of the mix-column transformation.
+  */
+  p=plaintext;
+  for (i=0; i < 4; i++)
+  {
+    value=ciphertext[i] ^ key[i];
+    for (j=0; j < 4; j++)
+      *p++=(value >> (8*j)) & 0xff;
+  }
+  /*
+    Reset registers.
+  */
+  value=0;
+}
+
+static void InitializeRoundKey(const unsigned char *ciphertext,
+  const unsigned int *key,unsigned int *plaintext)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned int
+    i,
+    j;
+
+  unsigned int
+    value;
+
+  p=ciphertext;
+  for (i=0; i < 4; i++)
+  {
+    value=0;
+    for (j=0; j < 4; j++)
+      value|=(*p++ << (8*j));
+    plaintext[i]=key[i] ^ value;
+  }
+  /*
+    Reset registers.
+  */
+  value=0;
+}
+
+static inline unsigned int RotateLeft(const unsigned int x)
+{
+  return(((x << 8) | ((x >> 24) & 0xff)));
+}
+
+static void EncipherAESBlock(AESInfo *aes_info,const unsigned char *plaintext,
+  unsigned char *ciphertext)
+{
+  register ssize_t
+    i,
+    j;
+
+  static int
+    map[4][4] =
+    {
+      { 0, 1, 2, 3 },
+      { 1, 2, 3, 0 },
+      { 2, 3, 0, 1 },
+      { 3, 0, 1, 2 }
+    };
+
+  static unsigned int
+    D[] =
+    {
+      0xa56363c6U, 0x847c7cf8U, 0x997777eeU, 0x8d7b7bf6U, 0x0df2f2ffU,
+      0xbd6b6bd6U, 0xb16f6fdeU, 0x54c5c591U, 0x50303060U, 0x03010102U,
+      0xa96767ceU, 0x7d2b2b56U, 0x19fefee7U, 0x62d7d7b5U, 0xe6abab4dU,
+      0x9a7676ecU, 0x45caca8fU, 0x9d82821fU, 0x40c9c989U, 0x877d7dfaU,
+      0x15fafaefU, 0xeb5959b2U, 0xc947478eU, 0x0bf0f0fbU, 0xecadad41U,
+      0x67d4d4b3U, 0xfda2a25fU, 0xeaafaf45U, 0xbf9c9c23U, 0xf7a4a453U,
+      0x967272e4U, 0x5bc0c09bU, 0xc2b7b775U, 0x1cfdfde1U, 0xae93933dU,
+      0x6a26264cU, 0x5a36366cU, 0x413f3f7eU, 0x02f7f7f5U, 0x4fcccc83U,
+      0x5c343468U, 0xf4a5a551U, 0x34e5e5d1U, 0x08f1f1f9U, 0x937171e2U,
+      0x73d8d8abU, 0x53313162U, 0x3f15152aU, 0x0c040408U, 0x52c7c795U,
+      0x65232346U, 0x5ec3c39dU, 0x28181830U, 0xa1969637U, 0x0f05050aU,
+      0xb59a9a2fU, 0x0907070eU, 0x36121224U, 0x9b80801bU, 0x3de2e2dfU,
+      0x26ebebcdU, 0x6927274eU, 0xcdb2b27fU, 0x9f7575eaU, 0x1b090912U,
+      0x9e83831dU, 0x742c2c58U, 0x2e1a1a34U, 0x2d1b1b36U, 0xb26e6edcU,
+      0xee5a5ab4U, 0xfba0a05bU, 0xf65252a4U, 0x4d3b3b76U, 0x61d6d6b7U,
+      0xceb3b37dU, 0x7b292952U, 0x3ee3e3ddU, 0x712f2f5eU, 0x97848413U,
+      0xf55353a6U, 0x68d1d1b9U, 0x00000000U, 0x2cededc1U, 0x60202040U,
+      0x1ffcfce3U, 0xc8b1b179U, 0xed5b5bb6U, 0xbe6a6ad4U, 0x46cbcb8dU,
+      0xd9bebe67U, 0x4b393972U, 0xde4a4a94U, 0xd44c4c98U, 0xe85858b0U,
+      0x4acfcf85U, 0x6bd0d0bbU, 0x2aefefc5U, 0xe5aaaa4fU, 0x16fbfbedU,
+      0xc5434386U, 0xd74d4d9aU, 0x55333366U, 0x94858511U, 0xcf45458aU,
+      0x10f9f9e9U, 0x06020204U, 0x817f7ffeU, 0xf05050a0U, 0x443c3c78U,
+      0xba9f9f25U, 0xe3a8a84bU, 0xf35151a2U, 0xfea3a35dU, 0xc0404080U,
+      0x8a8f8f05U, 0xad92923fU, 0xbc9d9d21U, 0x48383870U, 0x04f5f5f1U,
+      0xdfbcbc63U, 0xc1b6b677U, 0x75dadaafU, 0x63212142U, 0x30101020U,
+      0x1affffe5U, 0x0ef3f3fdU, 0x6dd2d2bfU, 0x4ccdcd81U, 0x140c0c18U,
+      0x35131326U, 0x2fececc3U, 0xe15f5fbeU, 0xa2979735U, 0xcc444488U,
+      0x3917172eU, 0x57c4c493U, 0xf2a7a755U, 0x827e7efcU, 0x473d3d7aU,
+      0xac6464c8U, 0xe75d5dbaU, 0x2b191932U, 0x957373e6U, 0xa06060c0U,
+      0x98818119U, 0xd14f4f9eU, 0x7fdcdca3U, 0x66222244U, 0x7e2a2a54U,
+      0xab90903bU, 0x8388880bU, 0xca46468cU, 0x29eeeec7U, 0xd3b8b86bU,
+      0x3c141428U, 0x79dedea7U, 0xe25e5ebcU, 0x1d0b0b16U, 0x76dbdbadU,
+      0x3be0e0dbU, 0x56323264U, 0x4e3a3a74U, 0x1e0a0a14U, 0xdb494992U,
+      0x0a06060cU, 0x6c242448U, 0xe45c5cb8U, 0x5dc2c29fU, 0x6ed3d3bdU,
+      0xefacac43U, 0xa66262c4U, 0xa8919139U, 0xa4959531U, 0x37e4e4d3U,
+      0x8b7979f2U, 0x32e7e7d5U, 0x43c8c88bU, 0x5937376eU, 0xb76d6ddaU,
+      0x8c8d8d01U, 0x64d5d5b1U, 0xd24e4e9cU, 0xe0a9a949U, 0xb46c6cd8U,
+      0xfa5656acU, 0x07f4f4f3U, 0x25eaeacfU, 0xaf6565caU, 0x8e7a7af4U,
+      0xe9aeae47U, 0x18080810U, 0xd5baba6fU, 0x887878f0U, 0x6f25254aU,
+      0x722e2e5cU, 0x241c1c38U, 0xf1a6a657U, 0xc7b4b473U, 0x51c6c697U,
+      0x23e8e8cbU, 0x7cdddda1U, 0x9c7474e8U, 0x211f1f3eU, 0xdd4b4b96U,
+      0xdcbdbd61U, 0x868b8b0dU, 0x858a8a0fU, 0x907070e0U, 0x423e3e7cU,
+      0xc4b5b571U, 0xaa6666ccU, 0xd8484890U, 0x05030306U, 0x01f6f6f7U,
+      0x120e0e1cU, 0xa36161c2U, 0x5f35356aU, 0xf95757aeU, 0xd0b9b969U,
+      0x91868617U, 0x58c1c199U, 0x271d1d3aU, 0xb99e9e27U, 0x38e1e1d9U,
+      0x13f8f8ebU, 0xb398982bU, 0x33111122U, 0xbb6969d2U, 0x70d9d9a9U,
+      0x898e8e07U, 0xa7949433U, 0xb69b9b2dU, 0x221e1e3cU, 0x92878715U,
+      0x20e9e9c9U, 0x49cece87U, 0xff5555aaU, 0x78282850U, 0x7adfdfa5U,
+      0x8f8c8c03U, 0xf8a1a159U, 0x80898909U, 0x170d0d1aU, 0xdabfbf65U,
+      0x31e6e6d7U, 0xc6424284U, 0xb86868d0U, 0xc3414182U, 0xb0999929U,
+      0x772d2d5aU, 0x110f0f1eU, 0xcbb0b07bU, 0xfc5454a8U, 0xd6bbbb6dU,
+      0x3a16162cU
+    };
+
+  unsigned int
+    alpha,
+    key[4],
+    text[4];
+
+  /*
+    Encipher one block.
+  */
+  (void) memset(text,0,sizeof(text));
+  InitializeRoundKey(plaintext,aes_info->encipher_key,text);
+  for (i=1; i < aes_info->rounds; i++)
+  {
+    /*
+      Linear mixing step: cause diffusion of the bits over multiple rounds.
+    */
+    for (j=0; j < 4; j++)
+      key[j]=D[text[j] & 0xff] ^
+        RotateLeft(D[(text[map[1][j]] >> 8) & 0xff] ^
+        RotateLeft(D[(text[map[2][j]] >> 16) & 0xff] ^
+        RotateLeft(D[(text[map[3][j]] >> 24) & 0xff])));
+    AddRoundKey(key,aes_info->encipher_key+4*i,text);
+  }
+  for (i=0; i < 4; i++)
+  {
+    alpha=(text[i] & 0x000000ff) | ((text[map[1][i]]) & 0x0000ff00) |
+      ((text[map[2][i]]) & 0x00ff0000) | ((text[map[3][i]]) & 0xff000000);
+    key[i]=ByteSubTransform(alpha,SBox);
+  }
+  FinalizeRoundKey(key,aes_info->encipher_key+4*aes_info->rounds,ciphertext);
+  /*
+    Reset registers.
+  */
+  alpha=0;
+  (void) ResetMagickMemory(key,0,sizeof(key));
+  (void) ResetMagickMemory(text,0,sizeof(text));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P a s s k e y D e c i p h e r I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PasskeyDecipherImage() converts cipher pixels to plain pixels.
+%
+%  The format of the PasskeyDecipherImage method is:
+%
+%      MagickBooleanType PasskeyDecipherImage(Image *image,
+%        const StringInfo *passkey,ExceptionInfo *exception)
+%      MagickBooleanType DecipherImage(Image *image,const char *passphrase,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o passphrase: decipher cipher pixels with this passphrase.
+%
+%    o passkey: decrypt cipher pixels with this passkey.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType DecipherImage(Image *image,
+  const char *passphrase,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  StringInfo
+    *passkey;
+
+  if (passphrase == (const char *) NULL)
+    return(MagickTrue);
+  passkey=StringToStringInfo(passphrase);
+  if (passkey == (StringInfo *) NULL)
+    return(MagickFalse);
+  status=PasskeyDecipherImage(image,passkey,exception);
+  passkey=DestroyStringInfo(passkey);
+  return(status);
+}
+
+MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
+  const StringInfo *passkey,ExceptionInfo *exception)
+{
+#define DecipherImageTag  "Decipher/Image "
+
+  AESInfo
+    *aes_info;
+
+  CacheView
+    *image_view;
+
+  const unsigned char
+    *digest;
+
+  MagickBooleanType
+    proceed;
+
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    quantum_type;
+
+  SignatureInfo
+    *signature_info;
+
+  register unsigned char
+    *p;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  StringInfo
+    *key,
+    *nonce;
+
+  unsigned char
+    input_block[AESBlocksize],
+    output_block[AESBlocksize],
+    *pixels;
+
+  /*
+    Generate decipher key and nonce.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (passkey == (const StringInfo *) NULL)
+    return(MagickTrue);
+  quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
+  if (quantum_info == (QuantumInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  aes_info=AcquireAESInfo();
+  key=CloneStringInfo(passkey);
+  if (key == (StringInfo *) NULL)
+    {
+      aes_info=DestroyAESInfo(aes_info);
+      quantum_info=DestroyQuantumInfo(quantum_info);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  nonce=SplitStringInfo(key,GetStringInfoLength(key)/2);
+  if (nonce == (StringInfo *) NULL)
+    {
+      key=DestroyStringInfo(key);
+      aes_info=DestroyAESInfo(aes_info);
+      quantum_info=DestroyQuantumInfo(quantum_info);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  SetAESKey(aes_info,key);
+  key=DestroyStringInfo(key);
+  signature_info=AcquireSignatureInfo();
+  UpdateSignature(signature_info,nonce);
+  SetStringInfoLength(nonce,sizeof(quantum_info->extent));
+  SetStringInfoDatum(nonce,(const unsigned char *) &quantum_info->extent);
+  UpdateSignature(signature_info,nonce);
+  FinalizeSignature(signature_info);
+  (void) ResetMagickMemory(input_block,0,sizeof(input_block));
+  digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
+  (void) CopyMagickMemory(input_block,digest,MagickMin(AESBlocksize,
+    GetSignatureDigestsize(signature_info))*sizeof(*input_block));
+  nonce=DestroyStringInfo(nonce);
+  signature_info=DestroySignatureInfo(signature_info);
+  /*
+    Convert cipher pixels to plain pixels.
+  */
+  quantum_type=GetQuantumType(image,exception);
+  pixels=GetQuantumPixels(quantum_info);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,exception);
+    p=pixels;
+    for (x=0; x < (ssize_t) length; x++)
+    {
+      (void) CopyMagickMemory(output_block,input_block,AESBlocksize*
+        sizeof(*output_block));
+      EncipherAESBlock(aes_info,output_block,output_block);
+      (void) CopyMagickMemory(input_block,input_block+1,(AESBlocksize-1)*
+        sizeof(*input_block));
+      input_block[AESBlocksize-1]=(*p);
+      *p++^=(*output_block);
+    }
+    (void) ImportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,exception);
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,DecipherImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  (void) DeleteImageProperty(image,"cipher:type");
+  (void) DeleteImageProperty(image,"cipher:mode");
+  (void) DeleteImageProperty(image,"cipher:nonce");
+  image->taint=MagickFalse;
+  /*
+    Free resources.
+  */
+  quantum_info=DestroyQuantumInfo(quantum_info);
+  aes_info=DestroyAESInfo(aes_info);
+  (void) ResetMagickMemory(input_block,0,sizeof(input_block));
+  (void) ResetMagickMemory(output_block,0,sizeof(output_block));
+  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P a s s k e y E n c i p h e r I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PasskeyEncipherImage() converts pixels to cipher-pixels.
+%
+%  The format of the PasskeyEncipherImage method is:
+%
+%      MagickBooleanType PasskeyEncipherImage(Image *image,
+%        const StringInfo *passkey,ExceptionInfo *exception)
+%      MagickBooleanType EncipherImage(Image *image,const char *passphrase,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o passphrase: encipher pixels with this passphrase.
+%
+%    o passkey: decrypt cipher pixels with this passkey.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType EncipherImage(Image *image,
+  const char *passphrase,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  StringInfo
+    *passkey;
+
+  if (passphrase == (const char *) NULL)
+    return(MagickTrue);
+  passkey=StringToStringInfo(passphrase);
+  if (passkey == (StringInfo *) NULL)
+    return(MagickFalse);
+  status=PasskeyEncipherImage(image,passkey,exception);
+  passkey=DestroyStringInfo(passkey);
+  return(status);
+}
+
+MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
+  const StringInfo *passkey,ExceptionInfo *exception)
+{
+#define EncipherImageTag  "Encipher/Image "
+
+  AESInfo
+    *aes_info;
+
+  CacheView
+    *image_view;
+
+  char
+    *signature;
+
+  const unsigned char
+    *digest;
+
+  MagickBooleanType
+    proceed;
+
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    quantum_type;
+
+  register unsigned char
+    *p;
+
+  SignatureInfo
+    *signature_info;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  StringInfo
+    *key,
+    *nonce;
+
+  unsigned char
+    input_block[AESBlocksize],
+    output_block[AESBlocksize],
+    *pixels;
+
+  /*
+    Generate encipher key and nonce.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (passkey == (const StringInfo *) NULL)
+    return(MagickTrue);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
+  if (quantum_info == (QuantumInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  aes_info=AcquireAESInfo();
+  key=CloneStringInfo(passkey);
+  if (key == (StringInfo *) NULL)
+    {
+      aes_info=DestroyAESInfo(aes_info);
+      quantum_info=DestroyQuantumInfo(quantum_info);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  nonce=SplitStringInfo(key,GetStringInfoLength(key)/2);
+  if (nonce == (StringInfo *) NULL)
+    {
+      key=DestroyStringInfo(key);
+      aes_info=DestroyAESInfo(aes_info);
+      quantum_info=DestroyQuantumInfo(quantum_info);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  SetAESKey(aes_info,key);
+  key=DestroyStringInfo(key);
+  signature_info=AcquireSignatureInfo();
+  UpdateSignature(signature_info,nonce);
+  SetStringInfoLength(nonce,sizeof(quantum_info->extent));
+  SetStringInfoDatum(nonce,(const unsigned char *) &quantum_info->extent);
+  UpdateSignature(signature_info,nonce);
+  nonce=DestroyStringInfo(nonce);
+  FinalizeSignature(signature_info);
+  (void) ResetMagickMemory(input_block,0,sizeof(input_block));
+  digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
+  (void) CopyMagickMemory(input_block,digest,MagickMin(AESBlocksize,
+    GetSignatureDigestsize(signature_info))*sizeof(*input_block));
+  signature=StringInfoToHexString(GetSignatureDigest(signature_info));
+  (void) SetImageProperty(image,"cipher:type","AES");
+  (void) SetImageProperty(image,"cipher:mode","CFB");
+  (void) SetImageProperty(image,"cipher:nonce",signature);
+  signature=DestroyString(signature);
+  signature_info=DestroySignatureInfo(signature_info);
+  /*
+    Convert plain pixels to cipher pixels.
+  */
+  quantum_type=GetQuantumType(image,exception);
+  pixels=GetQuantumPixels(quantum_info);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,exception);
+    p=pixels;
+    for (x=0; x < (ssize_t) length; x++)
+    {
+      (void) CopyMagickMemory(output_block,input_block,AESBlocksize*
+        sizeof(*output_block));
+      EncipherAESBlock(aes_info,output_block,output_block);
+      *p^=(*output_block);
+      (void) CopyMagickMemory(input_block,input_block+1,(AESBlocksize-1)*
+        sizeof(*input_block));
+      input_block[AESBlocksize-1]=(*p++);
+    }
+    (void) ImportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,exception);
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,EncipherImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  image->taint=MagickFalse;
+  /*
+    Free resources.
+  */
+  quantum_info=DestroyQuantumInfo(quantum_info);
+  aes_info=DestroyAESInfo(aes_info);
+  (void) ResetMagickMemory(input_block,0,sizeof(input_block));
+  (void) ResetMagickMemory(output_block,0,sizeof(output_block));
+  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t A E S K e y                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetAESKey() sets the key for the AES cipher.  The key length is specified
+%  in bits.  Valid values are 128, 192, or 256 requiring a key buffer length
+%  in bytes of 16, 24, and 32 respectively.
+%
+%  The format of the SetAESKey method is:
+%
+%      SetAESKey(AESInfo *aes_info,const StringInfo *key)
+%
+%  A description of each parameter follows:
+%
+%    o aes_info: the cipher context.
+%
+%    o key: the key.
+%
+*/
+
+static inline void InverseAddRoundKey(const unsigned int *alpha,
+  unsigned int *beta)
+{
+  register unsigned int
+    i,
+    j;
+
+  for (i=0; i < 4; i++)
+  {
+    beta[i]=0;
+    for (j=0; j < 4; j++)
+      beta[i]|=(ByteMultiply(0xe,(alpha[i] >> (8*j)) & 0xff) ^
+        ByteMultiply(0xb,(alpha[i] >> (8*((j+1) % 4))) & 0xff) ^
+        ByteMultiply(0xd,(alpha[i] >> (8*((j+2) % 4))) & 0xff) ^
+        ByteMultiply(0x9,(alpha[i] >> (8*((j+3) % 4))) & 0xff)) << (8*j);
+  }
+}
+
+static inline unsigned int XTime(unsigned char alpha)
+{
+  unsigned char
+    beta;
+
+  beta=(unsigned char) ((alpha & 0x80) != 0 ? 0x1b : 0);
+  alpha<<=1;
+  alpha^=beta;
+  return(alpha);
+}
+
+static inline unsigned int RotateRight(const unsigned int x)
+{
+  return((x >> 8) | ((x & 0xff) << 24));
+}
+
+static void SetAESKey(AESInfo *aes_info,const StringInfo *key)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    bytes,
+    n;
+
+  unsigned char
+    *datum;
+
+  unsigned int
+    alpha,
+    beta;
+
+  /*
+    Determine the number of rounds based on the number of bits in key.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(aes_info != (AESInfo *) NULL);
+  assert(aes_info->signature == MagickSignature);
+  assert(key != (StringInfo *) NULL);
+  n=4;
+  aes_info->rounds=10;
+  if ((8*GetStringInfoLength(key)) >= 256)
+    {
+      n=8;
+      aes_info->rounds=14;
+    }
+  else
+    if ((8*GetStringInfoLength(key)) >= 192)
+      {
+        n=6;
+        aes_info->rounds=12;
+      }
+  /*
+    Generate crypt key.
+  */
+  datum=GetStringInfoDatum(aes_info->key);
+  (void) ResetMagickMemory(datum,0,GetStringInfoLength(aes_info->key));
+  (void) CopyMagickMemory(datum,GetStringInfoDatum(key),MagickMin(
+    GetStringInfoLength(key),GetStringInfoLength(aes_info->key)));
+  for (i=0; i < n; i++)
+    aes_info->encipher_key[i]=datum[4*i] | (datum[4*i+1] << 8) |
+      (datum[4*i+2] << 16) | (datum[4*i+3] << 24);
+  beta=1;
+  bytes=(AESBlocksize/4)*(aes_info->rounds+1);
+  for (i=n; i < bytes; i++)
+  {
+    alpha=aes_info->encipher_key[i-1];
+    if ((i % n) == 0)
+      {
+        alpha=ByteSubTransform(RotateRight(alpha),SBox) ^ beta;
+        beta=XTime((unsigned char) (beta & 0xff));
+      }
+    else
+      if ((n > 6) && ((i % n) == 4))
+        alpha=ByteSubTransform(alpha,SBox);
+    aes_info->encipher_key[i]=aes_info->encipher_key[i-n] ^ alpha;
+  }
+  /*
+    Generate deciper key (in reverse order).
+  */
+  for (i=0; i < 4; i++)
+  {
+    aes_info->decipher_key[i]=aes_info->encipher_key[i];
+    aes_info->decipher_key[bytes-4+i]=aes_info->encipher_key[bytes-4+i];
+  }
+  for (i=4; i < (bytes-4); i+=4)
+    InverseAddRoundKey(aes_info->encipher_key+i,aes_info->decipher_key+i);
+  /*
+    Reset registers.
+  */
+  datum=GetStringInfoDatum(aes_info->key);
+  (void) ResetMagickMemory(datum,0,GetStringInfoLength(aes_info->key));
+  alpha=0;
+  beta=0;
+}
+#else
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P a s s k e y D e c i p h e r I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PasskeyDecipherImage() converts cipher pixels to plain pixels.
+%
+%  The format of the PasskeyDecipherImage method is:
+%
+%      MagickBooleanType PasskeyDecipherImage(Image *image,
+%        const StringInfo *passkey,ExceptionInfo *exception)
+%      MagickBooleanType DecipherImage(Image *image,const char *passphrase,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o passphrase: decipher cipher pixels with this passphrase.
+%
+%    o passkey: decrypt cipher pixels with this passkey.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType DecipherImage(Image *image,
+  const char *passphrase,ExceptionInfo *exception)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  (void) passphrase;
+  ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
+}
+
+MagickExport MagickBooleanType PasskeyDecipherImage(Image *image,
+  const StringInfo *passkey,ExceptionInfo *exception)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  (void) passkey;
+  ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P a s s k e y E n c i p h e r I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PasskeyEncipherImage() converts pixels to cipher-pixels.
+%
+%  The format of the PasskeyEncipherImage method is:
+%
+%      MagickBooleanType PasskeyEncipherImage(Image *image,
+%        const StringInfo *passkey,ExceptionInfo *exception)
+%      MagickBooleanType EncipherImage(Image *image,const char *passphrase,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o passphrase: decipher cipher pixels with this passphrase.
+%
+%    o passkey: decrypt cipher pixels with this passkey.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType EncipherImage(Image *image,
+  const char *passphrase,ExceptionInfo *exception)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  (void) passphrase;
+  ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
+}
+
+MagickExport MagickBooleanType PasskeyEncipherImage(Image *image,
+  const StringInfo *passkey,ExceptionInfo *exception)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  (void) passkey;
+  ThrowBinaryException(ImageError,"CipherSupportNotEnabled",image->filename);
+}
+#endif
diff --git a/MagickCore/cipher.h b/MagickCore/cipher.h
new file mode 100644
index 0000000..9a5c7e4
--- /dev/null
+++ b/MagickCore/cipher.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore cipher methods.
+*/
+#ifndef _MAGICKCORE_CIPHER_H
+#define _MAGICKCORE_CIPHER_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  DecipherImage(Image *,const char *,ExceptionInfo *),
+  EncipherImage(Image *,const char *,ExceptionInfo *),
+  PasskeyDecipherImage(Image *,const StringInfo *,ExceptionInfo *),
+  PasskeyEncipherImage(Image *,const StringInfo *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/client.c b/MagickCore/client.c
new file mode 100644
index 0000000..a625df4
--- /dev/null
+++ b/MagickCore/client.c
@@ -0,0 +1,156 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  CCCC  L      IIIII  EEEEE  N   N  TTTTT                    %
+%                 C      L        I    E      NN  N    T                      %
+%                 C      L        I    EEE    N N N    T                      %
+%                 C      L        I    E      N  NN    T                      %
+%                  CCCC  LLLLL  IIIII  EEEEE  N   N    T                      %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Client Methods                           %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               March 2003                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/client.h"
+#include "MagickCore/string_.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C l i e n t N a m e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetClientName returns the current client name.
+%
+%  The format of the GetClientName method is:
+%
+%      const char *GetClientName(void)
+%
+*/
+MagickExport const char *GetClientName(void)
+{
+  return(SetClientName((const char *) NULL));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C l i e n t P a t h                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetClientPath returns the current client name.
+%
+%  The format of the GetClientPath method is:
+%
+%      const char *GetClientPath(void)
+%
+*/
+MagickExport const char *GetClientPath(void)
+{
+  return(SetClientPath((const char *) NULL));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t C l i e n t N a m e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetClientName sets the client name and returns it.
+%
+%  The format of the SetClientName method is:
+%
+%      const char *SetClientName(const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o name: Specifies the new client name.
+%
+*/
+MagickExport const char *SetClientName(const char *name)
+{
+  static char
+    client_name[MaxTextExtent] = "Magick";
+
+  if ((name != (char *) NULL) && (*name != '\0'))
+    (void) CopyMagickString(client_name,name,MaxTextExtent);
+  return(client_name);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t C l i e n t P a t h                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetClientPath() sets the client path if the name is specified.  Otherwise
+%  the current client path is returned. A zero-length string is returned if
+%  the client path has never been set.
+%
+%  The format of the SetClientPath method is:
+%
+%      const char *SetClientPath(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: Specifies the new client path.
+%
+*/
+MagickExport const char *SetClientPath(const char *path)
+{
+  static char
+    client_path[MaxTextExtent] = "";
+
+  if ((path != (char *) NULL) && (*path != '\0'))
+    (void) CopyMagickString(client_path,path,MaxTextExtent);
+  return(client_path);
+}
diff --git a/MagickCore/client.h b/MagickCore/client.h
new file mode 100644
index 0000000..6a49d03
--- /dev/null
+++ b/MagickCore/client.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore client methods.
+*/
+#ifndef _MAGICKCORE_CLIENT_H
+#define _MAGICKCORE_CLIENT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport const char
+  *GetClientPath(void),
+  *GetClientName(void),
+  *SetClientName(const char *),
+  *SetClientPath(const char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/coder.c b/MagickCore/coder.c
new file mode 100644
index 0000000..ae27c58
--- /dev/null
+++ b/MagickCore/coder.c
@@ -0,0 +1,945 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                   CCCC   OOO   DDDD    EEEEE  RRRR                          %
+%                  C      O   O  D   D   E      R   R                         %
+%                  C      O   O  D   D   EEE    RRRR                          %
+%                  C      O   O  D   D   E      R R                           %
+%                   CCCC   OOO   DDDD    EEEEE  R  R                          %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Coder Methods                          %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 May 2001                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/coder.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define MagickCoderFilename  "coder.xml"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _CoderMapInfo
+{
+  const char
+    *magick,
+    *name;
+} CoderMapInfo;
+
+/*
+  Static declarations.
+*/
+static const CoderMapInfo
+  CoderMap[] =
+  {
+    { "3FR", "DNG" },
+    { "8BIM", "META" },
+    { "8BIMTEXT", "META" },
+    { "8BIMWTEXT", "META" },
+    { "AFM", "TTF" },
+    { "A", "RAW" },
+    { "AI", "PDF" },
+    { "APP1JPEG", "META" },
+    { "APP1", "META" },
+    { "ARW", "DNG" },
+    { "AVI", "MPEG" },
+    { "BIE", "JBIG" },
+    { "BMP2", "BMP" },
+    { "BMP3", "BMP" },
+    { "B", "RAW" },
+    { "BRF", "BRAILLE" },
+    { "BGRA", "BGR" },
+    { "CMYKA", "CMYK" },
+    { "C", "RAW" },
+    { "CAL", "CALS" },
+    { "CANVAS", "XC" },
+    { "CR2", "DNG" },
+    { "CRW", "DNG" },
+    { "CUR", "ICON" },
+    { "DCR", "DNG" },
+    { "DCX", "PCX" },
+    { "DFONT", "TTF" },
+    { "EPDF", "PDF" },
+    { "EPI", "PS" },
+    { "EPS2", "PS2" },
+    { "EPS3", "PS3" },
+    { "EPSF", "PS" },
+    { "EPSI", "PS" },
+    { "EPS", "PS" },
+    { "EPT2", "EPT" },
+    { "EPT3", "EPT" },
+    { "ERF", "DNG" },
+    { "EXIF", "META" },
+    { "FILE", "URL" },
+    { "FRACTAL", "PLASMA" },
+    { "FTP", "URL" },
+    { "FTS", "FITS" },
+    { "G3", "FAX" },
+    { "GIF87", "GIF" },
+    { "G", "RAW" },
+    { "GRANITE", "MAGICK" },
+    { "GROUP4", "TIFF" },
+    { "K25", "DNG" },
+    { "KDC", "DNG" },
+    { "H", "MAGICK" },
+    { "HTM", "HTML" },
+    { "HTTP", "URL" },
+    { "ICB", "TGA" },
+    { "ICC", "META" },
+    { "ICM", "META" },
+    { "ICO", "ICON" },
+    { "IMPLICIT", "***" },
+    { "IPTC", "META" },
+    { "IPTCTEXT", "META" },
+    { "IPTCWTEXT", "META" },
+    { "ISOBRL", "BRAILLE" },
+    { "JBG", "JBIG" },
+    { "JNG", "PNG" },
+    { "JPC", "JP2" },
+    { "J2C", "JP2" },
+    { "JPG", "JPEG" },
+    { "JPX", "JP2" },
+    { "K", "RAW" },
+    { "LOGO", "MAGICK" },
+    { "M2V", "MPEG" },
+    { "M4V", "MPEG" },
+    { "M", "RAW" },
+    { "MNG", "PNG" },
+    { "MOV", "MPEG" },
+    { "MP4", "MPEG" },
+    { "MPG", "MPEG" },
+    { "MPRI", "MPR" },
+    { "MRW", "DNG" },
+    { "MSVG", "SVG" },
+    { "NEF", "DNG" },
+    { "NETSCAPE", "MAGICK" },
+    { "O", "RAW" },
+    { "ORF", "DNG" },
+    { "OTF", "TTF" },
+    { "P7", "PNM" },
+    { "PAL", "UYVY" },
+    { "PAM", "PNM" },
+    { "PBM", "PNM" },
+    { "PCDS", "PCD" },
+    { "PDFA", "PDF" },
+    { "PEF", "DNG" },
+    { "PEF", "DNG" },
+    { "PFA", "TTF" },
+    { "PFB", "TTF" },
+    { "PFM", "PNM" },
+    { "PGM", "PNM" },
+    { "PGX", "JP2" },
+    { "PICON", "XPM" },
+    { "PJPEG", "JPEG" },
+    { "PM", "XPM" },
+    { "PNG24", "PNG" },
+    { "PNG32", "PNG" },
+    { "PNG8", "PNG" },
+    { "PPM", "PNM" },
+    { "PSB", "PSD" },
+    { "PTIF", "TIFF" },
+    { "RADIAL-GRADIENT", "GRADIENT" },
+    { "RAF", "DNG" },
+    { "RAS", "SUN" },
+    { "RGBA", "RGB" },
+    { "RGBO", "RGB" },
+    { "R", "RAW" },
+    { "ROSE", "MAGICK" },
+    { "SHTML", "HTML" },
+    { "SR2", "DNG" },
+    { "SRF", "DNG" },
+    { "SVGZ", "SVG" },
+    { "TEXT", "TXT" },
+    { "TIFF64", "TIFF" },
+    { "TIF", "TIFF" },
+    { "TTC", "TTF" },
+    { "UBRL", "BRAILLE" },
+    { "VDA", "TGA" },
+    { "VST", "TGA" },
+    { "WIZARD", "MAGICK" },
+    { "WMV", "MPEG" },
+    { "WMFWIN32", "EMF" },
+    { "WMZ", "WMF" },
+    { "X3f", "DNG" },
+    { "XMP", "META" },
+    { "XTRNARRAY", "XTRN" },
+    { "XTRNBLOB", "XTRN" },
+    { "XTRNFILE", "XTRN" },
+    { "XTRNIMAGE", "XTRN" },
+    { "XV", "VIFF" },
+    { "Y", "RAW" },
+    { "YCbCrA", "YCbCr" }
+ };
+
+static SemaphoreInfo
+  *coder_semaphore = (SemaphoreInfo *) NULL;
+
+static SplayTreeInfo
+  *coder_list = (SplayTreeInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_coder = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeCoderList(ExceptionInfo *),
+  LoadCoderLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o d e r C o m p o n e n t G e n e s i s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CoderComponentGenesis() instantiates the coder component.
+%
+%  The format of the CoderComponentGenesis method is:
+%
+%      MagickBooleanType CoderComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType CoderComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&coder_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o d e r C o m p o n e n t T e r m i n u s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CoderComponentTerminus() destroys the coder component.
+%
+%  The format of the CoderComponentTerminus method is:
+%
+%      CoderComponentTerminus(void)
+%
+*/
+MagickExport void CoderComponentTerminus(void)
+{
+  if (coder_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&coder_semaphore);
+  LockSemaphoreInfo(coder_semaphore);
+  if (coder_list != (SplayTreeInfo *) NULL)
+    coder_list=DestroySplayTree(coder_list);
+  instantiate_coder=MagickFalse;
+  UnlockSemaphoreInfo(coder_semaphore);
+  DestroySemaphoreInfo(&coder_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C o d e r I n f o                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCoderInfo searches the coder list for the specified name and if found
+%  returns attributes for that coder.
+%
+%  The format of the GetCoderInfo method is:
+%
+%      const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the coder name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const CoderInfo *GetCoderInfo(const char *name,
+  ExceptionInfo *exception)
+{
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((coder_list == (SplayTreeInfo *) NULL) ||
+      (instantiate_coder == MagickFalse))
+    if (InitializeCoderList(exception) == MagickFalse)
+      return((const CoderInfo *) NULL);
+  if ((coder_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(coder_list) == 0))
+    return((const CoderInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    {
+      ResetSplayTreeIterator(coder_list);
+      return((const CoderInfo *) GetNextValueInSplayTree(coder_list));
+    }
+  return((const CoderInfo *) GetValueFromSplayTree(coder_list,name));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o d e r I n f o L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCoderInfoList() returns any coder_map that match the specified pattern.
+%  The format of the GetCoderInfoList function is:
+%
+%      const CoderInfo **GetCoderInfoList(const char *pattern,
+%        size_t *number_coders,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_coders:  This integer returns the number of coders in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static int CoderInfoCompare(const void *x,const void *y)
+{
+  const CoderInfo
+    **p,
+    **q;
+
+  p=(const CoderInfo **) x,
+  q=(const CoderInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->name,(*q)->name));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
+  size_t *number_coders,ExceptionInfo *exception)
+{
+  const CoderInfo
+    **coder_map;
+
+  register const CoderInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate coder list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_coders != (size_t *) NULL);
+  *number_coders=0;
+  p=GetCoderInfo("*",exception);
+  if (p == (const CoderInfo *) NULL)
+    return((const CoderInfo **) NULL);
+  coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(coder_list)+1UL,sizeof(*coder_map));
+  if (coder_map == (const CoderInfo **) NULL)
+    return((const CoderInfo **) NULL);
+  /*
+    Generate coder list.
+  */
+  LockSemaphoreInfo(coder_semaphore);
+  ResetSplayTreeIterator(coder_list);
+  p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
+  for (i=0; p != (const CoderInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      coder_map[i++]=p;
+    p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
+  }
+  UnlockSemaphoreInfo(coder_semaphore);
+  qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
+  coder_map[i]=(CoderInfo *) NULL;
+  *number_coders=(size_t) i;
+  return(coder_map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o d e r L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCoderList() returns any coder_map that match the specified pattern.
+%
+%  The format of the GetCoderList function is:
+%
+%      char **GetCoderList(const char *pattern,size_t *number_coders,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_coders:  This integer returns the number of coders in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static int CoderCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+MagickExport char **GetCoderList(const char *pattern,
+  size_t *number_coders,ExceptionInfo *exception)
+{
+  char
+    **coder_map;
+
+  register const CoderInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate coder list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_coders != (size_t *) NULL);
+  *number_coders=0;
+  p=GetCoderInfo("*",exception);
+  if (p == (const CoderInfo *) NULL)
+    return((char **) NULL);
+  coder_map=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(coder_list)+1UL,sizeof(*coder_map));
+  if (coder_map == (char **) NULL)
+    return((char **) NULL);
+  /*
+    Generate coder list.
+  */
+  LockSemaphoreInfo(coder_semaphore);
+  ResetSplayTreeIterator(coder_list);
+  p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
+  for (i=0; p != (const CoderInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      coder_map[i++]=ConstantString(p->name);
+    p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
+  }
+  UnlockSemaphoreInfo(coder_semaphore);
+  qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
+  coder_map[i]=(char *) NULL;
+  *number_coders=(size_t) i;
+  return(coder_map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e C o d e r L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeCoderList() initializes the coder list.
+%
+%  The format of the InitializeCoderList method is:
+%
+%      MagickBooleanType InitializeCoderList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeCoderList(ExceptionInfo *exception)
+{
+  if ((coder_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_coder == MagickFalse))
+    {
+      if (coder_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&coder_semaphore);
+      LockSemaphoreInfo(coder_semaphore);
+      if ((coder_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_coder == MagickFalse))
+        {
+          (void) LoadCoderLists(MagickCoderFilename,exception);
+          instantiate_coder=MagickTrue;
+        }
+      UnlockSemaphoreInfo(coder_semaphore);
+    }
+  return(coder_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t C o d e r I n f o                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListCoderInfo() lists the coder info to a file.
+%
+%  The format of the ListCoderInfo coder is:
+%
+%      MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListCoderInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const char
+    *path;
+
+  const CoderInfo
+    **coder_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_coders;
+
+  ssize_t
+    j;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  coder_info=GetCoderInfoList("*",&number_coders,exception);
+  if (coder_info == (const CoderInfo **) NULL)
+    return(MagickFalse);
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_coders; i++)
+  {
+    if (coder_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,coder_info[i]->path) != 0))
+      {
+        if (coder_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path);
+        (void) FormatLocaleFile(file,"Magick      Coder\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=coder_info[i]->path;
+    (void) FormatLocaleFile(file,"%s",coder_info[i]->magick);
+    for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 11; j++)
+      (void) FormatLocaleFile(file," ");
+    if (coder_info[i]->name != (char *) NULL)
+      (void) FormatLocaleFile(file,"%s",coder_info[i]->name);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
+  (void) fflush(file);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d C o d e r L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadCoderList() loads the coder configuration file which provides a
+%  mapping between coder attributes and a coder name.
+%
+%  The format of the LoadCoderList coder is:
+%
+%      MagickBooleanType LoadCoderList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The coder list in XML format.
+%
+%    o filename:  The coder list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void *DestroyCoderNode(void *coder_info)
+{
+  register CoderInfo
+    *p;
+
+  p=(CoderInfo *) coder_info;
+  if (p->exempt == MagickFalse)
+    {
+      if (p->path != (char *) NULL)
+        p->path=DestroyString(p->path);
+      if (p->name != (char *) NULL)
+        p->name=DestroyString(p->name);
+      if (p->magick != (char *) NULL)
+        p->magick=DestroyString(p->magick);
+    }
+  return(RelinquishMagickMemory(p));
+}
+
+static MagickBooleanType LoadCoderList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  CoderInfo
+    *coder_info;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Load the coder map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading coder configuration file \"%s\" ...",filename);
+  if (xml == (const char *) NULL)
+    return(MagickFalse);
+  if (coder_list == (SplayTreeInfo *) NULL)
+    {
+      coder_list=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+        DestroyCoderNode);
+      if (coder_list == (SplayTreeInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  coder_info=(CoderInfo *) NULL;
+  token=AcquireString(xml);
+  for (q=(char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadCoderList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<coder") == 0)
+      {
+        /*
+          Coder element.
+        */
+        coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
+        if (coder_info == (CoderInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(coder_info,0,sizeof(*coder_info));
+        coder_info->path=ConstantString(filename);
+        coder_info->exempt=MagickFalse;
+        coder_info->signature=MagickSignature;
+        continue;
+      }
+    if (coder_info == (CoderInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AddValueToSplayTree(coder_list,ConstantString(
+          coder_info->magick),coder_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            coder_info->magick);
+        coder_info=(CoderInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'M':
+      case 'm':
+      {
+        if (LocaleCompare((char *) keyword,"magick") == 0)
+          {
+            coder_info->magick=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'N':
+      case 'n':
+      {
+        if (LocaleCompare((char *) keyword,"name") == 0)
+          {
+            coder_info->name=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            coder_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d C o d e r L i s t s                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadCoderLists() loads one or more coder configuration file which
+%  provides a mapping between coder attributes and a coder name.
+%
+%  The format of the LoadCoderLists coder is:
+%
+%      MagickBooleanType LoadCoderLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadCoderLists(const char *filename,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Load built-in coder map.
+  */
+  status=MagickFalse;
+  if (coder_list == (SplayTreeInfo *) NULL)
+    {
+      coder_list=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+        DestroyCoderNode);
+      if (coder_list == (SplayTreeInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++)
+  {
+    CoderInfo
+      *coder_info;
+
+    register const CoderMapInfo
+      *p;
+
+    p=CoderMap+i;
+    coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
+    if (coder_info == (CoderInfo *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
+        continue;
+      }
+    (void) ResetMagickMemory(coder_info,0,sizeof(*coder_info));
+    coder_info->path=(char *) "[built-in]";
+    coder_info->magick=(char *) p->magick;
+    coder_info->name=(char *) p->name;
+    coder_info->exempt=MagickTrue;
+    coder_info->signature=MagickSignature;
+    status=AddValueToSplayTree(coder_list,ConstantString(coder_info->magick),
+      coder_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
+  }
+  /*
+    Load external coder map.
+  */
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadCoderList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
diff --git a/MagickCore/coder.h b/MagickCore/coder.h
new file mode 100644
index 0000000..2d993bc
--- /dev/null
+++ b/MagickCore/coder.h
@@ -0,0 +1,58 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image coder methods.
+*/
+#ifndef _MAGICKCORE_CODER_H
+#define _MAGICKCORE_CODER_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _CoderInfo
+{
+  char
+    *path,
+    *magick,
+    *name;
+                                                                                
+  MagickBooleanType
+    exempt,
+    stealth;
+                                                                                
+  size_t
+    signature;
+} CoderInfo;
+
+extern MagickExport char
+  **GetCoderList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const CoderInfo
+  *GetCoderInfo(const char *,ExceptionInfo *),
+  **GetCoderInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  CoderComponentGenesis(void),
+  ListCoderInfo(FILE *,ExceptionInfo *);
+
+MagickExport void
+  CoderComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/color-private.h b/MagickCore/color-private.h
new file mode 100644
index 0000000..63ba296
--- /dev/null
+++ b/MagickCore/color-private.h
@@ -0,0 +1,29 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image color methods.
+*/
+#ifndef _MAGICKCORE_COLOR_PRIVATE_H
+#define _MAGICKCORE_COLOR_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/color.c b/MagickCore/color.c
new file mode 100644
index 0000000..84e1ff4
--- /dev/null
+++ b/MagickCore/color.c
@@ -0,0 +1,2630 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                       CCCC   OOO   L       OOO   RRRR                       %
+%                      C      O   O  L      O   O  R   R                      %
+%                      C      O   O  L      O   O  RRRR                       %
+%                      C      O   O  L      O   O  R R                        %
+%                       CCCC   OOO   LLLLL   OOO   R  R                       %
+%                                                                             %
+%                                                                             %
+%                          MagickCore Color Methods                           %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  We use linked-lists because splay-trees do not currently support duplicate
+%  key / value pairs (.e.g X11 green compliance and SVG green compliance).
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define ColorFilename  "colors.xml"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _ColorMapInfo
+{
+  const char
+    *name;
+
+  const unsigned char
+    red,
+    green,
+    blue;
+
+  const float
+    alpha;
+
+  const ssize_t
+    compliance;
+} ColorMapInfo;
+
+/*
+  Static declarations.
+*/
+static const ColorMapInfo
+  ColorMap[] =
+  {
+    { "none", 0, 0, 0, 0, SVGCompliance | XPMCompliance },
+    { "black", 0, 0, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "red", 255, 0, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "magenta", 255, 0, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "green", 0, 128, 0, 1, SVGCompliance },
+    { "cyan", 0, 255, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "blue", 0, 0, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "yellow", 255, 255, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "white", 255, 255, 255, 1, SVGCompliance | X11Compliance },
+    { "AliceBlue", 240, 248, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "AntiqueWhite", 250, 235, 215, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "AntiqueWhite1", 255, 239, 219, 1, X11Compliance },
+    { "AntiqueWhite2", 238, 223, 204, 1, X11Compliance },
+    { "AntiqueWhite3", 205, 192, 176, 1, X11Compliance },
+    { "AntiqueWhite4", 139, 131, 120, 1, X11Compliance },
+    { "aqua", 0, 255, 255, 1, SVGCompliance },
+    { "aquamarine", 127, 255, 212, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "aquamarine1", 127, 255, 212, 1, X11Compliance },
+    { "aquamarine2", 118, 238, 198, 1, X11Compliance },
+    { "aquamarine3", 102, 205, 170, 1, X11Compliance },
+    { "aquamarine4", 69, 139, 116, 1, X11Compliance },
+    { "azure", 240, 255, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "azure1", 240, 255, 255, 1, X11Compliance },
+    { "azure2", 224, 238, 238, 1, X11Compliance },
+    { "azure3", 193, 205, 205, 1, X11Compliance },
+    { "azure4", 131, 139, 139, 1, X11Compliance },
+    { "beige", 245, 245, 220, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "bisque", 255, 228, 196, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "bisque1", 255, 228, 196, 1, X11Compliance },
+    { "bisque2", 238, 213, 183, 1, X11Compliance },
+    { "bisque3", 205, 183, 158, 1, X11Compliance },
+    { "bisque4", 139, 125, 107, 1, X11Compliance },
+    { "BlanchedAlmond", 255, 235, 205, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "blue1", 0, 0, 255, 1, X11Compliance },
+    { "blue2", 0, 0, 238, 1, X11Compliance },
+    { "blue3", 0, 0, 205, 1, X11Compliance },
+    { "blue4", 0, 0, 139, 1, X11Compliance },
+    { "BlueViolet", 138, 43, 226, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "brown", 165, 42, 42, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "brown1", 255, 64, 64, 1, X11Compliance },
+    { "brown2", 238, 59, 59, 1, X11Compliance },
+    { "brown3", 205, 51, 51, 1, X11Compliance },
+    { "brown4", 139, 35, 35, 1, X11Compliance },
+    { "burlywood", 222, 184, 135, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "burlywood1", 255, 211, 155, 1, X11Compliance },
+    { "burlywood2", 238, 197, 145, 1, X11Compliance },
+    { "burlywood3", 205, 170, 125, 1, X11Compliance },
+    { "burlywood4", 139, 115, 85, 1, X11Compliance },
+    { "CadetBlue", 95, 158, 160, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "CadetBlue1", 152, 245, 255, 1, X11Compliance },
+    { "CadetBlue2", 142, 229, 238, 1, X11Compliance },
+    { "CadetBlue3", 122, 197, 205, 1, X11Compliance },
+    { "CadetBlue4", 83, 134, 139, 1, X11Compliance },
+    { "chartreuse", 127, 255, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "chartreuse1", 127, 255, 0, 1, X11Compliance },
+    { "chartreuse2", 118, 238, 0, 1, X11Compliance },
+    { "chartreuse3", 102, 205, 0, 1, X11Compliance },
+    { "chartreuse4", 69, 139, 0, 1, X11Compliance },
+    { "chocolate", 210, 105, 30, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "chocolate1", 255, 127, 36, 1, X11Compliance },
+    { "chocolate2", 238, 118, 33, 1, X11Compliance },
+    { "chocolate3", 205, 102, 29, 1, X11Compliance },
+    { "chocolate4", 139, 69, 19, 1, X11Compliance },
+    { "coral", 255, 127, 80, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "coral1", 255, 114, 86, 1, X11Compliance },
+    { "coral2", 238, 106, 80, 1, X11Compliance },
+    { "coral3", 205, 91, 69, 1, X11Compliance },
+    { "coral4", 139, 62, 47, 1, X11Compliance },
+    { "CornflowerBlue", 100, 149, 237, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "cornsilk", 255, 248, 220, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "cornsilk1", 255, 248, 220, 1, X11Compliance },
+    { "cornsilk2", 238, 232, 205, 1, X11Compliance },
+    { "cornsilk3", 205, 200, 177, 1, X11Compliance },
+    { "cornsilk4", 139, 136, 120, 1, X11Compliance },
+    { "crimson", 220, 20, 60, 1, SVGCompliance },
+    { "cyan1", 0, 255, 255, 1, X11Compliance },
+    { "cyan2", 0, 238, 238, 1, X11Compliance },
+    { "cyan3", 0, 205, 205, 1, X11Compliance },
+    { "cyan4", 0, 139, 139, 1, X11Compliance },
+    { "DarkBlue", 0, 0, 139, 1, SVGCompliance | X11Compliance },
+    { "DarkCyan", 0, 139, 139, 1, SVGCompliance | X11Compliance },
+    { "DarkGoldenrod", 184, 134, 11, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkGoldenrod1", 255, 185, 15, 1, X11Compliance },
+    { "DarkGoldenrod2", 238, 173, 14, 1, X11Compliance },
+    { "DarkGoldenrod3", 205, 149, 12, 1, X11Compliance },
+    { "DarkGoldenrod4", 139, 101, 8, 1, X11Compliance },
+    { "DarkGray", 169, 169, 169, 1, SVGCompliance | X11Compliance },
+    { "DarkGreen", 0, 100, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkGrey", 169, 169, 169, 1, SVGCompliance | X11Compliance },
+    { "DarkKhaki", 189, 183, 107, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkMagenta", 139, 0, 139, 1, SVGCompliance | X11Compliance },
+    { "DarkOliveGreen", 85, 107, 47, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkOliveGreen1", 202, 255, 112, 1, X11Compliance },
+    { "DarkOliveGreen2", 188, 238, 104, 1, X11Compliance },
+    { "DarkOliveGreen3", 162, 205, 90, 1, X11Compliance },
+    { "DarkOliveGreen4", 110, 139, 61, 1, X11Compliance },
+    { "DarkOrange", 255, 140, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkOrange1", 255, 127, 0, 1, X11Compliance },
+    { "DarkOrange2", 238, 118, 0, 1, X11Compliance },
+    { "DarkOrange3", 205, 102, 0, 1, X11Compliance },
+    { "DarkOrange4", 139, 69, 0, 1, X11Compliance },
+    { "DarkOrchid", 153, 50, 204, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkOrchid1", 191, 62, 255, 1, X11Compliance },
+    { "DarkOrchid2", 178, 58, 238, 1, X11Compliance },
+    { "DarkOrchid3", 154, 50, 205, 1, X11Compliance },
+    { "DarkOrchid4", 104, 34, 139, 1, X11Compliance },
+    { "DarkRed", 139, 0, 0, 1, SVGCompliance | X11Compliance },
+    { "DarkSalmon", 233, 150, 122, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkSeaGreen", 143, 188, 143, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkSeaGreen1", 193, 255, 193, 1, X11Compliance },
+    { "DarkSeaGreen2", 180, 238, 180, 1, X11Compliance },
+    { "DarkSeaGreen3", 155, 205, 155, 1, X11Compliance },
+    { "DarkSeaGreen4", 105, 139, 105, 1, X11Compliance },
+    { "DarkSlateBlue", 72, 61, 139, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkSlateGray", 47, 79, 79, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkSlateGray1", 151, 255, 255, 1, X11Compliance },
+    { "DarkSlateGray2", 141, 238, 238, 1, X11Compliance },
+    { "DarkSlateGray3", 121, 205, 205, 1, X11Compliance },
+    { "DarkSlateGray4", 82, 139, 139, 1, X11Compliance },
+    { "DarkSlateGrey", 47, 79, 79, 1, SVGCompliance | X11Compliance },
+    { "DarkTurquoise", 0, 206, 209, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DarkViolet", 148, 0, 211, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DeepPink", 255, 20, 147, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DeepPink1", 255, 20, 147, 1, X11Compliance },
+    { "DeepPink2", 238, 18, 137, 1, X11Compliance },
+    { "DeepPink3", 205, 16, 118, 1, X11Compliance },
+    { "DeepPink4", 139, 10, 80, 1, X11Compliance },
+    { "DeepSkyBlue", 0, 191, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DeepSkyBlue1", 0, 191, 255, 1, X11Compliance },
+    { "DeepSkyBlue2", 0, 178, 238, 1, X11Compliance },
+    { "DeepSkyBlue3", 0, 154, 205, 1, X11Compliance },
+    { "DeepSkyBlue4", 0, 104, 139, 1, X11Compliance },
+    { "DimGray", 105, 105, 105, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DimGrey", 105, 105, 105, 1, SVGCompliance | X11Compliance },
+    { "DodgerBlue", 30, 144, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "DodgerBlue1", 30, 144, 255, 1, X11Compliance },
+    { "DodgerBlue2", 28, 134, 238, 1, X11Compliance },
+    { "DodgerBlue3", 24, 116, 205, 1, X11Compliance },
+    { "DodgerBlue4", 16, 78, 139, 1, X11Compliance },
+    { "firebrick", 178, 34, 34, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "firebrick1", 255, 48, 48, 1, X11Compliance },
+    { "firebrick2", 238, 44, 44, 1, X11Compliance },
+    { "firebrick3", 205, 38, 38, 1, X11Compliance },
+    { "firebrick4", 139, 26, 26, 1, X11Compliance },
+    { "FloralWhite", 255, 250, 240, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "ForestGreen", 34, 139, 34, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "fractal", 128, 128, 128, 1, SVGCompliance },
+    { "freeze", 0, 0, 0, 0, SVGCompliance },
+    { "fuchsia", 255, 0, 255, 1, SVGCompliance },
+    { "gainsboro", 220, 220, 220, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "GhostWhite", 248, 248, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "gold", 255, 215, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "gold1", 255, 215, 0, 1, X11Compliance },
+    { "gold2", 238, 201, 0, 1, X11Compliance },
+    { "gold3", 205, 173, 0, 1, X11Compliance },
+    { "gold4", 139, 117, 0, 1, X11Compliance },
+    { "goldenrod", 218, 165, 32, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "goldenrod1", 255, 193, 37, 1, X11Compliance },
+    { "goldenrod2", 238, 180, 34, 1, X11Compliance },
+    { "goldenrod3", 205, 155, 29, 1, X11Compliance },
+    { "goldenrod4", 139, 105, 20, 1, X11Compliance },
+    { "gray", 126, 126, 126, 1, SVGCompliance },
+    { "gray", 190, 190, 190, 1, X11Compliance | XPMCompliance },
+    { "gray0", 0, 0, 0, 1, X11Compliance | XPMCompliance },
+    { "gray1", 3, 3, 3, 1, X11Compliance | XPMCompliance },
+    { "gray10", 26, 26, 26, 1, X11Compliance | XPMCompliance },
+    { "gray100", 255, 255, 255, 1, X11Compliance | XPMCompliance },
+    { "gray100", 255, 255, 255, 1, X11Compliance | XPMCompliance },
+    { "gray11", 28, 28, 28, 1, X11Compliance | XPMCompliance },
+    { "gray12", 31, 31, 31, 1, X11Compliance | XPMCompliance },
+    { "gray13", 33, 33, 33, 1, X11Compliance | XPMCompliance },
+    { "gray14", 36, 36, 36, 1, X11Compliance | XPMCompliance },
+    { "gray15", 38, 38, 38, 1, X11Compliance | XPMCompliance },
+    { "gray16", 41, 41, 41, 1, X11Compliance | XPMCompliance },
+    { "gray17", 43, 43, 43, 1, X11Compliance | XPMCompliance },
+    { "gray18", 46, 46, 46, 1, X11Compliance | XPMCompliance },
+    { "gray19", 48, 48, 48, 1, X11Compliance | XPMCompliance },
+    { "gray2", 5, 5, 5, 1, X11Compliance | XPMCompliance },
+    { "gray20", 51, 51, 51, 1, X11Compliance | XPMCompliance },
+    { "gray21", 54, 54, 54, 1, X11Compliance | XPMCompliance },
+    { "gray22", 56, 56, 56, 1, X11Compliance | XPMCompliance },
+    { "gray23", 59, 59, 59, 1, X11Compliance | XPMCompliance },
+    { "gray24", 61, 61, 61, 1, X11Compliance | XPMCompliance },
+    { "gray25", 64, 64, 64, 1, X11Compliance | XPMCompliance },
+    { "gray26", 66, 66, 66, 1, X11Compliance | XPMCompliance },
+    { "gray27", 69, 69, 69, 1, X11Compliance | XPMCompliance },
+    { "gray28", 71, 71, 71, 1, X11Compliance | XPMCompliance },
+    { "gray29", 74, 74, 74, 1, X11Compliance | XPMCompliance },
+    { "gray3", 8, 8, 8, 1, X11Compliance | XPMCompliance },
+    { "gray30", 77, 77, 77, 1, X11Compliance | XPMCompliance },
+    { "gray31", 79, 79, 79, 1, X11Compliance | XPMCompliance },
+    { "gray32", 82, 82, 82, 1, X11Compliance | XPMCompliance },
+    { "gray33", 84, 84, 84, 1, X11Compliance | XPMCompliance },
+    { "gray34", 87, 87, 87, 1, X11Compliance | XPMCompliance },
+    { "gray35", 89, 89, 89, 1, X11Compliance | XPMCompliance },
+    { "gray36", 92, 92, 92, 1, X11Compliance | XPMCompliance },
+    { "gray37", 94, 94, 94, 1, X11Compliance | XPMCompliance },
+    { "gray38", 97, 97, 97, 1, X11Compliance | XPMCompliance },
+    { "gray39", 99, 99, 99, 1, X11Compliance | XPMCompliance },
+    { "gray4", 10, 10, 10, 1, X11Compliance | XPMCompliance },
+    { "gray40", 102, 102, 102, 1, X11Compliance | XPMCompliance },
+    { "gray41", 105, 105, 105, 1, X11Compliance | XPMCompliance },
+    { "gray42", 107, 107, 107, 1, X11Compliance | XPMCompliance },
+    { "gray43", 110, 110, 110, 1, X11Compliance | XPMCompliance },
+    { "gray44", 112, 112, 112, 1, X11Compliance | XPMCompliance },
+    { "gray45", 115, 115, 115, 1, X11Compliance | XPMCompliance },
+    { "gray46", 117, 117, 117, 1, X11Compliance | XPMCompliance },
+    { "gray47", 120, 120, 120, 1, X11Compliance | XPMCompliance },
+    { "gray48", 122, 122, 122, 1, X11Compliance | XPMCompliance },
+    { "gray49", 125, 125, 125, 1, X11Compliance | XPMCompliance },
+    { "gray5", 13, 13, 13, 1, X11Compliance | XPMCompliance },
+    { "gray50", 127, 127, 127, 1, X11Compliance | XPMCompliance },
+    { "gray51", 130, 130, 130, 1, X11Compliance | XPMCompliance },
+    { "gray52", 133, 133, 133, 1, X11Compliance | XPMCompliance },
+    { "gray53", 135, 135, 135, 1, X11Compliance | XPMCompliance },
+    { "gray54", 138, 138, 138, 1, X11Compliance | XPMCompliance },
+    { "gray55", 140, 140, 140, 1, X11Compliance | XPMCompliance },
+    { "gray56", 143, 143, 143, 1, X11Compliance | XPMCompliance },
+    { "gray57", 145, 145, 145, 1, X11Compliance | XPMCompliance },
+    { "gray58", 148, 148, 148, 1, X11Compliance | XPMCompliance },
+    { "gray59", 150, 150, 150, 1, X11Compliance | XPMCompliance },
+    { "gray6", 15, 15, 15, 1, X11Compliance | XPMCompliance },
+    { "gray60", 153, 153, 153, 1, X11Compliance | XPMCompliance },
+    { "gray61", 156, 156, 156, 1, X11Compliance | XPMCompliance },
+    { "gray62", 158, 158, 158, 1, X11Compliance | XPMCompliance },
+    { "gray63", 161, 161, 161, 1, X11Compliance | XPMCompliance },
+    { "gray64", 163, 163, 163, 1, X11Compliance | XPMCompliance },
+    { "gray65", 166, 166, 166, 1, X11Compliance | XPMCompliance },
+    { "gray66", 168, 168, 168, 1, X11Compliance | XPMCompliance },
+    { "gray67", 171, 171, 171, 1, X11Compliance | XPMCompliance },
+    { "gray68", 173, 173, 173, 1, X11Compliance | XPMCompliance },
+    { "gray69", 176, 176, 176, 1, X11Compliance | XPMCompliance },
+    { "gray7", 18, 18, 18, 1, X11Compliance | XPMCompliance },
+    { "gray70", 179, 179, 179, 1, X11Compliance | XPMCompliance },
+    { "gray71", 181, 181, 181, 1, X11Compliance | XPMCompliance },
+    { "gray72", 184, 184, 184, 1, X11Compliance | XPMCompliance },
+    { "gray73", 186, 186, 186, 1, X11Compliance | XPMCompliance },
+    { "gray74", 189, 189, 189, 1, X11Compliance | XPMCompliance },
+    { "gray75", 191, 191, 191, 1, X11Compliance | XPMCompliance },
+    { "gray76", 194, 194, 194, 1, X11Compliance | XPMCompliance },
+    { "gray77", 196, 196, 196, 1, X11Compliance | XPMCompliance },
+    { "gray78", 199, 199, 199, 1, X11Compliance | XPMCompliance },
+    { "gray79", 201, 201, 201, 1, X11Compliance | XPMCompliance },
+    { "gray8", 20, 20, 20, 1, X11Compliance | XPMCompliance },
+    { "gray80", 204, 204, 204, 1, X11Compliance | XPMCompliance },
+    { "gray81", 207, 207, 207, 1, X11Compliance | XPMCompliance },
+    { "gray82", 209, 209, 209, 1, X11Compliance | XPMCompliance },
+    { "gray83", 212, 212, 212, 1, X11Compliance | XPMCompliance },
+    { "gray84", 214, 214, 214, 1, X11Compliance | XPMCompliance },
+    { "gray85", 217, 217, 217, 1, X11Compliance | XPMCompliance },
+    { "gray86", 219, 219, 219, 1, X11Compliance | XPMCompliance },
+    { "gray87", 222, 222, 222, 1, X11Compliance | XPMCompliance },
+    { "gray88", 224, 224, 224, 1, X11Compliance | XPMCompliance },
+    { "gray89", 227, 227, 227, 1, X11Compliance | XPMCompliance },
+    { "gray9", 23, 23, 23, 1, X11Compliance | XPMCompliance },
+    { "gray90", 229, 229, 229, 1, X11Compliance | XPMCompliance },
+    { "gray91", 232, 232, 232, 1, X11Compliance | XPMCompliance },
+    { "gray92", 235, 235, 235, 1, X11Compliance | XPMCompliance },
+    { "gray93", 237, 237, 237, 1, X11Compliance | XPMCompliance },
+    { "gray94", 240, 240, 240, 1, X11Compliance | XPMCompliance },
+    { "gray95", 242, 242, 242, 1, X11Compliance | XPMCompliance },
+    { "gray96", 245, 245, 245, 1, X11Compliance | XPMCompliance },
+    { "gray97", 247, 247, 247, 1, X11Compliance | XPMCompliance },
+    { "gray98", 250, 250, 250, 1, X11Compliance | XPMCompliance },
+    { "gray99", 252, 252, 252, 1, X11Compliance | XPMCompliance },
+    { "green", 0, 255, 0, 1, X11Compliance | XPMCompliance },
+    { "green1", 0, 255, 0, 1, X11Compliance },
+    { "green2", 0, 238, 0, 1, X11Compliance },
+    { "green3", 0, 205, 0, 1, X11Compliance },
+    { "green4", 0, 139, 0, 1, X11Compliance },
+    { "GreenYellow", 173, 255, 47, 1, X11Compliance | XPMCompliance },
+    { "grey", 190, 190, 190, 1, SVGCompliance | X11Compliance },
+    { "grey0", 0, 0, 0, 1, SVGCompliance | X11Compliance },
+    { "grey1", 3, 3, 3, 1, SVGCompliance | X11Compliance },
+    { "grey10", 26, 26, 26, 1, SVGCompliance | X11Compliance },
+    { "grey100", 255, 255, 255, 1, SVGCompliance | X11Compliance },
+    { "grey11", 28, 28, 28, 1, SVGCompliance | X11Compliance },
+    { "grey12", 31, 31, 31, 1, SVGCompliance | X11Compliance },
+    { "grey13", 33, 33, 33, 1, SVGCompliance | X11Compliance },
+    { "grey14", 36, 36, 36, 1, SVGCompliance | X11Compliance },
+    { "grey15", 38, 38, 38, 1, SVGCompliance | X11Compliance },
+    { "grey16", 41, 41, 41, 1, SVGCompliance | X11Compliance },
+    { "grey17", 43, 43, 43, 1, SVGCompliance | X11Compliance },
+    { "grey18", 46, 46, 46, 1, SVGCompliance | X11Compliance },
+    { "grey19", 48, 48, 48, 1, SVGCompliance | X11Compliance },
+    { "grey2", 5, 5, 5, 1, SVGCompliance | X11Compliance },
+    { "grey20", 51, 51, 51, 1, SVGCompliance | X11Compliance },
+    { "grey21", 54, 54, 54, 1, SVGCompliance | X11Compliance },
+    { "grey22", 56, 56, 56, 1, SVGCompliance | X11Compliance },
+    { "grey23", 59, 59, 59, 1, SVGCompliance | X11Compliance },
+    { "grey24", 61, 61, 61, 1, SVGCompliance | X11Compliance },
+    { "grey25", 64, 64, 64, 1, SVGCompliance | X11Compliance },
+    { "grey26", 66, 66, 66, 1, SVGCompliance | X11Compliance },
+    { "grey27", 69, 69, 69, 1, SVGCompliance | X11Compliance },
+    { "grey28", 71, 71, 71, 1, SVGCompliance | X11Compliance },
+    { "grey29", 74, 74, 74, 1, SVGCompliance | X11Compliance },
+    { "grey3", 8, 8, 8, 1, SVGCompliance | X11Compliance },
+    { "grey30", 77, 77, 77, 1, SVGCompliance | X11Compliance },
+    { "grey31", 79, 79, 79, 1, SVGCompliance | X11Compliance },
+    { "grey32", 82, 82, 82, 1, SVGCompliance | X11Compliance },
+    { "grey33", 84, 84, 84, 1, SVGCompliance | X11Compliance },
+    { "grey34", 87, 87, 87, 1, SVGCompliance | X11Compliance },
+    { "grey35", 89, 89, 89, 1, SVGCompliance | X11Compliance },
+    { "grey36", 92, 92, 92, 1, SVGCompliance | X11Compliance },
+    { "grey37", 94, 94, 94, 1, SVGCompliance | X11Compliance },
+    { "grey38", 97, 97, 97, 1, SVGCompliance | X11Compliance },
+    { "grey39", 99, 99, 99, 1, SVGCompliance | X11Compliance },
+    { "grey4", 10, 10, 10, 1, SVGCompliance | X11Compliance },
+    { "grey40", 102, 102, 102, 1, SVGCompliance | X11Compliance },
+    { "grey41", 105, 105, 105, 1, SVGCompliance | X11Compliance },
+    { "grey42", 107, 107, 107, 1, SVGCompliance | X11Compliance },
+    { "grey43", 110, 110, 110, 1, SVGCompliance | X11Compliance },
+    { "grey44", 112, 112, 112, 1, SVGCompliance | X11Compliance },
+    { "grey45", 115, 115, 115, 1, SVGCompliance | X11Compliance },
+    { "grey46", 117, 117, 117, 1, SVGCompliance | X11Compliance },
+    { "grey47", 120, 120, 120, 1, SVGCompliance | X11Compliance },
+    { "grey48", 122, 122, 122, 1, SVGCompliance | X11Compliance },
+    { "grey49", 125, 125, 125, 1, SVGCompliance | X11Compliance },
+    { "grey5", 13, 13, 13, 1, SVGCompliance | X11Compliance },
+    { "grey50", 127, 127, 127, 1, SVGCompliance | X11Compliance },
+    { "grey51", 130, 130, 130, 1, SVGCompliance | X11Compliance },
+    { "grey52", 133, 133, 133, 1, SVGCompliance | X11Compliance },
+    { "grey53", 135, 135, 135, 1, SVGCompliance | X11Compliance },
+    { "grey54", 138, 138, 138, 1, SVGCompliance | X11Compliance },
+    { "grey55", 140, 140, 140, 1, SVGCompliance | X11Compliance },
+    { "grey56", 143, 143, 143, 1, SVGCompliance | X11Compliance },
+    { "grey57", 145, 145, 145, 1, SVGCompliance | X11Compliance },
+    { "grey58", 148, 148, 148, 1, SVGCompliance | X11Compliance },
+    { "grey59", 150, 150, 150, 1, SVGCompliance | X11Compliance },
+    { "grey6", 15, 15, 15, 1, SVGCompliance | X11Compliance },
+    { "grey60", 153, 153, 153, 1, SVGCompliance | X11Compliance },
+    { "grey61", 156, 156, 156, 1, SVGCompliance | X11Compliance },
+    { "grey62", 158, 158, 158, 1, SVGCompliance | X11Compliance },
+    { "grey63", 161, 161, 161, 1, SVGCompliance | X11Compliance },
+    { "grey64", 163, 163, 163, 1, SVGCompliance | X11Compliance },
+    { "grey65", 166, 166, 166, 1, SVGCompliance | X11Compliance },
+    { "grey66", 168, 168, 168, 1, SVGCompliance | X11Compliance },
+    { "grey67", 171, 171, 171, 1, SVGCompliance | X11Compliance },
+    { "grey68", 173, 173, 173, 1, SVGCompliance | X11Compliance },
+    { "grey69", 176, 176, 176, 1, SVGCompliance | X11Compliance },
+    { "grey7", 18, 18, 18, 1, SVGCompliance | X11Compliance },
+    { "grey70", 179, 179, 179, 1, SVGCompliance | X11Compliance },
+    { "grey71", 181, 181, 181, 1, SVGCompliance | X11Compliance },
+    { "grey72", 184, 184, 184, 1, SVGCompliance | X11Compliance },
+    { "grey73", 186, 186, 186, 1, SVGCompliance | X11Compliance },
+    { "grey74", 189, 189, 189, 1, SVGCompliance | X11Compliance },
+    { "grey75", 191, 191, 191, 1, SVGCompliance | X11Compliance },
+    { "grey76", 194, 194, 194, 1, SVGCompliance | X11Compliance },
+    { "grey77", 196, 196, 196, 1, SVGCompliance | X11Compliance },
+    { "grey78", 199, 199, 199, 1, SVGCompliance | X11Compliance },
+    { "grey79", 201, 201, 201, 1, SVGCompliance | X11Compliance },
+    { "grey8", 20, 20, 20, 1, SVGCompliance | X11Compliance },
+    { "grey80", 204, 204, 204, 1, SVGCompliance | X11Compliance },
+    { "grey81", 207, 207, 207, 1, SVGCompliance | X11Compliance },
+    { "grey82", 209, 209, 209, 1, SVGCompliance | X11Compliance },
+    { "grey83", 212, 212, 212, 1, SVGCompliance | X11Compliance },
+    { "grey84", 214, 214, 214, 1, SVGCompliance | X11Compliance },
+    { "grey85", 217, 217, 217, 1, SVGCompliance | X11Compliance },
+    { "grey86", 219, 219, 219, 1, SVGCompliance | X11Compliance },
+    { "grey87", 222, 222, 222, 1, SVGCompliance | X11Compliance },
+    { "grey88", 224, 224, 224, 1, SVGCompliance | X11Compliance },
+    { "grey89", 227, 227, 227, 1, SVGCompliance | X11Compliance },
+    { "grey9", 23, 23, 23, 1, SVGCompliance | X11Compliance },
+    { "grey90", 229, 229, 229, 1, SVGCompliance | X11Compliance },
+    { "grey91", 232, 232, 232, 1, SVGCompliance | X11Compliance },
+    { "grey92", 235, 235, 235, 1, SVGCompliance | X11Compliance },
+    { "grey93", 237, 237, 237, 1, SVGCompliance | X11Compliance },
+    { "grey94", 240, 240, 240, 1, SVGCompliance | X11Compliance },
+    { "grey95", 242, 242, 242, 1, SVGCompliance | X11Compliance },
+    { "grey96", 245, 245, 245, 1, SVGCompliance | X11Compliance },
+    { "grey97", 247, 247, 247, 1, SVGCompliance | X11Compliance },
+    { "grey98", 250, 250, 250, 1, SVGCompliance | X11Compliance },
+    { "grey99", 252, 252, 252, 1, SVGCompliance | X11Compliance },
+    { "honeydew", 240, 255, 240, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "honeydew1", 240, 255, 240, 1, X11Compliance },
+    { "honeydew2", 224, 238, 224, 1, X11Compliance },
+    { "honeydew3", 193, 205, 193, 1, X11Compliance },
+    { "honeydew4", 131, 139, 131, 1, X11Compliance },
+    { "HotPink", 255, 105, 180, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "HotPink1", 255, 110, 180, 1, X11Compliance },
+    { "HotPink2", 238, 106, 167, 1, X11Compliance },
+    { "HotPink3", 205, 96, 144, 1, X11Compliance },
+    { "HotPink4", 139, 58, 98, 1, X11Compliance },
+    { "IndianRed", 205, 92, 92, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "IndianRed1", 255, 106, 106, 1, X11Compliance },
+    { "IndianRed2", 238, 99, 99, 1, X11Compliance },
+    { "IndianRed3", 205, 85, 85, 1, X11Compliance },
+    { "IndianRed4", 139, 58, 58, 1, X11Compliance },
+    { "indigo", 75, 0, 130, 1, SVGCompliance },
+    { "ivory", 255, 255, 240, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "ivory1", 255, 255, 240, 1, X11Compliance },
+    { "ivory2", 238, 238, 224, 1, X11Compliance },
+    { "ivory3", 205, 205, 193, 1, X11Compliance },
+    { "ivory4", 139, 139, 131, 1, X11Compliance },
+    { "khaki", 240, 230, 140, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "khaki1", 255, 246, 143, 1, X11Compliance },
+    { "khaki2", 238, 230, 133, 1, X11Compliance },
+    { "khaki3", 205, 198, 115, 1, X11Compliance },
+    { "khaki4", 139, 134, 78, 1, X11Compliance },
+    { "lavender", 230, 230, 250, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LavenderBlush", 255, 240, 245, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LavenderBlush1", 255, 240, 245, 1, X11Compliance },
+    { "LavenderBlush2", 238, 224, 229, 1, X11Compliance },
+    { "LavenderBlush3", 205, 193, 197, 1, X11Compliance },
+    { "LavenderBlush4", 139, 131, 134, 1, X11Compliance },
+    { "LawnGreen", 124, 252, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LemonChiffon", 255, 250, 205, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LemonChiffon1", 255, 250, 205, 1, X11Compliance },
+    { "LemonChiffon2", 238, 233, 191, 1, X11Compliance },
+    { "LemonChiffon3", 205, 201, 165, 1, X11Compliance },
+    { "LemonChiffon4", 139, 137, 112, 1, X11Compliance },
+    { "LightBlue", 173, 216, 230, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightBlue1", 191, 239, 255, 1, X11Compliance },
+    { "LightBlue2", 178, 223, 238, 1, X11Compliance },
+    { "LightBlue3", 154, 192, 205, 1, X11Compliance },
+    { "LightBlue4", 104, 131, 139, 1, X11Compliance },
+    { "LightCoral", 240, 128, 128, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightCyan", 224, 255, 255, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightCyan1", 224, 255, 255, 1, X11Compliance },
+    { "LightCyan2", 209, 238, 238, 1, X11Compliance },
+    { "LightCyan3", 180, 205, 205, 1, X11Compliance },
+    { "LightCyan4", 122, 139, 139, 1, X11Compliance },
+    { "LightGoldenrod", 238, 221, 130, 1, X11Compliance | XPMCompliance },
+    { "LightGoldenrod1", 255, 236, 139, 1, X11Compliance },
+    { "LightGoldenrod2", 238, 220, 130, 1, X11Compliance },
+    { "LightGoldenrod3", 205, 190, 112, 1, X11Compliance },
+    { "LightGoldenrod4", 139, 129, 76, 1, X11Compliance },
+    { "LightGoldenrodYellow", 250, 250, 210, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightGray", 211, 211, 211, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightGreen", 144, 238, 144, 1, SVGCompliance | X11Compliance },
+    { "LightGrey", 211, 211, 211, 1, SVGCompliance | X11Compliance },
+    { "LightPink", 255, 182, 193, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightPink1", 255, 174, 185, 1, X11Compliance },
+    { "LightPink2", 238, 162, 173, 1, X11Compliance },
+    { "LightPink3", 205, 140, 149, 1, X11Compliance },
+    { "LightPink4", 139, 95, 101, 1, X11Compliance },
+    { "LightSalmon", 255, 160, 122, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightSalmon1", 255, 160, 122, 1, X11Compliance },
+    { "LightSalmon2", 238, 149, 114, 1, X11Compliance },
+    { "LightSalmon3", 205, 129, 98, 1, X11Compliance },
+    { "LightSalmon4", 139, 87, 66, 1, X11Compliance },
+    { "LightSeaGreen", 32, 178, 170, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightSkyBlue", 135, 206, 250, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightSkyBlue1", 176, 226, 255, 1, X11Compliance },
+    { "LightSkyBlue2", 164, 211, 238, 1, X11Compliance },
+    { "LightSkyBlue3", 141, 182, 205, 1, X11Compliance },
+    { "LightSkyBlue4", 96, 123, 139, 1, X11Compliance },
+    { "LightSlateBlue", 132, 112, 255, 1, X11Compliance | XPMCompliance },
+    { "LightSlateGray", 119, 136, 153, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightSlateGrey", 119, 136, 153, 1, SVGCompliance | X11Compliance },
+    { "LightSteelBlue", 176, 196, 222, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightSteelBlue1", 202, 225, 255, 1, X11Compliance },
+    { "LightSteelBlue2", 188, 210, 238, 1, X11Compliance },
+    { "LightSteelBlue3", 162, 181, 205, 1, X11Compliance },
+    { "LightSteelBlue4", 110, 123, 139, 1, X11Compliance },
+    { "LightYellow", 255, 255, 224, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "LightYellow1", 255, 255, 224, 1, X11Compliance },
+    { "LightYellow2", 238, 238, 209, 1, X11Compliance },
+    { "LightYellow3", 205, 205, 180, 1, X11Compliance },
+    { "LightYellow4", 139, 139, 122, 1, X11Compliance },
+    { "lime", 0, 255, 0, 1, SVGCompliance },
+    { "LimeGreen", 50, 205, 50, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "linen", 250, 240, 230, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "magenta1", 255, 0, 255, 1, X11Compliance },
+    { "magenta2", 238, 0, 238, 1, X11Compliance },
+    { "magenta3", 205, 0, 205, 1, X11Compliance },
+    { "magenta4", 139, 0, 139, 1, X11Compliance },
+    { "maroon", 128, 0, 0, 1, SVGCompliance },
+    { "maroon", 176, 48, 96, 1, X11Compliance | XPMCompliance },
+    { "maroon1", 255, 52, 179, 1, X11Compliance },
+    { "maroon2", 238, 48, 167, 1, X11Compliance },
+    { "maroon3", 205, 41, 144, 1, X11Compliance },
+    { "maroon4", 139, 28, 98, 1, X11Compliance },
+    { "MediumAquamarine", 102, 205, 170, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumBlue", 0, 0, 205, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumForestGreen", 50, 129, 75, 1, X11Compliance | XPMCompliance },
+    { "MediumGoldenRod", 209, 193, 102, 1, X11Compliance | XPMCompliance },
+    { "MediumOrchid", 186, 85, 211, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumOrchid1", 224, 102, 255, 1, X11Compliance },
+    { "MediumOrchid2", 209, 95, 238, 1, X11Compliance },
+    { "MediumOrchid3", 180, 82, 205, 1, X11Compliance },
+    { "MediumOrchid4", 122, 55, 139, 1, X11Compliance },
+    { "MediumPurple", 147, 112, 219, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumPurple1", 171, 130, 255, 1, X11Compliance },
+    { "MediumPurple2", 159, 121, 238, 1, X11Compliance },
+    { "MediumPurple3", 137, 104, 205, 1, X11Compliance },
+    { "MediumPurple4", 93, 71, 139, 1, X11Compliance },
+    { "MediumSeaGreen", 60, 179, 113, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumSlateBlue", 123, 104, 238, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumSpringGreen", 0, 250, 154, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumTurquoise", 72, 209, 204, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MediumVioletRed", 199, 21, 133, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MidnightBlue", 25, 25, 112, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MintCream", 245, 255, 250, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MistyRose", 255, 228, 225, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "MistyRose1", 255, 228, 225, 1, X11Compliance },
+    { "MistyRose2", 238, 213, 210, 1, X11Compliance },
+    { "MistyRose3", 205, 183, 181, 1, X11Compliance },
+    { "MistyRose4", 139, 125, 123, 1, X11Compliance },
+    { "moccasin", 255, 228, 181, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "NavajoWhite", 255, 222, 173, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "NavajoWhite1", 255, 222, 173, 1, X11Compliance },
+    { "NavajoWhite2", 238, 207, 161, 1, X11Compliance },
+    { "NavajoWhite3", 205, 179, 139, 1, X11Compliance },
+    { "NavajoWhite4", 139, 121, 94, 1, X11Compliance },
+    { "navy", 0, 0, 128, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "NavyBlue", 0, 0, 128, 1, X11Compliance | XPMCompliance },
+    { "matte", 0, 0, 0, 0, SVGCompliance },
+    { "OldLace", 253, 245, 230, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "olive", 128, 128, 0, 1, SVGCompliance },
+    { "OliveDrab", 107, 142, 35, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "OliveDrab1", 192, 255, 62, 1, X11Compliance },
+    { "OliveDrab2", 179, 238, 58, 1, X11Compliance },
+    { "OliveDrab3", 154, 205, 50, 1, X11Compliance },
+    { "OliveDrab4", 105, 139, 34, 1, X11Compliance },
+    { "opaque", 0, 0, 0, 1, SVGCompliance },
+    { "orange", 255, 165, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "orange1", 255, 165, 0, 1, X11Compliance },
+    { "orange2", 238, 154, 0, 1, X11Compliance },
+    { "orange3", 205, 133, 0, 1, X11Compliance },
+    { "orange4", 139, 90, 0, 1, X11Compliance },
+    { "OrangeRed", 255, 69, 0, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "OrangeRed1", 255, 69, 0, 1, X11Compliance },
+    { "OrangeRed2", 238, 64, 0, 1, X11Compliance },
+    { "OrangeRed3", 205, 55, 0, 1, X11Compliance },
+    { "OrangeRed4", 139, 37, 0, 1, X11Compliance },
+    { "orchid", 218, 112, 214, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "orchid1", 255, 131, 250, 1, X11Compliance },
+    { "orchid2", 238, 122, 233, 1, X11Compliance },
+    { "orchid3", 205, 105, 201, 1, X11Compliance },
+    { "orchid4", 139, 71, 137, 1, X11Compliance },
+    { "PaleGoldenrod", 238, 232, 170, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "PaleGreen", 152, 251, 152, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "PaleGreen1", 154, 255, 154, 1, X11Compliance },
+    { "PaleGreen2", 144, 238, 144, 1, X11Compliance },
+    { "PaleGreen3", 124, 205, 124, 1, X11Compliance },
+    { "PaleGreen4", 84, 139, 84, 1, X11Compliance },
+    { "PaleTurquoise", 175, 238, 238, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "PaleTurquoise1", 187, 255, 255, 1, X11Compliance },
+    { "PaleTurquoise2", 174, 238, 238, 1, X11Compliance },
+    { "PaleTurquoise3", 150, 205, 205, 1, X11Compliance },
+    { "PaleTurquoise4", 102, 139, 139, 1, X11Compliance },
+    { "PaleVioletRed", 219, 112, 147, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "PaleVioletRed1", 255, 130, 171, 1, X11Compliance },
+    { "PaleVioletRed2", 238, 121, 159, 1, X11Compliance },
+    { "PaleVioletRed3", 205, 104, 137, 1, X11Compliance },
+    { "PaleVioletRed4", 139, 71, 93, 1, X11Compliance },
+    { "PapayaWhip", 255, 239, 213, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "PeachPuff", 255, 218, 185, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "PeachPuff1", 255, 218, 185, 1, X11Compliance },
+    { "PeachPuff2", 238, 203, 173, 1, X11Compliance },
+    { "PeachPuff3", 205, 175, 149, 1, X11Compliance },
+    { "PeachPuff4", 139, 119, 101, 1, X11Compliance },
+    { "peru", 205, 133, 63, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "pink", 255, 192, 203, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "pink1", 255, 181, 197, 1, X11Compliance },
+    { "pink2", 238, 169, 184, 1, X11Compliance },
+    { "pink3", 205, 145, 158, 1, X11Compliance },
+    { "pink4", 139, 99, 108, 1, X11Compliance },
+    { "plum", 221, 160, 221, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "plum1", 255, 187, 255, 1, X11Compliance },
+    { "plum2", 238, 174, 238, 1, X11Compliance },
+    { "plum3", 205, 150, 205, 1, X11Compliance },
+    { "plum4", 139, 102, 139, 1, X11Compliance },
+    { "PowderBlue", 176, 224, 230, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "purple", 128, 0, 128, 1, SVGCompliance },
+    { "purple", 160, 32, 240, 1, X11Compliance | XPMCompliance },
+    { "purple1", 155, 48, 255, 1, X11Compliance },
+    { "purple2", 145, 44, 238, 1, X11Compliance },
+    { "purple3", 125, 38, 205, 1, X11Compliance },
+    { "purple4", 85, 26, 139, 1, X11Compliance },
+    { "red1", 255, 0, 0, 1, X11Compliance },
+    { "red2", 238, 0, 0, 1, X11Compliance },
+    { "red3", 205, 0, 0, 1, X11Compliance },
+    { "red4", 139, 0, 0, 1, X11Compliance },
+    { "RosyBrown", 188, 143, 143, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "RosyBrown1", 255, 193, 193, 1, X11Compliance },
+    { "RosyBrown2", 238, 180, 180, 1, X11Compliance },
+    { "RosyBrown3", 205, 155, 155, 1, X11Compliance },
+    { "RosyBrown4", 139, 105, 105, 1, X11Compliance },
+    { "RoyalBlue", 65, 105, 225, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "RoyalBlue1", 72, 118, 255, 1, X11Compliance },
+    { "RoyalBlue2", 67, 110, 238, 1, X11Compliance },
+    { "RoyalBlue3", 58, 95, 205, 1, X11Compliance },
+    { "RoyalBlue4", 39, 64, 139, 1, X11Compliance },
+    { "SaddleBrown", 139, 69, 19, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "salmon", 250, 128, 114, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "salmon1", 255, 140, 105, 1, X11Compliance },
+    { "salmon2", 238, 130, 98, 1, X11Compliance },
+    { "salmon3", 205, 112, 84, 1, X11Compliance },
+    { "salmon4", 139, 76, 57, 1, X11Compliance },
+    { "SandyBrown", 244, 164, 96, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SeaGreen", 46, 139, 87, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SeaGreen1", 84, 255, 159, 1, X11Compliance },
+    { "SeaGreen2", 78, 238, 148, 1, X11Compliance },
+    { "SeaGreen3", 67, 205, 128, 1, X11Compliance },
+    { "SeaGreen4", 46, 139, 87, 1, X11Compliance },
+    { "seashell", 255, 245, 238, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "seashell1", 255, 245, 238, 1, X11Compliance },
+    { "seashell2", 238, 229, 222, 1, X11Compliance },
+    { "seashell3", 205, 197, 191, 1, X11Compliance },
+    { "seashell4", 139, 134, 130, 1, X11Compliance },
+    { "sienna", 160, 82, 45, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "sienna1", 255, 130, 71, 1, X11Compliance },
+    { "sienna2", 238, 121, 66, 1, X11Compliance },
+    { "sienna3", 205, 104, 57, 1, X11Compliance },
+    { "sienna4", 139, 71, 38, 1, X11Compliance },
+    { "silver", 192, 192, 192, 1, SVGCompliance },
+    { "SkyBlue", 135, 206, 235, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SkyBlue1", 135, 206, 255, 1, X11Compliance },
+    { "SkyBlue2", 126, 192, 238, 1, X11Compliance },
+    { "SkyBlue3", 108, 166, 205, 1, X11Compliance },
+    { "SkyBlue4", 74, 112, 139, 1, X11Compliance },
+    { "SlateBlue", 106, 90, 205, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SlateBlue1", 131, 111, 255, 1, X11Compliance },
+    { "SlateBlue2", 122, 103, 238, 1, X11Compliance },
+    { "SlateBlue3", 105, 89, 205, 1, X11Compliance },
+    { "SlateBlue4", 71, 60, 139, 1, X11Compliance },
+    { "SlateGray", 112, 128, 144, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SlateGray1", 198, 226, 255, 1, X11Compliance },
+    { "SlateGray2", 185, 211, 238, 1, X11Compliance },
+    { "SlateGray3", 159, 182, 205, 1, X11Compliance },
+    { "SlateGray4", 108, 123, 139, 1, X11Compliance },
+    { "SlateGrey", 112, 128, 144, 1, SVGCompliance | X11Compliance },
+    { "snow", 255, 250, 250, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "snow1", 255, 250, 250, 1, X11Compliance },
+    { "snow2", 238, 233, 233, 1, X11Compliance },
+    { "snow3", 205, 201, 201, 1, X11Compliance },
+    { "snow4", 139, 137, 137, 1, X11Compliance },
+    { "SpringGreen", 0, 255, 127, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SpringGreen1", 0, 255, 127, 1, X11Compliance },
+    { "SpringGreen2", 0, 238, 118, 1, X11Compliance },
+    { "SpringGreen3", 0, 205, 102, 1, X11Compliance },
+    { "SpringGreen4", 0, 139, 69, 1, X11Compliance },
+    { "SteelBlue", 70, 130, 180, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "SteelBlue1", 99, 184, 255, 1, X11Compliance },
+    { "SteelBlue2", 92, 172, 238, 1, X11Compliance },
+    { "SteelBlue3", 79, 148, 205, 1, X11Compliance },
+    { "SteelBlue4", 54, 100, 139, 1, X11Compliance },
+    { "tan", 210, 180, 140, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "tan1", 255, 165, 79, 1, X11Compliance },
+    { "tan2", 238, 154, 73, 1, X11Compliance },
+    { "tan3", 205, 133, 63, 1, X11Compliance },
+    { "tan4", 139, 90, 43, 1, X11Compliance },
+    { "teal", 0, 128, 128, 1, SVGCompliance },
+    { "thistle", 216, 191, 216, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "thistle1", 255, 225, 255, 1, X11Compliance },
+    { "thistle2", 238, 210, 238, 1, X11Compliance },
+    { "thistle3", 205, 181, 205, 1, X11Compliance },
+    { "thistle4", 139, 123, 139, 1, X11Compliance },
+    { "tomato", 255, 99, 71, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "tomato1", 255, 99, 71, 1, X11Compliance },
+    { "tomato2", 238, 92, 66, 1, X11Compliance },
+    { "tomato3", 205, 79, 57, 1, X11Compliance },
+    { "tomato4", 139, 54, 38, 1, X11Compliance },
+    { "transparent", 0, 0, 0, 0, SVGCompliance },
+    { "turquoise", 64, 224, 208, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "turquoise1", 0, 245, 255, 1, X11Compliance },
+    { "turquoise2", 0, 229, 238, 1, X11Compliance },
+    { "turquoise3", 0, 197, 205, 1, X11Compliance },
+    { "turquoise4", 0, 134, 139, 1, X11Compliance },
+    { "violet", 238, 130, 238, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "VioletRed", 208, 32, 144, 1, X11Compliance | XPMCompliance },
+    { "VioletRed1", 255, 62, 150, 1, X11Compliance },
+    { "VioletRed2", 238, 58, 140, 1, X11Compliance },
+    { "VioletRed3", 205, 50, 120, 1, X11Compliance },
+    { "VioletRed4", 139, 34, 82, 1, X11Compliance },
+    { "wheat", 245, 222, 179, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "wheat1", 255, 231, 186, 1, X11Compliance },
+    { "wheat2", 238, 216, 174, 1, X11Compliance },
+    { "wheat3", 205, 186, 150, 1, X11Compliance },
+    { "wheat4", 139, 126, 102, 1, X11Compliance },
+    { "WhiteSmoke", 245, 245, 245, 1, SVGCompliance | X11Compliance | XPMCompliance },
+    { "yellow1", 255, 255, 0, 1, X11Compliance },
+    { "yellow2", 238, 238, 0, 1, X11Compliance },
+    { "yellow3", 205, 205, 0, 1, X11Compliance },
+    { "yellow4", 139, 139, 0, 1, X11Compliance },
+    { "YellowGreen", 154, 205, 50, 1, SVGCompliance | X11Compliance | XPMCompliance }
+  };
+
+/*
+  Static declarations.
+*/
+static LinkedListInfo
+  *color_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *color_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_color = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeColorList(ExceptionInfo *),
+  LoadColorLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o l o r C o m p o n e n t G e n e s i s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ColorComponentGenesis() instantiates the color component.
+%
+%  The format of the ColorComponentGenesis method is:
+%
+%      MagickBooleanType ColorComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType ColorComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&color_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o l o r C o m p o n e n t T e r m i n u s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ColorComponentTerminus() destroys the color component.
+%
+%  The format of the ColorComponentTerminus method is:
+%
+%      ColorComponentTerminus(void)
+%
+*/
+
+static void *DestroyColorElement(void *color_info)
+{
+  register ColorInfo
+    *p;
+
+  p=(ColorInfo *) color_info;
+  if (p->exempt  == MagickFalse)
+    {
+      if (p->path != (char *) NULL)
+        p->path=DestroyString(p->path);
+      if (p->name != (char *) NULL)
+        p->name=DestroyString(p->name);
+    }
+  p=(ColorInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void ColorComponentTerminus(void)
+{
+  if (color_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&color_semaphore);
+  LockSemaphoreInfo(color_semaphore);
+  if (color_list != (LinkedListInfo *) NULL)
+    color_list=DestroyLinkedList(color_list,DestroyColorElement);
+  instantiate_color=MagickFalse;
+  UnlockSemaphoreInfo(color_semaphore);
+  DestroySemaphoreInfo(&color_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C o l o r C o m p l i a n c e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetColorInfo() searches the color list for the specified name and standards
+%  compliance and if found returns attributes for that color.
+%
+%  The format of the GetColorInfo method is:
+%
+%      const PixelPacket *GetColorInfo(const char *name,
+%        const ComplianceType compliance,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the color name.
+%
+%    o compliance: Adhere to this color standard: SVG, X11, or XPM.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const ColorInfo *GetColorCompliance(const char *name,
+  const ComplianceType compliance,ExceptionInfo *exception)
+{
+  char
+    colorname[MaxTextExtent];
+
+  register const ColorInfo
+    *p;
+
+  register char
+    *q;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((color_list == (LinkedListInfo *) NULL) ||
+      (instantiate_color == MagickFalse))
+    if (InitializeColorList(exception) == MagickFalse)
+      return((const ColorInfo *) NULL);
+  if ((color_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(color_list) != MagickFalse))
+    return((const ColorInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    return((const ColorInfo *) GetValueFromLinkedList(color_list,0));
+  /*
+    Strip names of whitespace.
+  */
+  (void) CopyMagickString(colorname,name,MaxTextExtent);
+  for (q=colorname; *q != '\0'; q++)
+  {
+    if (isspace((int) ((unsigned char) *q)) == 0)
+      continue;
+    (void) CopyMagickString(q,q+1,MaxTextExtent);
+    q--;
+  }
+  /*
+    Search for color tag.
+  */
+  LockSemaphoreInfo(color_semaphore);
+  ResetLinkedListIterator(color_list);
+  p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  while (p != (const ColorInfo *) NULL)
+  {
+    if (((p->compliance & compliance) != 0) &&
+        (LocaleCompare(colorname,p->name) == 0))
+      break;
+    p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  }
+  if (p == (ColorInfo *) NULL)
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+      "UnrecognizedColor","`%s'",name);
+  else
+    (void) InsertValueInLinkedList(color_list,0,
+      RemoveElementByValueFromLinkedList(color_list,p));
+  UnlockSemaphoreInfo(color_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C o l o r I n f o                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetColorInfo() searches the color list for the specified name and if found
+%  returns attributes for that color.
+%
+%  The format of the GetColorInfo method is:
+%
+%      const PixelPacket *GetColorInfo(const char *name,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o color_info: search the color list for the specified name and if found
+%      return attributes for that color.
+%
+%    o name: the color name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const ColorInfo *GetColorInfo(const char *name,
+  ExceptionInfo *exception)
+{
+  return(GetColorCompliance(name,AllCompliance,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n c a t e n a t e C o l o r C o m p o n e n t                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConcatenateColorComponent() returns the pixel as a canonical string.
+%
+%  The format of the ConcatenateColorComponent() method is:
+%
+%      void ConcatenateColorComponent(const PixelInfo *pixel,
+%        const ChannelType channel,const ComplianceType compliance,char *tuple)
+%
+%  A description of each parameter follows.
+%
+%    o pixel:  The pixel.
+%
+%    channel:  The channel.
+%
+%    o compliance: Adhere to this color standard: SVG, X11, or XPM.
+%
+%    tuple:  The color tuple.
+%
+*/
+MagickExport void ConcatenateColorComponent(const PixelInfo *pixel,
+  const ChannelType channel,const ComplianceType compliance,char *tuple)
+{
+  char
+    component[MaxTextExtent];
+
+  MagickRealType
+    color;
+
+  color=0.0;
+  switch (channel)
+  {
+    case RedChannel:
+    {
+      color=pixel->red;
+      break;
+    }
+    case GreenChannel:
+    {
+      color=pixel->green;
+      break;
+    }
+    case BlueChannel:
+    {
+      color=pixel->blue;
+      break;
+    }
+    case AlphaChannel:
+    {
+      color=pixel->alpha;
+      break;
+    }
+    case BlackChannel:
+    {
+      color=pixel->black;
+      break;
+    }
+    default:
+      break;
+  }
+  if (compliance != SVGCompliance)
+    {
+      if (pixel->depth > 16)
+        {
+          (void) FormatLocaleString(component,MaxTextExtent,"%10lu",
+            (unsigned long) ScaleQuantumToLong(ClampToQuantum(color)));
+          (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+          return;
+        }
+      if (pixel->depth > 8)
+        {
+          (void) FormatLocaleString(component,MaxTextExtent,"%5d",
+            ScaleQuantumToShort(ClampToQuantum(color)));
+          (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+          return;
+        }
+      (void) FormatLocaleString(component,MaxTextExtent,"%3d",
+        ScaleQuantumToChar(ClampToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (channel == AlphaChannel)
+    {
+      (void) FormatLocaleString(component,MaxTextExtent,"%g",
+        (double) (QuantumScale*color));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if ((pixel->colorspace == HSLColorspace) ||
+      (pixel->colorspace == HSBColorspace))
+    {
+      (void) FormatLocaleString(component,MaxTextExtent,"%g%%",
+        (double) (100.0*QuantumScale*color));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (pixel->depth > 8)
+    {
+      (void) FormatLocaleString(component,MaxTextExtent,"%g%%",
+        (double) (100.0*QuantumScale*color));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  (void) FormatLocaleString(component,MaxTextExtent,"%d",
+    ScaleQuantumToChar(ClampToQuantum(color)));
+  (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o l o r I n f o L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetColorInfoList() returns any colors that match the specified pattern.
+%
+%  The format of the GetColorInfoList function is:
+%
+%      const ColorInfo **GetColorInfoList(const char *pattern,
+%        size_t *number_colors,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_colors:  This integer returns the number of colors in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int ColorInfoCompare(const void *x,const void *y)
+{
+  const ColorInfo
+    **p,
+    **q;
+
+  p=(const ColorInfo **) x,
+  q=(const ColorInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->name,(*q)->name));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const ColorInfo **GetColorInfoList(const char *pattern,
+  size_t *number_colors,ExceptionInfo *exception)
+{
+  const ColorInfo
+    **colors;
+
+  register const ColorInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate color list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_colors != (size_t *) NULL);
+  *number_colors=0;
+  p=GetColorInfo("*",exception);
+  if (p == (const ColorInfo *) NULL)
+    return((const ColorInfo **) NULL);
+  colors=(const ColorInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
+  if (colors == (const ColorInfo **) NULL)
+    return((const ColorInfo **) NULL);
+  /*
+    Generate color list.
+  */
+  LockSemaphoreInfo(color_semaphore);
+  ResetLinkedListIterator(color_list);
+  p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  for (i=0; p != (const ColorInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      colors[i++]=p;
+    p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  }
+  UnlockSemaphoreInfo(color_semaphore);
+  qsort((void *) colors,(size_t) i,sizeof(*colors),ColorInfoCompare);
+  colors[i]=(ColorInfo *) NULL;
+  *number_colors=(size_t) i;
+  return(colors);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o l o r L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetColorList() returns any colors that match the specified pattern.
+%
+%  The format of the GetColorList function is:
+%
+%      char **GetColorList(const char *pattern,size_t *number_colors,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_colors:  This integer returns the number of colors in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int ColorCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetColorList(const char *pattern,
+  size_t *number_colors,ExceptionInfo *exception)
+{
+  char
+    **colors;
+
+  register const ColorInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate color list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_colors != (size_t *) NULL);
+  *number_colors=0;
+  p=GetColorInfo("*",exception);
+  if (p == (const ColorInfo *) NULL)
+    return((char **) NULL);
+  colors=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(color_list)+1UL,sizeof(*colors));
+  if (colors == (char **) NULL)
+    return((char **) NULL);
+  /*
+    Generate color list.
+  */
+  LockSemaphoreInfo(color_semaphore);
+  ResetLinkedListIterator(color_list);
+  p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  for (i=0; p != (const ColorInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      colors[i++]=ConstantString(p->name);
+    p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  }
+  UnlockSemaphoreInfo(color_semaphore);
+  qsort((void *) colors,(size_t) i,sizeof(*colors),ColorCompare);
+  colors[i]=(char *) NULL;
+  *number_colors=(size_t) i;
+  return(colors);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C o l o r T u p l e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetColorTuple() returns a color as a color tuple string (e.g. rgba(255,0,0))
+%  or hex string (e.g. #FF0000).
+%
+%  The format of the GetColorTuple method is:
+%
+%      GetColorTuple(const PixelInfo *pixel,const MagickBooleanType hex,
+%        char *tuple)
+%
+%  A description of each parameter follows.
+%
+%    o pixel: the pixel.
+%
+%    o hex: A value other than zero returns the tuple in a hexidecimal format.
+%
+%    o tuple: Return the color tuple as this string.
+%
+*/
+
+static void ConcatentateHexColorComponent(const PixelInfo *pixel,
+  const ChannelType channel,char *tuple)
+{
+  char
+    component[MaxTextExtent];
+
+  MagickRealType
+    color;
+
+  color=0.0;
+  switch (channel)
+  {
+    case RedChannel:
+    {
+      color=pixel->red;
+      break;
+    }
+    case GreenChannel:
+    {
+      color=pixel->green;
+      break;
+    }
+    case BlueChannel:
+    {
+      color=pixel->blue;
+      break;
+    }
+    case AlphaChannel:
+    {
+      color=pixel->alpha;
+      break;
+    }
+    case BlackChannel:
+    {
+      color=pixel->black;
+      break;
+    }
+    default:
+      break;
+  }
+  if (pixel->depth > 32)
+    {
+      (void) FormatLocaleString(component,MaxTextExtent,"%08lX%08lX",
+        (unsigned long) ScaleQuantumToLong(ClampToQuantum(color)),
+        (unsigned long) ScaleQuantumToLong(ClampToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (pixel->depth > 16)
+    {
+      (void) FormatLocaleString(component,MaxTextExtent,"%08X",
+        (unsigned int) ScaleQuantumToLong(ClampToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  if (pixel->depth > 8)
+    {
+      (void) FormatLocaleString(component,MaxTextExtent,"%04X",
+        ScaleQuantumToShort(ClampToQuantum(color)));
+      (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+      return;
+    }
+  (void) FormatLocaleString(component,MaxTextExtent,"%02X",
+    ScaleQuantumToChar(ClampToQuantum(color)));
+  (void) ConcatenateMagickString(tuple,component,MaxTextExtent);
+  return;
+}
+
+MagickExport void GetColorTuple(const PixelInfo *pixel,
+  const MagickBooleanType hex,char *tuple)
+{
+  PixelInfo
+    color;
+
+  assert(pixel != (const PixelInfo *) NULL);
+  assert(tuple != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tuple);
+  *tuple='\0';
+  if (hex != MagickFalse)
+    {
+      /*
+        Convert pixel to hex color.
+      */
+      (void) ConcatenateMagickString(tuple,"#",MaxTextExtent);
+      ConcatentateHexColorComponent(pixel,RedChannel,tuple);
+      ConcatentateHexColorComponent(pixel,GreenChannel,tuple);
+      ConcatentateHexColorComponent(pixel,BlueChannel,tuple);
+      if (pixel->colorspace == CMYKColorspace)
+        ConcatentateHexColorComponent(pixel,BlackChannel,tuple);
+      if ((pixel->matte != MagickFalse) && (pixel->alpha != OpaqueAlpha))
+        ConcatentateHexColorComponent(pixel,AlphaChannel,tuple);
+      return;
+    }
+  /*
+    Convert pixel to rgb() or cmyk() color.
+  */
+  color=(*pixel);
+  if (color.depth > 8)
+    {
+#define SVGCompliant(component) ((MagickRealType) \
+   ScaleCharToQuantum(ScaleQuantumToChar(ClampToQuantum(component))));
+
+      MagickStatusType
+        status;
+
+      /*
+        SVG requires color depths > 8 expressed as percentages.
+      */
+      status=color.red == SVGCompliant(color.red);
+      status&=color.green == SVGCompliant(color.green);
+      status&=color.blue == SVGCompliant(color.blue);
+      if (color.colorspace == CMYKColorspace)
+        status&=color.black == SVGCompliant(color.black);
+      if (color.matte != MagickFalse)
+        status&=color.alpha == SVGCompliant(color.alpha);
+      if (status != MagickFalse)
+        color.depth=8;
+    }
+  (void) ConcatenateMagickString(tuple,CommandOptionToMnemonic(
+    MagickColorspaceOptions,(ssize_t) color.colorspace),MaxTextExtent);
+  if (color.matte != MagickFalse)
+    (void) ConcatenateMagickString(tuple,"a",MaxTextExtent);
+  (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
+  ConcatenateColorComponent(&color,RedChannel,SVGCompliance,tuple);
+  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+  ConcatenateColorComponent(&color,GreenChannel,SVGCompliance,tuple);
+  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+  ConcatenateColorComponent(&color,BlueChannel,SVGCompliance,tuple);
+  if (color.colorspace == CMYKColorspace)
+    {
+      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+      ConcatenateColorComponent(&color,BlackChannel,SVGCompliance,tuple);
+    }
+  if (color.matte != MagickFalse)
+    {
+      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+      ConcatenateColorComponent(&color,AlphaChannel,SVGCompliance,tuple);
+    }
+  (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
+  LocaleLower(tuple);
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e C o l o r L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeColorList() initializes the color list.
+%
+%  The format of the InitializeColorList method is:
+%
+%      MagickBooleanType InitializeColorList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeColorList(ExceptionInfo *exception)
+{
+  if ((color_list == (LinkedListInfo *) NULL) &&
+      (instantiate_color == MagickFalse))
+    {
+      if (color_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&color_semaphore);
+      LockSemaphoreInfo(color_semaphore);
+      if ((color_list == (LinkedListInfo *) NULL) &&
+          (instantiate_color == MagickFalse))
+        {
+          (void) LoadColorLists(ColorFilename,exception);
+          instantiate_color=MagickTrue;
+        }
+      UnlockSemaphoreInfo(color_semaphore);
+    }
+  return(color_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s A l p h a S i m i l a r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsEquivalentAlpha() returns true if the distance between two alpha values is
+%  less than the specified distance in a linear color space.  This method is
+%  used by MatteFloodFill() and other algorithms which compare two alpha values.
+%
+%  The format of the IsEquivalentAlpha method is:
+%
+%      void IsEquivalentAlpha(const Image *image,const PixelPacket *p,
+%        const PixelPacket *q)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o p: Pixel p.
+%
+%    o q: Pixel q.
+%
+*/
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType IsEquivalentAlpha(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    distance;
+
+  if (image->matte == MagickFalse)
+    return(MagickTrue);
+  if (p->alpha == q->alpha)
+    return(MagickTrue);
+  fuzz=MagickMax(image->fuzz,MagickSQ1_2)*MagickMax(image->fuzz,MagickSQ1_2);
+  pixel=(MagickRealType) p->alpha-(MagickRealType) q->alpha;
+  distance=pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s I m a g e S i m i l a r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsEquivalentImage() returns true if the target is similar to a region of the
+%  image.
+%
+%  The format of the IsEquivalentImage method is:
+%
+%      MagickBooleanType IsEquivalentImage(const Image *image,
+%        const Image *target_image,ssize_t *x_offset,ssize_t *y_offset,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o target_image: the target image.
+%
+%    o x_offset: On input the starting x position to search for a match;
+%      on output the x position of the first match found.
+%
+%    o y_offset: On input the starting y position to search for a match;
+%      on output the y position of the first match found.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsEquivalentImage(const Image *image,
+  const Image *target_image,ssize_t *x_offset,ssize_t *y_offset,
+  ExceptionInfo *exception)
+{
+#define SearchImageText  "  Searching image...  "
+
+  CacheView
+    *image_view,
+    *target_view;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    target,
+    pixel;
+
+  register const Quantum
+    *p,
+    *q;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    j,
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(target_image != (Image *) NULL);
+  assert(target_image->signature == MagickSignature);
+  assert(x_offset != (ssize_t *) NULL);
+  assert(y_offset != (ssize_t *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  x=0;
+  status=MagickTrue;
+  GetPixelInfo(image,&pixel);
+  GetPixelInfo(image,&target);
+  image_view=AcquireCacheView(image);
+  target_view=AcquireCacheView(target_image);
+  for (y=(*y_offset); y < (ssize_t) image->rows; y++)
+  {
+    for (x=y == 0 ? *x_offset : 0; x < (ssize_t) image->columns; x++)
+    {
+      for (j=0; j < (ssize_t) target_image->rows; j++)
+      {
+        for (i=0; i < (ssize_t) target_image->columns; i++)
+        {
+          p=GetCacheViewVirtualPixels(image_view,x+i,y+j,1,1,exception);
+          SetPixelInfo(image,p,&pixel);
+          q=GetCacheViewVirtualPixels(target_view,i,j,1,1,exception);
+          SetPixelInfo(image,q,&target);
+          if (IsFuzzyEquivalencePixelInfo(&pixel,&target) == MagickFalse)
+            break;
+        }
+        if (i < (ssize_t) target_image->columns)
+          break;
+      }
+      if (j == (ssize_t) target_image->rows)
+        break;
+    }
+    if (x < (ssize_t) image->columns)
+      break;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,SearchImageText,(MagickOffsetType) y,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  target_view=DestroyCacheView(target_view);
+  image_view=DestroyCacheView(image_view);
+  *x_offset=x;
+  *y_offset=y;
+  if (status == MagickFalse)
+    return(status);
+  return(y < (ssize_t) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t C o l o r I n f o                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListColorInfo() lists color names to the specified file.  Color names
+%  are a convenience.  Rather than defining a color by its red, green, and
+%  blue intensities just use a color name such as white, blue, or yellow.
+%
+%  The format of the ListColorInfo method is:
+%
+%      MagickBooleanType ListColorInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  List color names to this file handle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListColorInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  char
+    tuple[MaxTextExtent];
+
+  const char
+    *path;
+
+  const ColorInfo
+    **color_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_colors;
+
+  /*
+    List name and attributes of each color in the list.
+  */
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  color_info=GetColorInfoList("*",&number_colors,exception);
+  if (color_info == (const ColorInfo **) NULL)
+    return(MagickFalse);
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_colors; i++)
+  {
+    if (color_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,color_info[i]->path) != 0))
+      {
+        if (color_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",color_info[i]->path);
+        (void) FormatLocaleFile(file,
+          "Name                  Color                  "
+          "                       Compliance\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=color_info[i]->path;
+    (void) FormatLocaleFile(file,"%-21.21s ",color_info[i]->name);
+    GetColorTuple(&color_info[i]->color,MagickFalse,tuple);
+    (void) FormatLocaleFile(file,"%-45.45s ",tuple);
+    if ((color_info[i]->compliance & SVGCompliance) != 0)
+      (void) FormatLocaleFile(file,"SVG ");
+    if ((color_info[i]->compliance & X11Compliance) != 0)
+      (void) FormatLocaleFile(file,"X11 ");
+    if ((color_info[i]->compliance & XPMCompliance) != 0)
+      (void) FormatLocaleFile(file,"XPM ");
+    (void) FormatLocaleFile(file,"\n");
+  }
+  color_info=(const ColorInfo **) RelinquishMagickMemory((void *) color_info);
+  (void) fflush(file);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d C o l o r L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadColorList() loads the color configuration file which provides a mapping
+%  between color attributes and a color name.
+%
+%  The format of the LoadColorList method is:
+%
+%      MagickBooleanType LoadColorList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The color list in XML format.
+%
+%    o filename:  The color list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadColorList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  ColorInfo
+    *color_info;
+
+  const char
+    *q;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Load the color map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading color file \"%s\" ...",filename);
+  if (xml == (char *) NULL)
+    return(MagickFalse);
+  if (color_list == (LinkedListInfo *) NULL)
+    {
+      color_list=NewLinkedList(0);
+      if (color_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  color_info=(ColorInfo *) NULL;
+  token=AcquireString(xml);
+  for (q=(char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadColorList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<color") == 0)
+      {
+        /*
+          Color element.
+        */
+        color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
+        if (color_info == (ColorInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
+        color_info->path=ConstantString(filename);
+        color_info->exempt=MagickFalse;
+        color_info->signature=MagickSignature;
+        continue;
+      }
+    if (color_info == (ColorInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AppendValueToLinkedList(color_list,color_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            color_info->name);
+        color_info=(ColorInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'C':
+      case 'c':
+      {
+        if (LocaleCompare((char *) keyword,"color") == 0)
+          {
+            (void) QueryMagickColor(token,&color_info->color,exception);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"compliance") == 0)
+          {
+            ssize_t
+              compliance;
+
+            compliance=color_info->compliance;
+            if (GlobExpression(token,"*SVG*",MagickTrue) != MagickFalse)
+              compliance|=SVGCompliance;
+            if (GlobExpression(token,"*X11*",MagickTrue) != MagickFalse)
+              compliance|=X11Compliance;
+            if (GlobExpression(token,"*XPM*",MagickTrue) != MagickFalse)
+              compliance|=XPMCompliance;
+            color_info->compliance=(ComplianceType) compliance;
+            break;
+          }
+        break;
+      }
+      case 'N':
+      case 'n':
+      {
+        if (LocaleCompare((char *) keyword,"name") == 0)
+          {
+            color_info->name=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            color_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d C o l o r L i s t s                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadColorList() loads one or more color configuration file which provides a
+%  mapping between color attributes and a color name.
+%
+%  The format of the LoadColorLists method is:
+%
+%      MagickBooleanType LoadColorLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadColorLists(const char *filename,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Load built-in color map.
+  */
+  status=MagickFalse;
+  if (color_list == (LinkedListInfo *) NULL)
+    {
+      color_list=NewLinkedList(0);
+      if (color_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  for (i=0; i < (ssize_t) (sizeof(ColorMap)/sizeof(*ColorMap)); i++)
+  {
+    ColorInfo
+      *color_info;
+
+    register const ColorMapInfo
+      *p;
+
+    p=ColorMap+i;
+    color_info=(ColorInfo *) AcquireMagickMemory(sizeof(*color_info));
+    if (color_info == (ColorInfo *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",color_info->name);
+        continue;
+      }
+    (void) ResetMagickMemory(color_info,0,sizeof(*color_info));
+    color_info->path=(char *) "[built-in]";
+    color_info->name=(char *) p->name;
+    GetPixelInfo((Image *) NULL,&color_info->color);
+    color_info->color.red=(MagickRealType) ScaleCharToQuantum(p->red);
+    color_info->color.green=(MagickRealType) ScaleCharToQuantum(p->green);
+    color_info->color.blue=(MagickRealType) ScaleCharToQuantum(p->blue);
+    color_info->color.alpha=(MagickRealType) (QuantumRange*p->alpha);
+    color_info->compliance=(ComplianceType) p->compliance;
+    color_info->exempt=MagickTrue;
+    color_info->signature=MagickSignature;
+    status=AppendValueToLinkedList(color_list,color_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",color_info->name);
+  }
+  /*
+    Load external color map.
+  */
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadColorList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u e r y C o l o r D a t a b a s e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueryColorDatabase() returns the red, green, blue, and opacity intensities
+%  for a given color name.
+%
+%  The format of the QueryColorDatabase method is:
+%
+%      MagickBooleanType QueryColorDatabase(const char *name,
+%        const ComplianceType compliance,PixelPacket *color,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the color name (e.g. white, blue, yellow).
+%
+%    o compliance: Adhere to this color standard: SVG, X11, or XPM.
+%
+%    o color: the red, green, blue, and opacity intensities values of the
+%      named color in this structure.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType QueryColorCompliance(const char *name,
+  const ComplianceType compliance,PixelPacket *color,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    pixel;
+
+  status=QueryMagickColorCompliance(name,compliance,&pixel,exception);
+  color->alpha=ClampToQuantum(pixel.alpha);
+  if (pixel.colorspace == CMYKColorspace)
+    {
+      color->red=ClampToQuantum((MagickRealType)
+        (QuantumRange-MagickMin(QuantumRange,(MagickRealType) (QuantumScale*
+        pixel.red*(QuantumRange-pixel.black)+pixel.black))));
+      color->green=ClampToQuantum((MagickRealType)
+        (QuantumRange-MagickMin(QuantumRange,(MagickRealType) (QuantumScale*
+        pixel.green*(QuantumRange-pixel.black)+pixel.black))));
+      color->blue=ClampToQuantum((MagickRealType)
+        (QuantumRange-MagickMin(QuantumRange,(MagickRealType) (QuantumScale*
+        pixel.blue*(QuantumRange-pixel.black)+pixel.black))));
+      color->black=ClampToQuantum((MagickRealType)
+        (QuantumRange-MagickMin(QuantumRange,(MagickRealType) (QuantumScale*
+        pixel.black*(QuantumRange-pixel.black)+pixel.black))));
+      return(status);
+    }
+  color->red=ClampToQuantum(pixel.red);
+  color->green=ClampToQuantum(pixel.green);
+  color->blue=ClampToQuantum(pixel.blue);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u e r y C o l o r D a t a b a s e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueryColorDatabase() returns the red, green, blue, and opacity intensities
+%  for a given color name.
+%
+%  The format of the QueryColorDatabase method is:
+%
+%      MagickBooleanType QueryColorDatabase(const char *name,PixelPacket *color,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the color name (e.g. white, blue, yellow).
+%
+%    o color: the red, green, blue, and opacity intensities values of the
+%      named color in this structure.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType QueryColorDatabase(const char *name,
+  PixelPacket *color,ExceptionInfo *exception)
+{
+  return(QueryColorCompliance(name,AllCompliance,color,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  Q u e r y C o l o r n a m e                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueryColorname() returns a named color for the given color intensity.  If
+%  an exact match is not found, a rgb() color is returned instead.
+%
+%  The format of the QueryColorname method is:
+%
+%      MagickBooleanType QueryColorname(const Image *image,
+%        const PixelPacket *color,const ComplianceType compliance,char *name,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o color: the color intensities.
+%
+%    o compliance: Adhere to this color standard: SVG, X11, or XPM.
+%
+%    o name: Return the color name or hex value.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType QueryColorname(const Image *image,
+  const PixelPacket *color,const ComplianceType compliance,char *name,
+  ExceptionInfo *exception)
+{
+  PixelInfo
+    pixel;
+
+  GetPixelInfo(image,&pixel);
+  SetPixelInfoPacket(image,color,&pixel);
+  return(QueryMagickColorname(image,&pixel,compliance,name,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u e r y M a g i c k C o l o r C o m p l i a n c e                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueryMagickColorCompliance() returns the red, green, blue, and alpha
+%  intensities for a given color name and standards compliance.
+%
+%  The format of the QueryMagickColor method is:
+%
+%      MagickBooleanType QueryMagickColor(const char *name,
+%        const ComplianceType compliance,PixelInfo *color,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the color name (e.g. white, blue, yellow).
+%
+%    o compliance: Adhere to this color standard: SVG, X11, or XPM.
+%
+%    o color: the red, green, blue, and opacity intensities values of the
+%      named color in this structure.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType QueryMagickColorCompliance(const char *name,
+  const ComplianceType compliance,PixelInfo *color,
+  ExceptionInfo *exception)
+{
+  GeometryInfo
+    geometry_info;
+
+  MagickRealType
+    scale;
+
+  MagickStatusType
+    flags;
+
+  register const ColorInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    type;
+
+  /*
+    Initialize color return value.
+  */
+  assert(name != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
+  assert(color != (PixelInfo *) NULL);
+  GetPixelInfo((Image *) NULL,color);
+  if ((name == (char *) NULL) || (*name == '\0'))
+    name=BackgroundColor;
+  while (isspace((int) ((unsigned char) *name)) != 0)
+    name++;
+  if (*name == '#')
+    {
+      char
+        c;
+
+      LongPixelPacket
+        pixel;
+
+      QuantumAny
+        range;
+
+      size_t
+        depth,
+        n;
+
+      /*
+        Parse hex color.
+      */
+      (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
+      name++;
+      for (n=0; isxdigit((int) ((unsigned char) name[n])) != MagickFalse; n++) ;
+      if ((n % 3) == 0)
+        {
+          do
+          {
+            pixel.red=pixel.green;
+            pixel.green=pixel.blue;
+            pixel.blue=0;
+            for (i=(ssize_t) (n/3-1); i >= 0; i--)
+            {
+              c=(*name++);
+              pixel.blue<<=4;
+              if ((c >= '0') && (c <= '9'))
+                pixel.blue|=(int) (c-'0');
+              else
+                if ((c >= 'A') && (c <= 'F'))
+                  pixel.blue|=(int) c-((int) 'A'-10);
+                else
+                  if ((c >= 'a') && (c <= 'f'))
+                    pixel.blue|=(int) c-((int) 'a'-10);
+                  else
+                    return(MagickFalse);
+            }
+          } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
+          depth=4*(n/3);
+        }
+      else
+        {
+          if ((n % 4) != 0)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionWarning,"UnrecognizedColor","`%s'",name);
+              return(MagickFalse);
+            }
+          do
+          {
+            pixel.red=pixel.green;
+            pixel.green=pixel.blue;
+            pixel.blue=pixel.alpha;
+            pixel.alpha=0;
+            for (i=(ssize_t) (n/4-1); i >= 0; i--)
+            {
+              c=(*name++);
+              pixel.alpha<<=4;
+              if ((c >= '0') && (c <= '9'))
+                pixel.alpha|=(int) (c-'0');
+              else
+                if ((c >= 'A') && (c <= 'F'))
+                  pixel.alpha|=(int) c-((int) 'A'-10);
+                else
+                  if ((c >= 'a') && (c <= 'f'))
+                    pixel.alpha|=(int) c-((int) 'a'-10);
+                  else
+                    return(MagickFalse);
+            }
+          } while (isxdigit((int) ((unsigned char) *name)) != MagickFalse);
+          depth=4*(n/4);
+        }
+      color->colorspace=RGBColorspace;
+      color->matte=MagickFalse;
+      range=GetQuantumRange(depth);
+      color->red=(MagickRealType) ScaleAnyToQuantum(pixel.red,range);
+      color->green=(MagickRealType) ScaleAnyToQuantum(pixel.green,range);
+      color->blue=(MagickRealType) ScaleAnyToQuantum(pixel.blue,range);
+      color->alpha=(MagickRealType) OpaqueAlpha;
+      if ((n % 3) != 0)
+        {
+          color->matte=MagickTrue;
+          color->alpha=(MagickRealType) ScaleAnyToQuantum(pixel.alpha,range);
+        }
+      color->black=0.0;
+      return(MagickTrue);
+    }
+  if (strchr(name,'(') != (char *) NULL)
+    {
+      char
+        colorspace[MaxTextExtent];
+
+      /*
+        Parse color of the form rgb(100,255,0).
+      */
+      (void) CopyMagickString(colorspace,name,MaxTextExtent);
+      for (i=0; colorspace[i] != '\0'; i++)
+        if (colorspace[i] == '(')
+          break;
+      colorspace[i--]='\0';
+      LocaleLower(colorspace);
+      color->matte=MagickFalse;
+      if ((i > 0) && (colorspace[i] == 'a'))
+        {
+          colorspace[i]='\0';
+          color->matte=MagickTrue;
+        }
+      type=ParseCommandOption(MagickColorspaceOptions,MagickFalse,colorspace);
+      if (type < 0)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            OptionWarning,"UnrecognizedColor","`%s'",name);
+          return(MagickFalse);
+        }
+      color->colorspace=(ColorspaceType) type;
+      SetGeometryInfo(&geometry_info);
+      flags=ParseGeometry(name+i+1,&geometry_info);
+      scale=(MagickRealType) ScaleCharToQuantum(1);
+      if ((flags & PercentValue) != 0)
+        scale=(MagickRealType) (QuantumRange/100.0);
+      if ((flags & RhoValue) != 0)
+        color->red=(MagickRealType) ClampToQuantum(scale*geometry_info.rho);
+      if ((flags & SigmaValue) != 0)
+        color->green=(MagickRealType) ClampToQuantum(scale*geometry_info.sigma);
+      if ((flags & XiValue) != 0)
+        color->blue=(MagickRealType) ClampToQuantum(scale*geometry_info.xi);
+      color->alpha=(MagickRealType) OpaqueAlpha;
+      if ((flags & PsiValue) != 0)
+        {
+          if (color->colorspace == CMYKColorspace)
+            color->black=(MagickRealType) ClampToQuantum(scale*
+              geometry_info.psi);
+          else
+            if (color->matte != MagickFalse)
+              color->alpha=(MagickRealType) ClampToQuantum((MagickRealType)
+                QuantumRange*geometry_info.psi);
+        }
+      if (((flags & ChiValue) != 0) && (color->matte != MagickFalse))
+        color->alpha=(MagickRealType) ClampToQuantum((MagickRealType)
+          QuantumRange*geometry_info.chi);
+      if (LocaleCompare(colorspace,"gray") == 0)
+        {
+          color->green=color->red;
+          color->blue=color->red;
+          if (((flags & SigmaValue) != 0) && (color->matte != MagickFalse))
+            color->alpha=(MagickRealType) ClampToQuantum((MagickRealType)
+              QuantumRange*geometry_info.sigma);
+        }
+      if ((LocaleCompare(colorspace,"HSB") == 0) ||
+          (LocaleCompare(colorspace,"HSL") == 0) ||
+          (LocaleCompare(colorspace,"HWB") == 0))
+        {
+          PixelPacket
+            pixel;
+
+          scale=1.0/360.0;
+          if ((flags & PercentValue) != 0)
+            scale=1.0/100.0;
+          geometry_info.rho*=360.0*scale;
+          scale=1.0/255.0;
+          if ((flags & PercentValue) != 0)
+            scale=1.0/100.0;
+          geometry_info.sigma*=scale;
+          geometry_info.xi*=scale;
+          if (LocaleCompare(colorspace,"HSB") == 0)
+            ConvertHSBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
+              360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
+              &pixel.green,&pixel.blue);
+          else
+            if (LocaleCompare(colorspace,"HSL") == 0)
+              ConvertHSLToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
+                360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
+                &pixel.green,&pixel.blue);
+            else
+              ConvertHWBToRGB(fmod(fmod(geometry_info.rho,360.0)+360.0,360.0)/
+                360.0,geometry_info.sigma,geometry_info.xi,&pixel.red,
+                &pixel.green,&pixel.blue);
+          color->colorspace=RGBColorspace;
+          color->red=(MagickRealType) pixel.red;
+          color->green=(MagickRealType) pixel.green;
+          color->blue=(MagickRealType) pixel.blue;
+        }
+      return(MagickTrue);
+    }
+  /*
+    Parse named color.
+  */
+  p=GetColorCompliance(name,compliance,exception);
+  if (p == (const ColorInfo *) NULL)
+    return(MagickFalse);
+  color->colorspace=RGBColorspace;
+  color->matte=p->color.alpha != OpaqueAlpha ? MagickTrue : MagickFalse;
+  color->red=(MagickRealType) p->color.red;
+  color->green=(MagickRealType) p->color.green;
+  color->blue=(MagickRealType) p->color.blue;
+  color->alpha=(MagickRealType) p->color.alpha;
+  color->black=0.0;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u e r y M a g i c k C o l o r                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueryMagickColor() returns the red, green, blue, and opacity intensities
+%  for a given color name.
+%
+%  The format of the QueryMagickColor method is:
+%
+%      MagickBooleanType QueryMagickColor(const char *name,
+%        PixelInfo *color,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the color name (e.g. white, blue, yellow).
+%
+%    o color: the red, green, blue, and opacity intensities values of the
+%      named color in this structure.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType QueryMagickColor(const char *name,
+  PixelInfo *color,ExceptionInfo *exception)
+{
+  return(QueryMagickColorCompliance(name,AllCompliance,color,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  Q u e r y M a g i c k C o l o r n a m e                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueryMagickColorname() returns a named color for the given color intensity.
+%  If an exact match is not found, a hex value is returned instead.  For
+%  example an intensity of rgb:(0,0,0) returns black whereas rgb:(223,223,223)
+%  returns #dfdfdf.
+%
+%  The format of the QueryMagickColorname method is:
+%
+%      MagickBooleanType QueryMagickColorname(const Image *image,
+%        const PixelPacket *color,const ComplianceType compliance,char *name,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o color: the color intensities.
+%
+%    o Compliance: Adhere to this color standard: SVG, X11, or XPM.
+%
+%    o name: Return the color name or hex value.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType QueryMagickColorname(const Image *image,
+  const PixelInfo *color,const ComplianceType compliance,
+  char *name,ExceptionInfo *exception)
+{
+  PixelInfo
+    pixel;
+
+  MagickRealType
+    opacity;
+
+  register const ColorInfo
+    *p;
+
+  *name='\0';
+  pixel=(*color);
+  if (compliance == XPMCompliance)
+    {
+      pixel.matte=MagickFalse;
+      pixel.depth=(size_t) MagickMin(1.0*image->depth,16.0);
+    }
+  GetColorTuple(&pixel,compliance != SVGCompliance ? MagickTrue : MagickFalse,
+    name);
+  (void) GetColorInfo("*",exception);
+  ResetLinkedListIterator(color_list);
+  opacity=image->matte != MagickFalse ? color->alpha : OpaqueAlpha;
+  p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  while (p != (const ColorInfo *) NULL)
+  {
+    if (((p->compliance & compliance) != 0) && ((p->color.red == color->red)) &&
+         (p->color.green == color->green) && (p->color.blue == color->blue) &&
+         (p->color.alpha == opacity))
+      {
+        (void) CopyMagickString(name,p->name,MaxTextExtent);
+        break;
+      }
+    p=(const ColorInfo *) GetNextValueInLinkedList(color_list);
+  }
+  return(MagickTrue);
+}
diff --git a/MagickCore/color.h b/MagickCore/color.h
new file mode 100644
index 0000000..b6bcafe
--- /dev/null
+++ b/MagickCore/color.h
@@ -0,0 +1,100 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image color methods.
+*/
+#ifndef _MAGICKCORE_COLOR_H
+#define _MAGICKCORE_COLOR_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/pixel.h>
+#include <MagickCore/exception.h>
+
+typedef enum
+{
+  UndefinedCompliance,
+  NoCompliance = 0x0000,
+  SVGCompliance = 0x0001,
+  X11Compliance = 0x0002,
+  XPMCompliance = 0x0004,
+  AllCompliance = 0x7fffffff
+} ComplianceType;
+
+typedef struct _ColorInfo
+{
+  char
+    *path,
+    *name;
+
+  ComplianceType
+    compliance;
+
+  PixelInfo
+    color;
+
+  MagickBooleanType
+    exempt,
+    stealth;
+
+  size_t
+    signature;
+} ColorInfo;
+
+typedef struct _ErrorInfo
+{
+  double
+    mean_error_per_pixel,
+    normalized_mean_error,
+    normalized_maximum_error;
+} ErrorInfo;
+
+extern MagickExport char
+  **GetColorList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const ColorInfo
+  *GetColorInfo(const char *,ExceptionInfo *),
+  **GetColorInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ColorComponentGenesis(void),
+  IsEquivalentAlpha(const Image *,const PixelPacket *,const PixelPacket *),
+  IsEquivalentImage(const Image *,const Image *,ssize_t *x,ssize_t *y,
+    ExceptionInfo *),
+  ListColorInfo(FILE *,ExceptionInfo *),
+  QueryColorCompliance(const char *,const ComplianceType,PixelPacket *,
+    ExceptionInfo *),
+  QueryColorDatabase(const char *,PixelPacket *,ExceptionInfo *),
+  QueryColorname(const Image *,const PixelPacket *,const ComplianceType,char *,
+    ExceptionInfo *),
+  QueryMagickColor(const char *,PixelInfo *,ExceptionInfo *),
+  QueryMagickColorCompliance(const char *,const ComplianceType,
+    PixelInfo *,ExceptionInfo *),
+  QueryMagickColorname(const Image *,const PixelInfo *,
+    const ComplianceType,char *,ExceptionInfo *);
+
+extern MagickExport void
+  ColorComponentTerminus(void),
+  ConcatenateColorComponent(const PixelInfo *,const ChannelType,
+    const ComplianceType,char *),
+  GetColorTuple(const PixelInfo *,const MagickBooleanType,char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/colormap-private.h b/MagickCore/colormap-private.h
new file mode 100644
index 0000000..8953148
--- /dev/null
+++ b/MagickCore/colormap-private.h
@@ -0,0 +1,42 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image colormap methods.
+*/
+#ifndef _MAGICKCORE_COLORMAP_PRIVATE_H
+#define _MAGICKCORE_COLORMAP_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/image.h>
+#include <MagickCore/color.h>
+#include <MagickCore/exception-private.h>
+
+static inline Quantum ConstrainColormapIndex(Image *image,const size_t index)
+{
+  if (index < image->colors)
+    return((Quantum) index);
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+  return((Quantum) 0);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/colormap.c b/MagickCore/colormap.c
new file mode 100644
index 0000000..42be2fc
--- /dev/null
+++ b/MagickCore/colormap.c
@@ -0,0 +1,383 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            CCCC   OOO   L       OOO   RRRR   M   M   AAA   PPPP             %
+%           C      O   O  L      O   O  R   R  MM MM  A   A  P   P            %
+%           C      O   O  L      O   O  RRRR   M M M  AAAAA  PPPP             %
+%           C      O   O  L      O   O  R R    M   M  A   A  P                %
+%            CCCC   OOO   LLLLL   OOO   R  R   M   M  A   A  P                %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Colormap Methods                          %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  We use linked-lists because splay-trees do not currently support duplicate
+%  key / value pairs (.e.g X11 green compliance and SVG green compliance).
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e I m a g e C o l o r m a p                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireImageColormap() allocates an image colormap and initializes
+%  it to a linear gray colorspace.  If the image already has a colormap,
+%  it is replaced.  AcquireImageColormap() returns MagickTrue if successful,
+%  otherwise MagickFalse if there is not enough memory.
+%
+%  The format of the AcquireImageColormap method is:
+%
+%      MagickBooleanType AcquireImageColormap(Image *image,
+%        const size_t colors)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colors: the number of colors in the image colormap.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,
+  const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline size_t MagickMin(const size_t x,
+  const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType AcquireImageColormap(Image *image,
+  const size_t colors)
+{
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  /*
+    Allocate image colormap.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  image->colors=colors;
+  length=(size_t) colors;
+  if (image->colormap == (PixelPacket *) NULL)
+    image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
+      sizeof(*image->colormap));
+  else
+    image->colormap=(PixelPacket *) ResizeQuantumMemory(image->colormap,length,
+      sizeof(*image->colormap));
+  if (image->colormap == (PixelPacket *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  for (i=0; i < (ssize_t) image->colors; i++)
+  {
+    size_t
+      pixel;
+
+    pixel=(size_t) (i*(QuantumRange/MagickMax(colors-1,1)));
+    image->colormap[i].red=(Quantum) pixel;
+    image->colormap[i].green=(Quantum) pixel;
+    image->colormap[i].blue=(Quantum) pixel;
+    image->colormap[i].alpha=OpaqueAlpha;
+  }
+  return(SetImageStorageClass(image,PseudoClass));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C y c l e C o l o r m a p I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CycleColormap() displaces an image's colormap by a given number of
+%  positions.  If you cycle the colormap a number of times you can produce
+%  a psychodelic effect.
+%
+%  The format of the CycleColormapImage method is:
+%
+%      MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o displace:  displace the colormap this amount.
+%
+*/
+MagickExport MagickBooleanType CycleColormapImage(Image *image,
+  const ssize_t displace)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->storage_class == DirectClass)
+    (void) SetImageType(image,PaletteType);
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    ssize_t
+      index;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      index=(ssize_t) (GetPixelIndex(image,q)+displace) % image->colors;
+      if (index < 0)
+        index+=(ssize_t) image->colors;
+      SetPixelIndex(image,(Quantum) index,q);
+      SetPixelPacket(image,image->colormap+(ssize_t) index,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S o r t C o l o r m a p B y I n t e n s i t y                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SortColormapByIntensity() sorts the colormap of a PseudoClass image by
+%  decreasing color intensity.
+%
+%  The format of the SortColormapByIntensity method is:
+%
+%      MagickBooleanType SortColormapByIntensity(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: A pointer to an Image structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int IntensityCompare(const void *x,const void *y)
+{
+  const PixelPacket
+    *color_1,
+    *color_2;
+
+  int
+    intensity;
+
+  color_1=(const PixelPacket *) x;
+  color_2=(const PixelPacket *) y;
+  intensity=(int) GetPixelPacketIntensity(color_2)-(int)
+    GetPixelPacketIntensity(color_1);
+  return(intensity);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport MagickBooleanType SortColormapByIntensity(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  unsigned short
+    *pixels;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (image->storage_class != PseudoClass)
+    return(MagickTrue);
+  /*
+    Allocate memory for pixel indexes.
+  */
+  pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors,
+    sizeof(*pixels));
+  if (pixels == (unsigned short *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  /*
+    Assign index values to colormap entries.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < (ssize_t) image->colors; i++)
+    image->colormap[i].alpha=(Quantum) i;
+  /*
+    Sort image colormap by decreasing color popularity.
+  */
+  qsort((void *) image->colormap,(size_t) image->colors,
+    sizeof(*image->colormap),IntensityCompare);
+  /*
+    Update image colormap indexes to sorted colormap order.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < (ssize_t) image->colors; i++)
+    pixels[(ssize_t) image->colormap[i].alpha]=(unsigned short) i;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    Quantum
+      index;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      index=(Quantum) pixels[(ssize_t) GetPixelIndex(image,q)];
+      SetPixelIndex(image,index,q);
+      SetPixelPacket(image,image->colormap+(ssize_t) index,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  pixels=(unsigned short *) RelinquishMagickMemory(pixels);
+  return(status);
+}
diff --git a/MagickCore/colormap.h b/MagickCore/colormap.h
new file mode 100644
index 0000000..d81fa66
--- /dev/null
+++ b/MagickCore/colormap.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image colormap methods.
+*/
+#ifndef _MAGICKCORE_COLORMAP_H
+#define _MAGICKCORE_COLORMAP_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  AcquireImageColormap(Image *,const size_t),
+  CycleColormapImage(Image *,const ssize_t),
+  SortColormapByIntensity(Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/colorspace-private.h b/MagickCore/colorspace-private.h
new file mode 100644
index 0000000..6933411
--- /dev/null
+++ b/MagickCore/colorspace-private.h
@@ -0,0 +1,72 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image colorspace private methods.
+*/
+#ifndef _MAGICKCORE_COLORSPACE_PRIVATE_H
+#define _MAGICKCORE_COLORSPACE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/image-private.h>
+#include <MagickCore/pixel.h>
+
+static inline MagickBooleanType IsGrayColorspace(
+  const ColorspaceType colorspace)
+{
+  if ((colorspace == GRAYColorspace) || (colorspace == Rec601LumaColorspace) || 
+      (colorspace == Rec709LumaColorspace))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+static inline void ConvertRGBToCMYK(PixelInfo *pixel)
+{
+  MagickRealType
+    black,
+    cyan,
+    magenta,
+    yellow;
+                                                                                
+  if ((pixel->red == 0) && (pixel->green == 0) && (pixel->blue == 0))
+    {
+      pixel->black=(MagickRealType) QuantumRange;
+      return;
+    }
+  cyan=(MagickRealType) (1.0-QuantumScale*pixel->red);
+  magenta=(MagickRealType) (1.0-QuantumScale*pixel->green);
+  yellow=(MagickRealType) (1.0-QuantumScale*pixel->blue);
+  black=cyan;
+  if (magenta < black)
+    black=magenta;
+  if (yellow < black)
+    black=yellow;
+  cyan=(MagickRealType) ((cyan-black)/(1.0-black));
+  magenta=(MagickRealType) ((magenta-black)/(1.0-black));
+  yellow=(MagickRealType) ((yellow-black)/(1.0-black));
+  pixel->colorspace=CMYKColorspace;
+  pixel->red=QuantumRange*cyan;
+  pixel->green=QuantumRange*magenta;
+  pixel->blue=QuantumRange*yellow;
+  pixel->black=QuantumRange*black;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/colorspace.c b/MagickCore/colorspace.c
new file mode 100644
index 0000000..bdcd743
--- /dev/null
+++ b/MagickCore/colorspace.c
@@ -0,0 +1,2660 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     CCCC   OOO   L       OOO   RRRR   SSSSS  PPPP    AAA    CCCC  EEEEE     %
+%    C      O   O  L      O   O  R   R  SS     P   P  A   A  C      E         %
+%    C      O   O  L      O   O  RRRR    SSS   PPPP   AAAAA  C      EEE       %
+%    C      O   O  L      O   O  R R       SS  P      A   A  C      E         %
+%     CCCC   OOO   LLLLL   OOO   R  R   SSSSS  P      A   A   CCCC  EEEEE     %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Colorspace Methods                     %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/utility.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _TransformPacket
+{
+  MagickRealType
+    x,
+    y,
+    z;
+} TransformPacket;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     R G B T r a n s f o r m I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RGBTransformImage() converts the reference image from RGB to an alternate
+%  colorspace.  The transformation matrices are not the standard ones: the
+%  weights are rescaled to normalized the range of the transformed values to
+%  be [0..QuantumRange].
+%
+%  The format of the RGBTransformImage method is:
+%
+%      MagickBooleanType RGBTransformImage(Image *image,
+%        const ColorspaceType colorspace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colorspace: the colorspace to transform the image to.
+%
+*/
+
+static inline void ConvertRGBToXYZ(const Quantum red,const Quantum green,
+  const Quantum blue,double *X,double *Y,double *Z)
+{
+  double
+    b,
+    g,
+    r;
+
+  assert(X != (double *) NULL);
+  assert(Y != (double *) NULL);
+  assert(Z != (double *) NULL);
+  r=QuantumScale*red;
+  if (r > 0.04045)
+    r=pow((r+0.055)/1.055,2.4);
+  else
+    r/=12.92;
+  g=QuantumScale*green;
+  if (g > 0.04045)
+    g=pow((g+0.055)/1.055,2.4);
+  else
+    g/=12.92;
+  b=QuantumScale*blue;
+  if (b > 0.04045)
+    b=pow((b+0.055)/1.055,2.4);
+  else
+    b/=12.92;
+  *X=0.4124240*r+0.3575790*g+0.1804640*b;
+  *Y=0.2126560*r+0.7151580*g+0.0721856*b;
+  *Z=0.0193324*r+0.1191930*g+0.9504440*b;
+}
+
+static double LabF1(double alpha)
+{
+
+  if (alpha <= ((24.0/116.0)*(24.0/116.0)*(24.0/116.0)))
+    return((841.0/108.0)*alpha+(16.0/116.0));
+  return(pow(alpha,1.0/3.0));
+}
+
+static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
+  double *L,double *a,double *b)
+{
+#define D50X  (0.9642)
+#define D50Y  (1.0)
+#define D50Z  (0.8249)
+
+  double
+    fx,
+    fy,
+    fz;
+
+  assert(L != (double *) NULL);
+  assert(a != (double *) NULL);
+  assert(b != (double *) NULL);
+  *L=0.0;
+  *a=0.5;
+  *b=0.5;
+  if ((X == 0.0) && (Y == 0.0) && (Z == 0.0))
+    return;
+  fx=LabF1(X/D50X);
+  fy=LabF1(Y/D50Y);
+  fz=LabF1(Z/D50Z);
+  *L=(116.0*fy-16.0)/100.0;
+  *a=(500.0*(fx-fy))/255.0;
+  if (*a < 0.0)
+    *a+=1.0;
+  *b=(200.0*(fy-fz))/255.0;
+  if (*b < 0.0)
+    *b+=1.0;
+}
+
+MagickExport MagickBooleanType RGBTransformImage(Image *image,
+  const ColorspaceType colorspace)
+{
+#define RGBTransformImageTag  "RGBTransform/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status,
+    sync;
+
+  MagickOffsetType
+    progress;
+
+  PrimaryInfo
+    primary_info;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  TransformPacket
+    *x_map,
+    *y_map,
+    *z_map;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(colorspace != RGBColorspace);
+  assert(colorspace != TransparentColorspace);
+  assert(colorspace != UndefinedColorspace);
+  switch (image->colorspace)
+  {
+    case GRAYColorspace:
+    case Rec601LumaColorspace:
+    case Rec709LumaColorspace:
+    case RGBColorspace:
+    case TransparentColorspace:
+      break;
+    default:
+    {
+      (void) TransformImageColorspace(image,image->colorspace);
+      break;
+    }
+  }
+  if (SetImageColorspace(image,colorspace) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  switch (colorspace)
+  {
+    case CMYColorspace:
+    {
+      /*
+        Convert RGB to CMY colorspace.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,ClampToQuantum((MagickRealType) (QuantumRange-
+            GetPixelRed(image,q))),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) (QuantumRange-
+            GetPixelGreen(image,q))),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) (QuantumRange-
+            GetPixelBlue(image,q))),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      image->type=image->matte == MagickFalse ? ColorSeparationType :
+        ColorSeparationMatteType;
+      return(status);
+    }
+    case CMYKColorspace:
+    {
+      PixelInfo
+        zero;
+
+      /*
+        Convert RGB to CMYK colorspace.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      GetPixelInfo(image,&zero);
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        PixelInfo
+          pixel;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        pixel=zero;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelInfo(image,q,&pixel);
+          ConvertRGBToCMYK(&pixel);
+          SetPixelPixelInfo(image,&pixel,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      image->type=image->matte == MagickFalse ? ColorSeparationType :
+        ColorSeparationMatteType;
+      return(status);
+    }
+    case HSBColorspace:
+    {
+      /*
+        Transform image from RGB to HSB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          brightness,
+          hue,
+          saturation;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        hue=0.0;
+        saturation=0.0;
+        brightness=0.0;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          ConvertRGBToHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
+            GetPixelBlue(image,q),&hue,&saturation,&brightness);
+          SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+            hue),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+            saturation),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+            brightness),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case HSLColorspace:
+    {
+      /*
+        Transform image from RGB to HSL.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          hue,
+          lightness,
+          saturation;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        hue=0.0;
+        saturation=0.0;
+        lightness=0.0;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          ConvertRGBToHSL(GetPixelRed(image,q),GetPixelGreen(image,q),
+            GetPixelBlue(image,q),&hue,&saturation,&lightness);
+          SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+            hue),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+            saturation),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+            lightness),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case HWBColorspace:
+    {
+      /*
+        Transform image from RGB to HWB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          blackness,
+          hue,
+          whiteness;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        hue=0.0;
+        whiteness=0.0;
+        blackness=0.0;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          ConvertRGBToHWB(GetPixelRed(image,q),GetPixelGreen(image,q),
+            GetPixelBlue(image,q),&hue,&whiteness,&blackness);
+          SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+            hue),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+            whiteness),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+            blackness),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case LabColorspace:
+    {
+      /*
+        Transform image from RGB to Lab.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          a,
+          b,
+          L,
+          X,
+          Y,
+          Z;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        L=0.0;
+        a=0.0;
+        b=0.0;
+        X=0.0;
+        Y=0.0;
+        Z=0.0;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          ConvertRGBToXYZ(GetPixelRed(image,q),GetPixelGreen(image,q),
+            GetPixelBlue(image,q),&X,&Y,&Z);
+          ConvertXYZToLab(X,Y,Z,&L,&a,&b);
+          SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+            L),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+            a),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+            b),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case LogColorspace:
+    {
+#define DisplayGamma  (1.0/1.7)
+#define FilmGamma  0.6
+#define ReferenceBlack  95.0
+#define ReferenceWhite  685.0
+
+      const char
+        *value;
+
+      double
+        black,
+        density,
+        film_gamma,
+        gamma,
+        reference_black,
+        reference_white;
+
+      Quantum
+        *logmap;
+
+      /*
+        Transform RGB to Log colorspace.
+      */
+      density=DisplayGamma;
+      gamma=DisplayGamma;
+      value=GetImageProperty(image,"gamma");
+      if (value != (const char *) NULL)
+        gamma=1.0/InterpretLocaleValue(value,(char **) NULL) != 0.0 ?
+          InterpretLocaleValue(value,(char **) NULL) : 1.0;
+      film_gamma=FilmGamma;
+      value=GetImageProperty(image,"film-gamma");
+      if (value != (const char *) NULL)
+        film_gamma=InterpretLocaleValue(value,(char **) NULL);
+      reference_black=ReferenceBlack;
+      value=GetImageProperty(image,"reference-black");
+      if (value != (const char *) NULL)
+        reference_black=InterpretLocaleValue(value,(char **) NULL);
+      reference_white=ReferenceWhite;
+      value=GetImageProperty(image,"reference-white");
+      if (value != (const char *) NULL)
+        reference_white=InterpretLocaleValue(value,(char **) NULL);
+      logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+        sizeof(*logmap));
+      if (logmap == (Quantum *) NULL)
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename);
+      black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
+        0.002/film_gamma);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+        logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
+          log10(black+((MagickRealType) i/MaxMap)*(1.0-black))/((gamma/density)*
+          0.002/film_gamma))/1024.0));
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=(ssize_t) image->columns; x != 0; x--)
+        {
+          SetPixelRed(image,logmap[ScaleQuantumToMap(
+            GetPixelRed(image,q))],q);
+          SetPixelGreen(image,logmap[ScaleQuantumToMap(
+            GetPixelGreen(image,q))],q);
+          SetPixelBlue(image,logmap[ScaleQuantumToMap(
+            GetPixelBlue(image,q))],q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      logmap=(Quantum *) RelinquishMagickMemory(logmap);
+      return(status);
+    }
+    default:
+      break;
+  }
+  /*
+    Allocate the tables.
+  */
+  x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+    sizeof(*x_map));
+  y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+    sizeof(*y_map));
+  z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+    sizeof(*z_map));
+  if ((x_map == (TransformPacket *) NULL) ||
+      (y_map == (TransformPacket *) NULL) ||
+      (z_map == (TransformPacket *) NULL))
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  (void) ResetMagickMemory(&primary_info,0,sizeof(primary_info));
+  switch (colorspace)
+  {
+    case OHTAColorspace:
+    {
+      /*
+        Initialize OHTA tables:
+
+          I1 = 0.33333*R+0.33334*G+0.33333*B
+          I2 = 0.50000*R+0.00000*G-0.50000*B
+          I3 =-0.25000*R+0.50000*G-0.25000*B
+
+        I and Q, normally -0.5 through 0.5, are normalized to the range 0
+        through QuantumRange.
+      */
+      primary_info.y=(double) (MaxMap+1.0)/2.0;
+      primary_info.z=(double) (MaxMap+1.0)/2.0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.33333f*(MagickRealType) i;
+        y_map[i].x=0.33334f*(MagickRealType) i;
+        z_map[i].x=0.33333f*(MagickRealType) i;
+        x_map[i].y=0.50000f*(MagickRealType) i;
+        y_map[i].y=0.00000f*(MagickRealType) i;
+        z_map[i].y=(-0.50000f)*(MagickRealType) i;
+        x_map[i].z=(-0.25000f)*(MagickRealType) i;
+        y_map[i].z=0.50000f*(MagickRealType) i;
+        z_map[i].z=(-0.25000f)*(MagickRealType) i;
+      }
+      break;
+    }
+    case Rec601LumaColorspace:
+    case GRAYColorspace:
+    {
+      /*
+        Initialize Rec601 luma tables:
+
+          G = 0.29900*R+0.58700*G+0.11400*B
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.29900f*(MagickRealType) i;
+        y_map[i].x=0.58700f*(MagickRealType) i;
+        z_map[i].x=0.11400f*(MagickRealType) i;
+        x_map[i].y=0.29900f*(MagickRealType) i;
+        y_map[i].y=0.58700f*(MagickRealType) i;
+        z_map[i].y=0.11400f*(MagickRealType) i;
+        x_map[i].z=0.29900f*(MagickRealType) i;
+        y_map[i].z=0.58700f*(MagickRealType) i;
+        z_map[i].z=0.11400f*(MagickRealType) i;
+      }
+      image->type=GrayscaleType;
+      break;
+    }
+    case Rec601YCbCrColorspace:
+    case YCbCrColorspace:
+    {
+      /*
+        Initialize YCbCr tables (ITU-R BT.601):
+
+          Y =  0.299000*R+0.587000*G+0.114000*B
+          Cb= -0.168736*R-0.331264*G+0.500000*B
+          Cr=  0.500000*R-0.418688*G-0.081312*B
+
+        Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
+        through QuantumRange.
+      */
+      primary_info.y=(double) (MaxMap+1.0)/2.0;
+      primary_info.z=(double) (MaxMap+1.0)/2.0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.299000f*(MagickRealType) i;
+        y_map[i].x=0.587000f*(MagickRealType) i;
+        z_map[i].x=0.114000f*(MagickRealType) i;
+        x_map[i].y=(-0.168730f)*(MagickRealType) i;
+        y_map[i].y=(-0.331264f)*(MagickRealType) i;
+        z_map[i].y=0.500000f*(MagickRealType) i;
+        x_map[i].z=0.500000f*(MagickRealType) i;
+        y_map[i].z=(-0.418688f)*(MagickRealType) i;
+        z_map[i].z=(-0.081312f)*(MagickRealType) i;
+      }
+      break;
+    }
+    case Rec709LumaColorspace:
+    {
+      /*
+        Initialize Rec709 luma tables:
+
+          G = 0.21260*R+0.71520*G+0.07220*B
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.21260f*(MagickRealType) i;
+        y_map[i].x=0.71520f*(MagickRealType) i;
+        z_map[i].x=0.07220f*(MagickRealType) i;
+        x_map[i].y=0.21260f*(MagickRealType) i;
+        y_map[i].y=0.71520f*(MagickRealType) i;
+        z_map[i].y=0.07220f*(MagickRealType) i;
+        x_map[i].z=0.21260f*(MagickRealType) i;
+        y_map[i].z=0.71520f*(MagickRealType) i;
+        z_map[i].z=0.07220f*(MagickRealType) i;
+      }
+      break;
+    }
+    case Rec709YCbCrColorspace:
+    {
+      /*
+        Initialize YCbCr tables (ITU-R BT.709):
+
+          Y =  0.212600*R+0.715200*G+0.072200*B
+          Cb= -0.114572*R-0.385428*G+0.500000*B
+          Cr=  0.500000*R-0.454153*G-0.045847*B
+
+        Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
+        through QuantumRange.
+      */
+      primary_info.y=(double) (MaxMap+1.0)/2.0;
+      primary_info.z=(double) (MaxMap+1.0)/2.0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.212600f*(MagickRealType) i;
+        y_map[i].x=0.715200f*(MagickRealType) i;
+        z_map[i].x=0.072200f*(MagickRealType) i;
+        x_map[i].y=(-0.114572f)*(MagickRealType) i;
+        y_map[i].y=(-0.385428f)*(MagickRealType) i;
+        z_map[i].y=0.500000f*(MagickRealType) i;
+        x_map[i].z=0.500000f*(MagickRealType) i;
+        y_map[i].z=(-0.454153f)*(MagickRealType) i;
+        z_map[i].z=(-0.045847f)*(MagickRealType) i;
+      }
+      break;
+    }
+    case sRGBColorspace:
+    {
+      /*
+        Linear sRGB to nonlinear RGB (http://www.w3.org/Graphics/Color/sRGB):
+
+          R = 1.0*R+0.0*G+0.0*B
+          G = 0.0*R+0.1*G+0.0*B
+          B = 0.0*R+0.0*G+1.0*B
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        MagickRealType
+          v;
+
+        v=(MagickRealType) i/(MagickRealType) MaxMap;
+        if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.04045f)
+          v/=12.92f;
+        else
+          v=(MagickRealType) pow((((double) i/MaxMap)+0.055)/1.055,2.4);
+        x_map[i].x=1.0f*MaxMap*v;
+        y_map[i].x=0.0f*MaxMap*v;
+        z_map[i].x=0.0f*MaxMap*v;
+        x_map[i].y=0.0f*MaxMap*v;
+        y_map[i].y=1.0f*MaxMap*v;
+        z_map[i].y=0.0f*MaxMap*v;
+        x_map[i].z=0.0f*MaxMap*v;
+        y_map[i].z=0.0f*MaxMap*v;
+        z_map[i].z=1.0f*MaxMap*v;
+      }
+      break;
+    }
+    case XYZColorspace:
+    {
+      /*
+        Initialize CIE XYZ tables (ITU-R 709 RGB):
+
+          X = 0.4124564*R+0.3575761*G+0.1804375*B
+          Y = 0.2126729*R+0.7151522*G+0.0721750*B
+          Z = 0.0193339*R+0.1191920*G+0.9503041*B
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.4124564f*(MagickRealType) i;
+        y_map[i].x=0.3575761f*(MagickRealType) i;
+        z_map[i].x=0.1804375f*(MagickRealType) i;
+        x_map[i].y=0.2126729f*(MagickRealType) i;
+        y_map[i].y=0.7151522f*(MagickRealType) i;
+        z_map[i].y=0.0721750f*(MagickRealType) i;
+        x_map[i].z=0.0193339f*(MagickRealType) i;
+        y_map[i].z=0.1191920f*(MagickRealType) i;
+        z_map[i].z=0.9503041f*(MagickRealType) i;
+      }
+      break;
+    }
+    case YCCColorspace:
+    {
+      /*
+        Initialize YCC tables:
+
+          Y =  0.29900*R+0.58700*G+0.11400*B
+          C1= -0.29900*R-0.58700*G+0.88600*B
+          C2=  0.70100*R-0.58700*G-0.11400*B
+
+        YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
+      */
+      primary_info.y=(double) ScaleQuantumToMap(ScaleCharToQuantum(156));
+      primary_info.z=(double) ScaleQuantumToMap(ScaleCharToQuantum(137));
+      for (i=0; i <= (ssize_t) (0.018*MaxMap); i++)
+      {
+        x_map[i].x=0.003962014134275617f*(MagickRealType) i;
+        y_map[i].x=0.007778268551236748f*(MagickRealType) i;
+        z_map[i].x=0.001510600706713781f*(MagickRealType) i;
+        x_map[i].y=(-0.002426619775463276f)*(MagickRealType) i;
+        y_map[i].y=(-0.004763965913702149f)*(MagickRealType) i;
+        z_map[i].y=0.007190585689165425f*(MagickRealType) i;
+        x_map[i].z=0.006927257754597858f*(MagickRealType) i;
+        y_map[i].z=(-0.005800713697502058f)*(MagickRealType) i;
+        z_map[i].z=(-0.0011265440570958f)*(MagickRealType) i;
+      }
+      for ( ; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.2201118963486454*(1.099f*(MagickRealType) i-0.099f);
+        y_map[i].x=0.4321260306242638*(1.099f*(MagickRealType) i-0.099f);
+        z_map[i].x=0.08392226148409894*(1.099f*(MagickRealType) i-0.099f);
+        x_map[i].y=(-0.1348122097479598)*(1.099f*(MagickRealType) i-0.099f);
+        y_map[i].y=(-0.2646647729834528)*(1.099f*(MagickRealType) i-0.099f);
+        z_map[i].y=0.3994769827314126*(1.099f*(MagickRealType) i-0.099f);
+        x_map[i].z=0.3848476530332144*(1.099f*(MagickRealType) i-0.099f);
+        y_map[i].z=(-0.3222618720834477)*(1.099f*(MagickRealType) i-0.099f);
+        z_map[i].z=(-0.06258578094976668)*(1.099f*(MagickRealType) i-0.099f);
+      }
+      break;
+    }
+    case YIQColorspace:
+    {
+      /*
+        Initialize YIQ tables:
+
+          Y = 0.29900*R+0.58700*G+0.11400*B
+          I = 0.59600*R-0.27400*G-0.32200*B
+          Q = 0.21100*R-0.52300*G+0.31200*B
+
+        I and Q, normally -0.5 through 0.5, are normalized to the range 0
+        through QuantumRange.
+      */
+      primary_info.y=(double) (MaxMap+1.0)/2.0;
+      primary_info.z=(double) (MaxMap+1.0)/2.0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.29900f*(MagickRealType) i;
+        y_map[i].x=0.58700f*(MagickRealType) i;
+        z_map[i].x=0.11400f*(MagickRealType) i;
+        x_map[i].y=0.59600f*(MagickRealType) i;
+        y_map[i].y=(-0.27400f)*(MagickRealType) i;
+        z_map[i].y=(-0.32200f)*(MagickRealType) i;
+        x_map[i].z=0.21100f*(MagickRealType) i;
+        y_map[i].z=(-0.52300f)*(MagickRealType) i;
+        z_map[i].z=0.31200f*(MagickRealType) i;
+      }
+      break;
+    }
+    case YPbPrColorspace:
+    {
+      /*
+        Initialize YPbPr tables (ITU-R BT.601):
+
+          Y =  0.299000*R+0.587000*G+0.114000*B
+          Pb= -0.168736*R-0.331264*G+0.500000*B
+          Pr=  0.500000*R-0.418688*G-0.081312*B
+
+        Pb and Pr, normally -0.5 through 0.5, are normalized to the range 0
+        through QuantumRange.
+      */
+      primary_info.y=(double) (MaxMap+1.0)/2.0;
+      primary_info.z=(double) (MaxMap+1.0)/2.0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.299000f*(MagickRealType) i;
+        y_map[i].x=0.587000f*(MagickRealType) i;
+        z_map[i].x=0.114000f*(MagickRealType) i;
+        x_map[i].y=(-0.168736f)*(MagickRealType) i;
+        y_map[i].y=(-0.331264f)*(MagickRealType) i;
+        z_map[i].y=0.500000f*(MagickRealType) i;
+        x_map[i].z=0.500000f*(MagickRealType) i;
+        y_map[i].z=(-0.418688f)*(MagickRealType) i;
+        z_map[i].z=(-0.081312f)*(MagickRealType) i;
+      }
+      break;
+    }
+    case YUVColorspace:
+    default:
+    {
+      /*
+        Initialize YUV tables:
+
+          Y =  0.29900*R+0.58700*G+0.11400*B
+          U = -0.14740*R-0.28950*G+0.43690*B
+          V =  0.61500*R-0.51500*G-0.10000*B
+
+        U and V, normally -0.5 through 0.5, are normalized to the range 0
+        through QuantumRange.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
+      */
+      primary_info.y=(double) (MaxMap+1.0)/2.0;
+      primary_info.z=(double) (MaxMap+1.0)/2.0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=0.29900f*(MagickRealType) i;
+        y_map[i].x=0.58700f*(MagickRealType) i;
+        z_map[i].x=0.11400f*(MagickRealType) i;
+        x_map[i].y=(-0.14740f)*(MagickRealType) i;
+        y_map[i].y=(-0.28950f)*(MagickRealType) i;
+        z_map[i].y=0.43690f*(MagickRealType) i;
+        x_map[i].z=0.61500f*(MagickRealType) i;
+        y_map[i].z=(-0.51500f)*(MagickRealType) i;
+        z_map[i].z=(-0.10000f)*(MagickRealType) i;
+      }
+      break;
+    }
+  }
+  /*
+    Convert from RGB.
+  */
+  switch (image->storage_class)
+  {
+    case DirectClass:
+    default:
+    {
+      /*
+        Convert DirectClass image.
+      */
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        PixelInfo
+          pixel;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        register size_t
+          blue,
+          green,
+          red;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          red=ScaleQuantumToMap(GetPixelRed(image,q));
+          green=ScaleQuantumToMap(GetPixelGreen(image,q));
+          blue=ScaleQuantumToMap(GetPixelBlue(image,q));
+          pixel.red=(x_map[red].x+y_map[green].x+z_map[blue].x)+
+            (MagickRealType) primary_info.x;
+          pixel.green=(x_map[red].y+y_map[green].y+z_map[blue].y)+
+            (MagickRealType) primary_info.y;
+          pixel.blue=(x_map[red].z+y_map[green].z+z_map[blue].z)+
+            (MagickRealType) primary_info.z;
+          SetPixelRed(image,ScaleMapToQuantum(pixel.red),q);
+          SetPixelGreen(image,ScaleMapToQuantum(pixel.green),q);
+          SetPixelBlue(image,ScaleMapToQuantum(pixel.blue),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_RGBTransformImage)
+#endif
+            proceed=SetImageProgress(image,RGBTransformImageTag,progress++,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      image_view=DestroyCacheView(image_view);
+      break;
+    }
+    case PseudoClass:
+    {
+      register size_t
+        blue,
+        green,
+        red;
+
+      /*
+        Convert PseudoClass image.
+      */
+      image_view=AcquireCacheView(image);
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        PixelInfo
+          pixel;
+
+        red=ScaleQuantumToMap(image->colormap[i].red);
+        green=ScaleQuantumToMap(image->colormap[i].green);
+        blue=ScaleQuantumToMap(image->colormap[i].blue);
+        pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x+primary_info.x;
+        pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y+primary_info.y;
+        pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z+primary_info.z;
+        image->colormap[i].red=ScaleMapToQuantum(pixel.red);
+        image->colormap[i].green=ScaleMapToQuantum(pixel.green);
+        image->colormap[i].blue=ScaleMapToQuantum(pixel.blue);
+      }
+      image_view=DestroyCacheView(image_view);
+      (void) SyncImage(image);
+      break;
+    }
+  }
+  /*
+    Relinquish resources.
+  */
+  z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
+  y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
+  x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
+  if (SetImageColorspace(image,colorspace) == MagickFalse)
+    return(MagickFalse);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e C o l o r s p a c e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageColorspace() sets the colorspace member of the Image structure.
+%
+%  The format of the SetImageColorspace method is:
+%
+%      MagickBooleanType SetImageColorspace(Image *image,
+%        const ColorspaceType colorspace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colorspace: the colorspace.
+%
+*/
+MagickExport MagickBooleanType SetImageColorspace(Image *image,
+  const ColorspaceType colorspace)
+{
+  image->colorspace=colorspace;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s f o r m I m a g e C o l o r s p a c e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformImageColorspace() transforms an image colorspace.
+%
+%  The format of the TransformImageColorspace method is:
+%
+%      MagickBooleanType TransformImageColorspace(Image *image,
+%        const ColorspaceType colorspace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colorspace: the colorspace.
+%
+*/
+MagickExport MagickBooleanType TransformImageColorspace(Image *image,
+  const ColorspaceType colorspace)
+{
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (colorspace == UndefinedColorspace)
+    {
+      if (SetImageColorspace(image,colorspace) == MagickFalse)
+        return(MagickFalse);
+      return(MagickTrue);
+    }
+  if (image->colorspace == colorspace)
+    return(MagickTrue);
+  if ((colorspace == RGBColorspace) || (colorspace == TransparentColorspace))
+    return(TransformRGBImage(image,image->colorspace));
+  status=MagickTrue;
+  if ((image->colorspace != RGBColorspace) &&
+      (image->colorspace != TransparentColorspace) &&
+      (image->colorspace != GRAYColorspace))
+    status=TransformRGBImage(image,image->colorspace);
+  if (RGBTransformImage(image,colorspace) == MagickFalse)
+    status=MagickFalse;
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     T r a n s f o r m R G B I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformRGBImage() converts the reference image from an alternate
+%  colorspace to RGB.  The transformation matrices are not the standard ones:
+%  the weights are rescaled to normalize the range of the transformed values to
+%  be [0..QuantumRange].
+%
+%  The format of the TransformRGBImage method is:
+%
+%      MagickBooleanType TransformRGBImage(Image *image,
+%        const ColorspaceType colorspace)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o colorspace: the colorspace to transform the image to.
+%
+*/
+
+static double LabF2(double alpha)
+{
+  double
+    beta;
+
+  if (alpha > (24.0/116.0))
+    return(alpha*alpha*alpha);
+  beta=(108.0/841.0)*(alpha-(16.0/116.0));
+  if (beta > 0.0)
+    return(beta);
+  return(0.0);
+}
+
+static inline void ConvertLabToXYZ(const double L,const double a,const double b,
+  double *X,double *Y,double *Z)
+{
+
+  double
+    x,
+    y,
+    z;
+
+  assert(X != (double *) NULL);
+  assert(Y != (double *) NULL);
+  assert(Z != (double *) NULL);
+  *X=0.0;
+  *Y=0.0;
+  *Z=0.0;
+  if (L <= 0.0)
+    return;
+  y=(100.0*L+16.0)/116.0;
+  x=y+255.0*0.002*(a > 0.5 ? a-1.0 : a);
+  z=y-255.0*0.005*(b > 0.5 ? b-1.0 : b);
+  *X=D50X*LabF2(x);
+  *Y=D50Y*LabF2(y);
+  *Z=D50Z*LabF2(z);
+}
+
+static inline ssize_t RoundToYCC(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return(0);
+  if (value >= 1388.0)
+    return(1388);
+  return((ssize_t) (value+0.5));
+}
+
+static inline void ConvertXYZToRGB(const double x,const double y,const double z,
+  Quantum *red,Quantum *green,Quantum *blue)
+{
+  double
+    b,
+    g,
+    r;
+
+  /*
+    Convert XYZ to RGB colorspace.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  r=3.2404542*x-1.5371385*y-0.4985314*z;
+  g=(-0.9692660*x+1.8760108*y+0.0415560*z);
+  b=0.0556434*x-0.2040259*y+1.0572252*z;
+  if (r > 0.0031308)
+    r=1.055*pow(r,1.0/2.4)-0.055;
+  else
+    r*=12.92;
+  if (g > 0.0031308)
+    g=1.055*pow(g,1.0/2.4)-0.055;
+  else
+    g*=12.92;
+  if (b > 0.0031308)
+    b=1.055*pow(b,1.0/2.4)-0.055;
+  else
+    b*=12.92;
+  *red=RoundToQuantum((MagickRealType) QuantumRange*r);
+  *green=RoundToQuantum((MagickRealType) QuantumRange*g);
+  *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
+}
+
+static inline void ConvertCMYKToRGB(PixelInfo *pixel)
+{
+  pixel->red=(MagickRealType) QuantumRange-(QuantumScale*pixel->red*
+    (QuantumRange-pixel->black)+pixel->black);
+  pixel->green=(MagickRealType) QuantumRange-(QuantumScale*pixel->green*
+    (QuantumRange-pixel->black)+pixel->black);
+  pixel->blue=(MagickRealType) QuantumRange-(QuantumScale*pixel->blue*
+    (QuantumRange-pixel->black)+pixel->black);
+}
+
+MagickExport MagickBooleanType TransformRGBImage(Image *image,
+  const ColorspaceType colorspace)
+{
+#define D50X  (0.9642)
+#define D50Y  (1.0)
+#define D50Z  (0.8249)
+#define TransformRGBImageTag  "Transform/Image"
+
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  static const float
+    YCCMap[1389] =
+    {
+      0.000000f, 0.000720f, 0.001441f, 0.002161f, 0.002882f, 0.003602f,
+      0.004323f, 0.005043f, 0.005764f, 0.006484f, 0.007205f, 0.007925f,
+      0.008646f, 0.009366f, 0.010086f, 0.010807f, 0.011527f, 0.012248f,
+      0.012968f, 0.013689f, 0.014409f, 0.015130f, 0.015850f, 0.016571f,
+      0.017291f, 0.018012f, 0.018732f, 0.019452f, 0.020173f, 0.020893f,
+      0.021614f, 0.022334f, 0.023055f, 0.023775f, 0.024496f, 0.025216f,
+      0.025937f, 0.026657f, 0.027378f, 0.028098f, 0.028818f, 0.029539f,
+      0.030259f, 0.030980f, 0.031700f, 0.032421f, 0.033141f, 0.033862f,
+      0.034582f, 0.035303f, 0.036023f, 0.036744f, 0.037464f, 0.038184f,
+      0.038905f, 0.039625f, 0.040346f, 0.041066f, 0.041787f, 0.042507f,
+      0.043228f, 0.043948f, 0.044669f, 0.045389f, 0.046110f, 0.046830f,
+      0.047550f, 0.048271f, 0.048991f, 0.049712f, 0.050432f, 0.051153f,
+      0.051873f, 0.052594f, 0.053314f, 0.054035f, 0.054755f, 0.055476f,
+      0.056196f, 0.056916f, 0.057637f, 0.058357f, 0.059078f, 0.059798f,
+      0.060519f, 0.061239f, 0.061960f, 0.062680f, 0.063401f, 0.064121f,
+      0.064842f, 0.065562f, 0.066282f, 0.067003f, 0.067723f, 0.068444f,
+      0.069164f, 0.069885f, 0.070605f, 0.071326f, 0.072046f, 0.072767f,
+      0.073487f, 0.074207f, 0.074928f, 0.075648f, 0.076369f, 0.077089f,
+      0.077810f, 0.078530f, 0.079251f, 0.079971f, 0.080692f, 0.081412f,
+      0.082133f, 0.082853f, 0.083573f, 0.084294f, 0.085014f, 0.085735f,
+      0.086455f, 0.087176f, 0.087896f, 0.088617f, 0.089337f, 0.090058f,
+      0.090778f, 0.091499f, 0.092219f, 0.092939f, 0.093660f, 0.094380f,
+      0.095101f, 0.095821f, 0.096542f, 0.097262f, 0.097983f, 0.098703f,
+      0.099424f, 0.100144f, 0.100865f, 0.101585f, 0.102305f, 0.103026f,
+      0.103746f, 0.104467f, 0.105187f, 0.105908f, 0.106628f, 0.107349f,
+      0.108069f, 0.108790f, 0.109510f, 0.110231f, 0.110951f, 0.111671f,
+      0.112392f, 0.113112f, 0.113833f, 0.114553f, 0.115274f, 0.115994f,
+      0.116715f, 0.117435f, 0.118156f, 0.118876f, 0.119597f, 0.120317f,
+      0.121037f, 0.121758f, 0.122478f, 0.123199f, 0.123919f, 0.124640f,
+      0.125360f, 0.126081f, 0.126801f, 0.127522f, 0.128242f, 0.128963f,
+      0.129683f, 0.130403f, 0.131124f, 0.131844f, 0.132565f, 0.133285f,
+      0.134006f, 0.134726f, 0.135447f, 0.136167f, 0.136888f, 0.137608f,
+      0.138329f, 0.139049f, 0.139769f, 0.140490f, 0.141210f, 0.141931f,
+      0.142651f, 0.143372f, 0.144092f, 0.144813f, 0.145533f, 0.146254f,
+      0.146974f, 0.147695f, 0.148415f, 0.149135f, 0.149856f, 0.150576f,
+      0.151297f, 0.152017f, 0.152738f, 0.153458f, 0.154179f, 0.154899f,
+      0.155620f, 0.156340f, 0.157061f, 0.157781f, 0.158501f, 0.159222f,
+      0.159942f, 0.160663f, 0.161383f, 0.162104f, 0.162824f, 0.163545f,
+      0.164265f, 0.164986f, 0.165706f, 0.166427f, 0.167147f, 0.167867f,
+      0.168588f, 0.169308f, 0.170029f, 0.170749f, 0.171470f, 0.172190f,
+      0.172911f, 0.173631f, 0.174352f, 0.175072f, 0.175793f, 0.176513f,
+      0.177233f, 0.177954f, 0.178674f, 0.179395f, 0.180115f, 0.180836f,
+      0.181556f, 0.182277f, 0.182997f, 0.183718f, 0.184438f, 0.185159f,
+      0.185879f, 0.186599f, 0.187320f, 0.188040f, 0.188761f, 0.189481f,
+      0.190202f, 0.190922f, 0.191643f, 0.192363f, 0.193084f, 0.193804f,
+      0.194524f, 0.195245f, 0.195965f, 0.196686f, 0.197406f, 0.198127f,
+      0.198847f, 0.199568f, 0.200288f, 0.201009f, 0.201729f, 0.202450f,
+      0.203170f, 0.203890f, 0.204611f, 0.205331f, 0.206052f, 0.206772f,
+      0.207493f, 0.208213f, 0.208934f, 0.209654f, 0.210375f, 0.211095f,
+      0.211816f, 0.212536f, 0.213256f, 0.213977f, 0.214697f, 0.215418f,
+      0.216138f, 0.216859f, 0.217579f, 0.218300f, 0.219020f, 0.219741f,
+      0.220461f, 0.221182f, 0.221902f, 0.222622f, 0.223343f, 0.224063f,
+      0.224784f, 0.225504f, 0.226225f, 0.226945f, 0.227666f, 0.228386f,
+      0.229107f, 0.229827f, 0.230548f, 0.231268f, 0.231988f, 0.232709f,
+      0.233429f, 0.234150f, 0.234870f, 0.235591f, 0.236311f, 0.237032f,
+      0.237752f, 0.238473f, 0.239193f, 0.239914f, 0.240634f, 0.241354f,
+      0.242075f, 0.242795f, 0.243516f, 0.244236f, 0.244957f, 0.245677f,
+      0.246398f, 0.247118f, 0.247839f, 0.248559f, 0.249280f, 0.250000f,
+      0.250720f, 0.251441f, 0.252161f, 0.252882f, 0.253602f, 0.254323f,
+      0.255043f, 0.255764f, 0.256484f, 0.257205f, 0.257925f, 0.258646f,
+      0.259366f, 0.260086f, 0.260807f, 0.261527f, 0.262248f, 0.262968f,
+      0.263689f, 0.264409f, 0.265130f, 0.265850f, 0.266571f, 0.267291f,
+      0.268012f, 0.268732f, 0.269452f, 0.270173f, 0.270893f, 0.271614f,
+      0.272334f, 0.273055f, 0.273775f, 0.274496f, 0.275216f, 0.275937f,
+      0.276657f, 0.277378f, 0.278098f, 0.278818f, 0.279539f, 0.280259f,
+      0.280980f, 0.281700f, 0.282421f, 0.283141f, 0.283862f, 0.284582f,
+      0.285303f, 0.286023f, 0.286744f, 0.287464f, 0.288184f, 0.288905f,
+      0.289625f, 0.290346f, 0.291066f, 0.291787f, 0.292507f, 0.293228f,
+      0.293948f, 0.294669f, 0.295389f, 0.296109f, 0.296830f, 0.297550f,
+      0.298271f, 0.298991f, 0.299712f, 0.300432f, 0.301153f, 0.301873f,
+      0.302594f, 0.303314f, 0.304035f, 0.304755f, 0.305476f, 0.306196f,
+      0.306916f, 0.307637f, 0.308357f, 0.309078f, 0.309798f, 0.310519f,
+      0.311239f, 0.311960f, 0.312680f, 0.313401f, 0.314121f, 0.314842f,
+      0.315562f, 0.316282f, 0.317003f, 0.317723f, 0.318444f, 0.319164f,
+      0.319885f, 0.320605f, 0.321326f, 0.322046f, 0.322767f, 0.323487f,
+      0.324207f, 0.324928f, 0.325648f, 0.326369f, 0.327089f, 0.327810f,
+      0.328530f, 0.329251f, 0.329971f, 0.330692f, 0.331412f, 0.332133f,
+      0.332853f, 0.333573f, 0.334294f, 0.335014f, 0.335735f, 0.336455f,
+      0.337176f, 0.337896f, 0.338617f, 0.339337f, 0.340058f, 0.340778f,
+      0.341499f, 0.342219f, 0.342939f, 0.343660f, 0.344380f, 0.345101f,
+      0.345821f, 0.346542f, 0.347262f, 0.347983f, 0.348703f, 0.349424f,
+      0.350144f, 0.350865f, 0.351585f, 0.352305f, 0.353026f, 0.353746f,
+      0.354467f, 0.355187f, 0.355908f, 0.356628f, 0.357349f, 0.358069f,
+      0.358790f, 0.359510f, 0.360231f, 0.360951f, 0.361671f, 0.362392f,
+      0.363112f, 0.363833f, 0.364553f, 0.365274f, 0.365994f, 0.366715f,
+      0.367435f, 0.368156f, 0.368876f, 0.369597f, 0.370317f, 0.371037f,
+      0.371758f, 0.372478f, 0.373199f, 0.373919f, 0.374640f, 0.375360f,
+      0.376081f, 0.376801f, 0.377522f, 0.378242f, 0.378963f, 0.379683f,
+      0.380403f, 0.381124f, 0.381844f, 0.382565f, 0.383285f, 0.384006f,
+      0.384726f, 0.385447f, 0.386167f, 0.386888f, 0.387608f, 0.388329f,
+      0.389049f, 0.389769f, 0.390490f, 0.391210f, 0.391931f, 0.392651f,
+      0.393372f, 0.394092f, 0.394813f, 0.395533f, 0.396254f, 0.396974f,
+      0.397695f, 0.398415f, 0.399135f, 0.399856f, 0.400576f, 0.401297f,
+      0.402017f, 0.402738f, 0.403458f, 0.404179f, 0.404899f, 0.405620f,
+      0.406340f, 0.407061f, 0.407781f, 0.408501f, 0.409222f, 0.409942f,
+      0.410663f, 0.411383f, 0.412104f, 0.412824f, 0.413545f, 0.414265f,
+      0.414986f, 0.415706f, 0.416427f, 0.417147f, 0.417867f, 0.418588f,
+      0.419308f, 0.420029f, 0.420749f, 0.421470f, 0.422190f, 0.422911f,
+      0.423631f, 0.424352f, 0.425072f, 0.425793f, 0.426513f, 0.427233f,
+      0.427954f, 0.428674f, 0.429395f, 0.430115f, 0.430836f, 0.431556f,
+      0.432277f, 0.432997f, 0.433718f, 0.434438f, 0.435158f, 0.435879f,
+      0.436599f, 0.437320f, 0.438040f, 0.438761f, 0.439481f, 0.440202f,
+      0.440922f, 0.441643f, 0.442363f, 0.443084f, 0.443804f, 0.444524f,
+      0.445245f, 0.445965f, 0.446686f, 0.447406f, 0.448127f, 0.448847f,
+      0.449568f, 0.450288f, 0.451009f, 0.451729f, 0.452450f, 0.453170f,
+      0.453891f, 0.454611f, 0.455331f, 0.456052f, 0.456772f, 0.457493f,
+      0.458213f, 0.458934f, 0.459654f, 0.460375f, 0.461095f, 0.461816f,
+      0.462536f, 0.463256f, 0.463977f, 0.464697f, 0.465418f, 0.466138f,
+      0.466859f, 0.467579f, 0.468300f, 0.469020f, 0.469741f, 0.470461f,
+      0.471182f, 0.471902f, 0.472622f, 0.473343f, 0.474063f, 0.474784f,
+      0.475504f, 0.476225f, 0.476945f, 0.477666f, 0.478386f, 0.479107f,
+      0.479827f, 0.480548f, 0.481268f, 0.481988f, 0.482709f, 0.483429f,
+      0.484150f, 0.484870f, 0.485591f, 0.486311f, 0.487032f, 0.487752f,
+      0.488473f, 0.489193f, 0.489914f, 0.490634f, 0.491354f, 0.492075f,
+      0.492795f, 0.493516f, 0.494236f, 0.494957f, 0.495677f, 0.496398f,
+      0.497118f, 0.497839f, 0.498559f, 0.499280f, 0.500000f, 0.500720f,
+      0.501441f, 0.502161f, 0.502882f, 0.503602f, 0.504323f, 0.505043f,
+      0.505764f, 0.506484f, 0.507205f, 0.507925f, 0.508646f, 0.509366f,
+      0.510086f, 0.510807f, 0.511527f, 0.512248f, 0.512968f, 0.513689f,
+      0.514409f, 0.515130f, 0.515850f, 0.516571f, 0.517291f, 0.518012f,
+      0.518732f, 0.519452f, 0.520173f, 0.520893f, 0.521614f, 0.522334f,
+      0.523055f, 0.523775f, 0.524496f, 0.525216f, 0.525937f, 0.526657f,
+      0.527378f, 0.528098f, 0.528818f, 0.529539f, 0.530259f, 0.530980f,
+      0.531700f, 0.532421f, 0.533141f, 0.533862f, 0.534582f, 0.535303f,
+      0.536023f, 0.536744f, 0.537464f, 0.538184f, 0.538905f, 0.539625f,
+      0.540346f, 0.541066f, 0.541787f, 0.542507f, 0.543228f, 0.543948f,
+      0.544669f, 0.545389f, 0.546109f, 0.546830f, 0.547550f, 0.548271f,
+      0.548991f, 0.549712f, 0.550432f, 0.551153f, 0.551873f, 0.552594f,
+      0.553314f, 0.554035f, 0.554755f, 0.555476f, 0.556196f, 0.556916f,
+      0.557637f, 0.558357f, 0.559078f, 0.559798f, 0.560519f, 0.561239f,
+      0.561960f, 0.562680f, 0.563401f, 0.564121f, 0.564842f, 0.565562f,
+      0.566282f, 0.567003f, 0.567723f, 0.568444f, 0.569164f, 0.569885f,
+      0.570605f, 0.571326f, 0.572046f, 0.572767f, 0.573487f, 0.574207f,
+      0.574928f, 0.575648f, 0.576369f, 0.577089f, 0.577810f, 0.578530f,
+      0.579251f, 0.579971f, 0.580692f, 0.581412f, 0.582133f, 0.582853f,
+      0.583573f, 0.584294f, 0.585014f, 0.585735f, 0.586455f, 0.587176f,
+      0.587896f, 0.588617f, 0.589337f, 0.590058f, 0.590778f, 0.591499f,
+      0.592219f, 0.592939f, 0.593660f, 0.594380f, 0.595101f, 0.595821f,
+      0.596542f, 0.597262f, 0.597983f, 0.598703f, 0.599424f, 0.600144f,
+      0.600865f, 0.601585f, 0.602305f, 0.603026f, 0.603746f, 0.604467f,
+      0.605187f, 0.605908f, 0.606628f, 0.607349f, 0.608069f, 0.608790f,
+      0.609510f, 0.610231f, 0.610951f, 0.611671f, 0.612392f, 0.613112f,
+      0.613833f, 0.614553f, 0.615274f, 0.615994f, 0.616715f, 0.617435f,
+      0.618156f, 0.618876f, 0.619597f, 0.620317f, 0.621037f, 0.621758f,
+      0.622478f, 0.623199f, 0.623919f, 0.624640f, 0.625360f, 0.626081f,
+      0.626801f, 0.627522f, 0.628242f, 0.628963f, 0.629683f, 0.630403f,
+      0.631124f, 0.631844f, 0.632565f, 0.633285f, 0.634006f, 0.634726f,
+      0.635447f, 0.636167f, 0.636888f, 0.637608f, 0.638329f, 0.639049f,
+      0.639769f, 0.640490f, 0.641210f, 0.641931f, 0.642651f, 0.643372f,
+      0.644092f, 0.644813f, 0.645533f, 0.646254f, 0.646974f, 0.647695f,
+      0.648415f, 0.649135f, 0.649856f, 0.650576f, 0.651297f, 0.652017f,
+      0.652738f, 0.653458f, 0.654179f, 0.654899f, 0.655620f, 0.656340f,
+      0.657061f, 0.657781f, 0.658501f, 0.659222f, 0.659942f, 0.660663f,
+      0.661383f, 0.662104f, 0.662824f, 0.663545f, 0.664265f, 0.664986f,
+      0.665706f, 0.666427f, 0.667147f, 0.667867f, 0.668588f, 0.669308f,
+      0.670029f, 0.670749f, 0.671470f, 0.672190f, 0.672911f, 0.673631f,
+      0.674352f, 0.675072f, 0.675793f, 0.676513f, 0.677233f, 0.677954f,
+      0.678674f, 0.679395f, 0.680115f, 0.680836f, 0.681556f, 0.682277f,
+      0.682997f, 0.683718f, 0.684438f, 0.685158f, 0.685879f, 0.686599f,
+      0.687320f, 0.688040f, 0.688761f, 0.689481f, 0.690202f, 0.690922f,
+      0.691643f, 0.692363f, 0.693084f, 0.693804f, 0.694524f, 0.695245f,
+      0.695965f, 0.696686f, 0.697406f, 0.698127f, 0.698847f, 0.699568f,
+      0.700288f, 0.701009f, 0.701729f, 0.702450f, 0.703170f, 0.703891f,
+      0.704611f, 0.705331f, 0.706052f, 0.706772f, 0.707493f, 0.708213f,
+      0.708934f, 0.709654f, 0.710375f, 0.711095f, 0.711816f, 0.712536f,
+      0.713256f, 0.713977f, 0.714697f, 0.715418f, 0.716138f, 0.716859f,
+      0.717579f, 0.718300f, 0.719020f, 0.719741f, 0.720461f, 0.721182f,
+      0.721902f, 0.722622f, 0.723343f, 0.724063f, 0.724784f, 0.725504f,
+      0.726225f, 0.726945f, 0.727666f, 0.728386f, 0.729107f, 0.729827f,
+      0.730548f, 0.731268f, 0.731988f, 0.732709f, 0.733429f, 0.734150f,
+      0.734870f, 0.735591f, 0.736311f, 0.737032f, 0.737752f, 0.738473f,
+      0.739193f, 0.739914f, 0.740634f, 0.741354f, 0.742075f, 0.742795f,
+      0.743516f, 0.744236f, 0.744957f, 0.745677f, 0.746398f, 0.747118f,
+      0.747839f, 0.748559f, 0.749280f, 0.750000f, 0.750720f, 0.751441f,
+      0.752161f, 0.752882f, 0.753602f, 0.754323f, 0.755043f, 0.755764f,
+      0.756484f, 0.757205f, 0.757925f, 0.758646f, 0.759366f, 0.760086f,
+      0.760807f, 0.761527f, 0.762248f, 0.762968f, 0.763689f, 0.764409f,
+      0.765130f, 0.765850f, 0.766571f, 0.767291f, 0.768012f, 0.768732f,
+      0.769452f, 0.770173f, 0.770893f, 0.771614f, 0.772334f, 0.773055f,
+      0.773775f, 0.774496f, 0.775216f, 0.775937f, 0.776657f, 0.777378f,
+      0.778098f, 0.778818f, 0.779539f, 0.780259f, 0.780980f, 0.781700f,
+      0.782421f, 0.783141f, 0.783862f, 0.784582f, 0.785303f, 0.786023f,
+      0.786744f, 0.787464f, 0.788184f, 0.788905f, 0.789625f, 0.790346f,
+      0.791066f, 0.791787f, 0.792507f, 0.793228f, 0.793948f, 0.794669f,
+      0.795389f, 0.796109f, 0.796830f, 0.797550f, 0.798271f, 0.798991f,
+      0.799712f, 0.800432f, 0.801153f, 0.801873f, 0.802594f, 0.803314f,
+      0.804035f, 0.804755f, 0.805476f, 0.806196f, 0.806916f, 0.807637f,
+      0.808357f, 0.809078f, 0.809798f, 0.810519f, 0.811239f, 0.811960f,
+      0.812680f, 0.813401f, 0.814121f, 0.814842f, 0.815562f, 0.816282f,
+      0.817003f, 0.817723f, 0.818444f, 0.819164f, 0.819885f, 0.820605f,
+      0.821326f, 0.822046f, 0.822767f, 0.823487f, 0.824207f, 0.824928f,
+      0.825648f, 0.826369f, 0.827089f, 0.827810f, 0.828530f, 0.829251f,
+      0.829971f, 0.830692f, 0.831412f, 0.832133f, 0.832853f, 0.833573f,
+      0.834294f, 0.835014f, 0.835735f, 0.836455f, 0.837176f, 0.837896f,
+      0.838617f, 0.839337f, 0.840058f, 0.840778f, 0.841499f, 0.842219f,
+      0.842939f, 0.843660f, 0.844380f, 0.845101f, 0.845821f, 0.846542f,
+      0.847262f, 0.847983f, 0.848703f, 0.849424f, 0.850144f, 0.850865f,
+      0.851585f, 0.852305f, 0.853026f, 0.853746f, 0.854467f, 0.855187f,
+      0.855908f, 0.856628f, 0.857349f, 0.858069f, 0.858790f, 0.859510f,
+      0.860231f, 0.860951f, 0.861671f, 0.862392f, 0.863112f, 0.863833f,
+      0.864553f, 0.865274f, 0.865994f, 0.866715f, 0.867435f, 0.868156f,
+      0.868876f, 0.869597f, 0.870317f, 0.871037f, 0.871758f, 0.872478f,
+      0.873199f, 0.873919f, 0.874640f, 0.875360f, 0.876081f, 0.876801f,
+      0.877522f, 0.878242f, 0.878963f, 0.879683f, 0.880403f, 0.881124f,
+      0.881844f, 0.882565f, 0.883285f, 0.884006f, 0.884726f, 0.885447f,
+      0.886167f, 0.886888f, 0.887608f, 0.888329f, 0.889049f, 0.889769f,
+      0.890490f, 0.891210f, 0.891931f, 0.892651f, 0.893372f, 0.894092f,
+      0.894813f, 0.895533f, 0.896254f, 0.896974f, 0.897695f, 0.898415f,
+      0.899135f, 0.899856f, 0.900576f, 0.901297f, 0.902017f, 0.902738f,
+      0.903458f, 0.904179f, 0.904899f, 0.905620f, 0.906340f, 0.907061f,
+      0.907781f, 0.908501f, 0.909222f, 0.909942f, 0.910663f, 0.911383f,
+      0.912104f, 0.912824f, 0.913545f, 0.914265f, 0.914986f, 0.915706f,
+      0.916427f, 0.917147f, 0.917867f, 0.918588f, 0.919308f, 0.920029f,
+      0.920749f, 0.921470f, 0.922190f, 0.922911f, 0.923631f, 0.924352f,
+      0.925072f, 0.925793f, 0.926513f, 0.927233f, 0.927954f, 0.928674f,
+      0.929395f, 0.930115f, 0.930836f, 0.931556f, 0.932277f, 0.932997f,
+      0.933718f, 0.934438f, 0.935158f, 0.935879f, 0.936599f, 0.937320f,
+      0.938040f, 0.938761f, 0.939481f, 0.940202f, 0.940922f, 0.941643f,
+      0.942363f, 0.943084f, 0.943804f, 0.944524f, 0.945245f, 0.945965f,
+      0.946686f, 0.947406f, 0.948127f, 0.948847f, 0.949568f, 0.950288f,
+      0.951009f, 0.951729f, 0.952450f, 0.953170f, 0.953891f, 0.954611f,
+      0.955331f, 0.956052f, 0.956772f, 0.957493f, 0.958213f, 0.958934f,
+      0.959654f, 0.960375f, 0.961095f, 0.961816f, 0.962536f, 0.963256f,
+      0.963977f, 0.964697f, 0.965418f, 0.966138f, 0.966859f, 0.967579f,
+      0.968300f, 0.969020f, 0.969741f, 0.970461f, 0.971182f, 0.971902f,
+      0.972622f, 0.973343f, 0.974063f, 0.974784f, 0.975504f, 0.976225f,
+      0.976945f, 0.977666f, 0.978386f, 0.979107f, 0.979827f, 0.980548f,
+      0.981268f, 0.981988f, 0.982709f, 0.983429f, 0.984150f, 0.984870f,
+      0.985591f, 0.986311f, 0.987032f, 0.987752f, 0.988473f, 0.989193f,
+      0.989914f, 0.990634f, 0.991354f, 0.992075f, 0.992795f, 0.993516f,
+      0.994236f, 0.994957f, 0.995677f, 0.996398f, 0.997118f, 0.997839f,
+      0.998559f, 0.999280f, 1.000000f
+    };
+#endif
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  TransformPacket
+    *y_map,
+    *x_map,
+    *z_map;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  switch (colorspace)
+  {
+    case GRAYColorspace:
+    case Rec601LumaColorspace:
+    case Rec709LumaColorspace:
+    case RGBColorspace:
+    case TransparentColorspace:
+    case UndefinedColorspace:
+      return(MagickTrue);
+    default:
+      break;
+  }
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  switch (colorspace)
+  {
+    case CMYColorspace:
+    {
+      /*
+        Transform image from CMY to RGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,ClampToQuantum((MagickRealType) (QuantumRange-
+            GetPixelRed(image,q))),q);
+          SetPixelGreen(image,ClampToQuantum((MagickRealType) (QuantumRange-
+            GetPixelGreen(image,q))),q);
+          SetPixelBlue(image,ClampToQuantum((MagickRealType) (QuantumRange-
+            GetPixelBlue(image,q))),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    case CMYKColorspace:
+    {
+      PixelInfo
+        zero;
+
+      /*
+        Transform image from CMYK to RGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      GetPixelInfo(image,&zero);
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        PixelInfo
+          pixel;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        pixel=zero;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelInfo(image,q,&pixel);
+          ConvertCMYKToRGB(&pixel);
+          SetPixelPixelInfo(image,&pixel,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    case HSBColorspace:
+    {
+      /*
+        Transform image from HSB to RGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          brightness,
+          hue,
+          saturation;
+
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          Quantum
+            blue,
+            green,
+            red;
+
+          hue=(double) (QuantumScale*GetPixelRed(image,q));
+          saturation=(double) (QuantumScale*GetPixelGreen(image,q));
+          brightness=(double) (QuantumScale*GetPixelBlue(image,q));
+          ConvertHSBToRGB(hue,saturation,brightness,&red,&green,&blue);
+          SetPixelRed(image,red,q);
+          SetPixelGreen(image,green,q);
+          SetPixelBlue(image,blue,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    case HSLColorspace:
+    {
+      /*
+        Transform image from HSL to RGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          hue,
+          lightness,
+          saturation;
+
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          Quantum
+            blue,
+            green,
+            red;
+
+          hue=(double) (QuantumScale*GetPixelRed(image,q));
+          saturation=(double) (QuantumScale*GetPixelGreen(image,q));
+          lightness=(double) (QuantumScale*GetPixelBlue(image,q));
+          ConvertHSLToRGB(hue,saturation,lightness,&red,&green,&blue);
+          SetPixelRed(image,red,q);
+          SetPixelGreen(image,green,q);
+          SetPixelBlue(image,blue,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    case HWBColorspace:
+    {
+      /*
+        Transform image from HWB to RGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          blackness,
+          hue,
+          whiteness;
+
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          Quantum
+            blue,
+            green,
+            red;
+
+          hue=(double) (QuantumScale*GetPixelRed(image,q));
+          whiteness=(double) (QuantumScale*GetPixelGreen(image,q));
+          blackness=(double) (QuantumScale*GetPixelBlue(image,q));
+          ConvertHWBToRGB(hue,whiteness,blackness,&red,&green,&blue);
+          SetPixelRed(image,red,q);
+          SetPixelGreen(image,green,q);
+          SetPixelBlue(image,blue,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    case LabColorspace:
+    {
+      /*
+        Transform image from Lab to RGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        double
+          a,
+          b,
+          L,
+          X,
+          Y,
+          Z;
+
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        X=0.0;
+        Y=0.0;
+        Z=0.0;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          Quantum
+            blue,
+            green,
+            red;
+
+          L=QuantumScale*GetPixelRed(image,q);
+          a=QuantumScale*GetPixelGreen(image,q);
+          b=QuantumScale*GetPixelBlue(image,q);
+          ConvertLabToXYZ(L,a,b,&X,&Y,&Z);
+          ConvertXYZToRGB(X,Y,Z,&red,&green,&blue);
+          SetPixelRed(image,red,q);
+          SetPixelGreen(image,green,q);
+          SetPixelBlue(image,blue,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    case LogColorspace:
+    {
+      const char
+        *value;
+
+      double
+        black,
+        density,
+        film_gamma,
+        gamma,
+        reference_black,
+        reference_white;
+
+      Quantum
+        *logmap;
+
+      /*
+        Transform Log to RGB colorspace.
+      */
+      density=DisplayGamma;
+      gamma=DisplayGamma;
+      value=GetImageProperty(image,"gamma");
+      if (value != (const char *) NULL)
+        gamma=1.0/InterpretLocaleValue(value,(char **) NULL) != 0.0 ?
+          InterpretLocaleValue(value,(char **) NULL) : 1.0;
+      film_gamma=FilmGamma;
+      value=GetImageProperty(image,"film-gamma");
+      if (value != (const char *) NULL)
+        film_gamma=InterpretLocaleValue(value,(char **) NULL);
+      reference_black=ReferenceBlack;
+      value=GetImageProperty(image,"reference-black");
+      if (value != (const char *) NULL)
+        reference_black=InterpretLocaleValue(value,(char **) NULL);
+      reference_white=ReferenceWhite;
+      value=GetImageProperty(image,"reference-white");
+      if (value != (const char *) NULL)
+        reference_white=InterpretLocaleValue(value,(char **) NULL);
+      logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+        sizeof(*logmap));
+      if (logmap == (Quantum *) NULL)
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename);
+      black=pow(10.0,(reference_black-reference_white)*(gamma/density)*
+        0.002/film_gamma);
+      for (i=0; i <= (ssize_t) (reference_black*MaxMap/1024.0); i++)
+        logmap[i]=(Quantum) 0;
+      for ( ; i < (ssize_t) (reference_white*MaxMap/1024.0); i++)
+        logmap[i]=ClampToQuantum((MagickRealType) QuantumRange/(1.0-black)*
+          (pow(10.0,(1024.0*i/MaxMap-reference_white)*
+          (gamma/density)*0.002/film_gamma)-black));
+      for ( ; i <= (ssize_t) MaxMap; i++)
+        logmap[i]=(Quantum) QuantumRange;
+      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+        return(MagickFalse);
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=(ssize_t) image->columns; x != 0; x--)
+        {
+          SetPixelRed(image,logmap[ScaleQuantumToMap(
+            GetPixelRed(image,q))],q);
+          SetPixelGreen(image,logmap[ScaleQuantumToMap(
+            GetPixelGreen(image,q))],q);
+          SetPixelBlue(image,logmap[ScaleQuantumToMap(
+            GetPixelBlue(image,q))],q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      logmap=(Quantum *) RelinquishMagickMemory(logmap);
+      if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
+    default:
+      break;
+  }
+  /*
+    Allocate the tables.
+  */
+  x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+    sizeof(*x_map));
+  y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+    sizeof(*y_map));
+  z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
+    sizeof(*z_map));
+  if ((x_map == (TransformPacket *) NULL) ||
+      (y_map == (TransformPacket *) NULL) ||
+      (z_map == (TransformPacket *) NULL))
+    {
+      if (z_map != (TransformPacket *) NULL)
+        z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
+      if (y_map != (TransformPacket *) NULL)
+        y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
+      if (x_map != (TransformPacket *) NULL)
+        x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  switch (colorspace)
+  {
+    case OHTAColorspace:
+    {
+      /*
+        Initialize OHTA tables:
+
+          R = I1+1.00000*I2-0.66668*I3
+          G = I1+0.00000*I2+1.33333*I3
+          B = I1-1.00000*I2-0.66668*I3
+
+        I and Q, normally -0.5 through 0.5, must be normalized to the range 0
+        through QuantumRange.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=(MagickRealType) i;
+        y_map[i].x=0.500000f*(2.000000*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].x=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].y=(MagickRealType) i;
+        y_map[i].y=0.000000f;
+        z_map[i].y=0.666665f*(2.000000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].z=(MagickRealType) i;
+        y_map[i].z=(-0.500000f)*(2.000000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].z=(-0.333340f)*(2.000000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+      }
+      break;
+    }
+    case Rec601YCbCrColorspace:
+    case YCbCrColorspace:
+    {
+      /*
+        Initialize YCbCr tables:
+
+          R = Y            +1.402000*Cr
+          G = Y-0.344136*Cb-0.714136*Cr
+          B = Y+1.772000*Cb
+
+        Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
+        through QuantumRange.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=(MagickRealType) i;
+        y_map[i].x=0.000000f;
+        z_map[i].x=(1.402000f*0.500000f)*(2.000000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        x_map[i].y=(MagickRealType) i;
+        y_map[i].y=(-0.344136f*0.500000f)*(2.000000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        z_map[i].y=(-0.714136f*0.500000f)*(2.000000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        x_map[i].z=(MagickRealType) i;
+        y_map[i].z=(1.772000f*0.500000f)*(2.000000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        z_map[i].z=0.000000f;
+      }
+      break;
+    }
+    case Rec709YCbCrColorspace:
+    {
+      /*
+        Initialize YCbCr tables:
+
+          R = Y            +1.574800*Cr
+          G = Y-0.187324*Cb-0.468124*Cr
+          B = Y+1.855600*Cb
+
+        Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
+        through QuantumRange.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=(MagickRealType) i;
+        y_map[i].x=0.000000f;
+        z_map[i].x=(1.574800f*0.50000f)*(2.00000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        x_map[i].y=(MagickRealType) i;
+        y_map[i].y=(-0.187324f*0.50000f)*(2.00000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        z_map[i].y=(-0.468124f*0.50000f)*(2.00000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        x_map[i].z=(MagickRealType) i;
+        y_map[i].z=(1.855600f*0.50000f)*(2.00000f*(MagickRealType) i-
+          (MagickRealType) MaxMap);
+        z_map[i].z=0.00000f;
+      }
+      break;
+    }
+    case sRGBColorspace:
+    {
+      /*
+        Nonlinear sRGB to linear RGB.
+
+          R = 1.0*R+0.0*G+0.0*B
+          G = 0.0*R+1.0*G+0.0*B
+          B = 0.0*R+0.0*G+1.0*B
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=1.0f*(MagickRealType) i;
+        y_map[i].x=0.0f*(MagickRealType) i;
+        z_map[i].x=0.0f*(MagickRealType) i;
+        x_map[i].y=0.0f*(MagickRealType) i;
+        y_map[i].y=1.0f*(MagickRealType) i;
+        z_map[i].y=0.0f*(MagickRealType) i;
+        x_map[i].z=0.0f*(MagickRealType) i;
+        y_map[i].z=0.0f*(MagickRealType) i;
+        z_map[i].z=1.0f*(MagickRealType) i;
+      }
+      break;
+    }
+    case XYZColorspace:
+    {
+      /*
+        Initialize CIE XYZ tables (ITU R-709 RGB):
+
+          R =  3.2404542*X-1.5371385*Y-0.4985314*Z
+          G = -0.9692660*X+1.8760108*Y+0.0415560*Z
+          B =  0.0556434*X-0.2040259*Y+1.057225*Z
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=3.2404542f*(MagickRealType) i;
+        x_map[i].y=(-0.9692660f)*(MagickRealType) i;
+        x_map[i].z=0.0556434f*(MagickRealType) i;
+        y_map[i].x=(-1.5371385f)*(MagickRealType) i;
+        y_map[i].y=1.8760108f*(MagickRealType) i;
+        y_map[i].z=(-0.2040259f)*(MagickRealType) i;
+        z_map[i].x=(-0.4985314f)*(MagickRealType) i;
+        z_map[i].y=0.0415560f*(MagickRealType) i;
+        z_map[i].z=1.0572252f*(MagickRealType) i;
+      }
+      break;
+    }
+    case YCCColorspace:
+    {
+      /*
+        Initialize YCC tables:
+
+          R = Y            +1.340762*C2
+          G = Y-0.317038*C1-0.682243*C2
+          B = Y+1.632639*C1
+
+        YCC is scaled by 1.3584.  C1 zero is 156 and C2 is at 137.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=1.3584000f*(MagickRealType) i;
+        y_map[i].x=0.0000000f;
+        z_map[i].x=1.8215000f*((MagickRealType) i-(MagickRealType)
+          ScaleQuantumToMap(ScaleCharToQuantum(137)));
+        x_map[i].y=1.3584000f*(MagickRealType) i;
+        y_map[i].y=(-0.4302726f)*((MagickRealType) i-(MagickRealType)
+          ScaleQuantumToMap(ScaleCharToQuantum(156)));
+        z_map[i].y=(-0.9271435f)*((MagickRealType) i-(MagickRealType)
+          ScaleQuantumToMap(ScaleCharToQuantum(137)));
+        x_map[i].z=1.3584000f*(MagickRealType) i;
+        y_map[i].z=2.2179000f*((MagickRealType) i-(MagickRealType)
+          ScaleQuantumToMap(ScaleCharToQuantum(156)));
+        z_map[i].z=0.0000000f;
+      }
+      break;
+    }
+    case YIQColorspace:
+    {
+      /*
+        Initialize YIQ tables:
+
+          R = Y+0.95620*I+0.62140*Q
+          G = Y-0.27270*I-0.64680*Q
+          B = Y-1.10370*I+1.70060*Q
+
+        I and Q, normally -0.5 through 0.5, must be normalized to the range 0
+        through QuantumRange.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=(MagickRealType) i;
+        y_map[i].x=0.47810f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].x=0.31070f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].y=(MagickRealType) i;
+        y_map[i].y=(-0.13635f)*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].y=(-0.32340f)*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].z=(MagickRealType) i;
+        y_map[i].z=(-0.55185f)*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].z=0.85030f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+      }
+      break;
+    }
+    case YPbPrColorspace:
+    {
+      /*
+        Initialize YPbPr tables:
+
+          R = Y            +1.402000*C2
+          G = Y-0.344136*C1+0.714136*C2
+          B = Y+1.772000*C1
+
+        Pb and Pr, normally -0.5 through 0.5, must be normalized to the range 0
+        through QuantumRange.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=(MagickRealType) i;
+        y_map[i].x=0.000000f;
+        z_map[i].x=0.701000f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].y=(MagickRealType) i;
+        y_map[i].y=(-0.172068f)*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].y=0.357068f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].z=(MagickRealType) i;
+        y_map[i].z=0.88600f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].z=0.00000f;
+      }
+      break;
+    }
+    case YUVColorspace:
+    default:
+    {
+      /*
+        Initialize YUV tables:
+
+          R = Y          +1.13980*V
+          G = Y-0.39380*U-0.58050*V
+          B = Y+2.02790*U
+
+        U and V, normally -0.5 through 0.5, must be normalized to the range 0
+        through QuantumRange.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        x_map[i].x=(MagickRealType) i;
+        y_map[i].x=0.00000f;
+        z_map[i].x=0.56990f*(2.0000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].y=(MagickRealType) i;
+        y_map[i].y=(-0.19690f)*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].y=(-0.29025f)*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        x_map[i].z=(MagickRealType) i;
+        y_map[i].z=1.01395f*(2.00000f*(MagickRealType) i-(MagickRealType)
+          MaxMap);
+        z_map[i].z=0.00000f;
+      }
+      break;
+    }
+  }
+  /*
+    Convert to RGB.
+  */
+  switch (image->storage_class)
+  {
+    case DirectClass:
+    default:
+    {
+      /*
+        Convert DirectClass image.
+      */
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        PixelInfo
+          pixel;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          register size_t
+            blue,
+            green,
+            red;
+
+          red=ScaleQuantumToMap(GetPixelRed(image,q));
+          green=ScaleQuantumToMap(GetPixelGreen(image,q));
+          blue=ScaleQuantumToMap(GetPixelBlue(image,q));
+          pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
+          pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
+          pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
+          switch (colorspace)
+          {
+            case YCCColorspace:
+            {
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+              pixel.red=QuantumRange*YCCMap[RoundToYCC(1024.0*QuantumScale*
+                pixel.red)];
+              pixel.green=QuantumRange*YCCMap[RoundToYCC(1024.0*QuantumScale*
+                pixel.green)];
+              pixel.blue=QuantumRange*YCCMap[RoundToYCC(1024.0*QuantumScale*
+                pixel.blue)];
+#endif
+              break;
+            }
+            case sRGBColorspace:
+            {
+              if ((QuantumScale*pixel.red) <= 0.0031308)
+                pixel.red*=12.92f;
+              else
+                pixel.red=(MagickRealType) QuantumRange*(1.055*
+                  pow(QuantumScale*pixel.red,(1.0/2.4))-0.055);
+              if ((QuantumScale*pixel.green) <= 0.0031308)
+                pixel.green*=12.92f;
+              else
+                pixel.green=(MagickRealType) QuantumRange*(1.055*
+                  pow(QuantumScale*pixel.green,(1.0/2.4))-0.055);
+              if ((QuantumScale*pixel.blue) <= 0.0031308)
+                pixel.blue*=12.92f;
+              else
+                pixel.blue=(MagickRealType) QuantumRange*(1.055*
+                  pow(QuantumScale*pixel.blue,(1.0/2.4))-0.055);
+              break;
+            }
+            default:
+              break;
+          }
+          SetPixelRed(image,ScaleMapToQuantum((MagickRealType) MaxMap*
+            QuantumScale*pixel.red),q);
+          SetPixelGreen(image,ScaleMapToQuantum((MagickRealType) MaxMap*
+            QuantumScale*pixel.green),q);
+          SetPixelBlue(image,ScaleMapToQuantum((MagickRealType) MaxMap*
+            QuantumScale*pixel.blue),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransformRGBImage)
+#endif
+            proceed=SetImageProgress(image,TransformRGBImageTag,progress++,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      image_view=DestroyCacheView(image_view);
+      break;
+    }
+    case PseudoClass:
+    {
+      /*
+        Convert PseudoClass image.
+      */
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        PixelInfo
+          pixel;
+
+        register size_t
+          blue,
+          green,
+          red;
+
+        red=ScaleQuantumToMap(image->colormap[i].red);
+        green=ScaleQuantumToMap(image->colormap[i].green);
+        blue=ScaleQuantumToMap(image->colormap[i].blue);
+        pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
+        pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
+        pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
+        switch (colorspace)
+        {
+          case YCCColorspace:
+          {
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+            image->colormap[i].red=(Quantum) (QuantumRange*YCCMap[
+              RoundToYCC(1024.0*QuantumScale*pixel.red)]);
+            image->colormap[i].green=(Quantum) (QuantumRange*YCCMap[
+              RoundToYCC(1024.0*QuantumScale*pixel.green)]);
+            image->colormap[i].blue=(Quantum) (QuantumRange*YCCMap[
+              RoundToYCC(1024.0*QuantumScale*pixel.blue)]);
+#endif
+            break;
+          }
+          case sRGBColorspace:
+          {
+            if ((QuantumScale*pixel.red) <= 0.0031308)
+              pixel.red*=12.92f;
+            else
+              pixel.red=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
+                pixel.red,(1.0/2.4))-0.055);
+            if ((QuantumScale*pixel.green) <= 0.0031308)
+              pixel.green*=12.92f;
+            else
+              pixel.green=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
+                pixel.green,(1.0/2.4))-0.055);
+            if ((QuantumScale*pixel.blue) <= 0.0031308)
+              pixel.blue*=12.92f;
+            else
+              pixel.blue=(MagickRealType) QuantumRange*(1.055*pow(QuantumScale*
+                pixel.blue,(1.0/2.4))-0.055);
+          }
+          default:
+          {
+            image->colormap[i].red=ScaleMapToQuantum((MagickRealType) MaxMap*
+              QuantumScale*pixel.red);
+            image->colormap[i].green=ScaleMapToQuantum((MagickRealType) MaxMap*
+              QuantumScale*pixel.green);
+            image->colormap[i].blue=ScaleMapToQuantum((MagickRealType) MaxMap*
+              QuantumScale*pixel.blue);
+            break;
+          }
+        }
+      }
+      image_view=DestroyCacheView(image_view);
+      (void) SyncImage(image);
+      break;
+    }
+  }
+  /*
+    Relinquish resources.
+  */
+  z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
+  y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
+  x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
+  if (SetImageColorspace(image,RGBColorspace) == MagickFalse)
+    return(MagickFalse);
+  return(MagickTrue);
+}
diff --git a/MagickCore/colorspace.h b/MagickCore/colorspace.h
new file mode 100644
index 0000000..8c67028
--- /dev/null
+++ b/MagickCore/colorspace.h
@@ -0,0 +1,62 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image colorspace methods.
+*/
+#ifndef _MAGICKCORE_COLORSPACE_H
+#define _MAGICKCORE_COLORSPACE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedColorspace,
+  RGBColorspace,
+  GRAYColorspace,
+  TransparentColorspace,
+  OHTAColorspace,
+  LabColorspace,
+  XYZColorspace,
+  YCbCrColorspace,
+  YCCColorspace,
+  YIQColorspace,
+  YPbPrColorspace,
+  YUVColorspace,
+  CMYKColorspace,
+  sRGBColorspace,
+  HSBColorspace,
+  HSLColorspace,
+  HWBColorspace,
+  Rec601LumaColorspace,
+  Rec601YCbCrColorspace,
+  Rec709LumaColorspace,
+  Rec709YCbCrColorspace,
+  LogColorspace,
+  CMYColorspace
+} ColorspaceType;
+
+extern MagickExport MagickBooleanType
+  RGBTransformImage(Image *,const ColorspaceType),
+  SetImageColorspace(Image *,const ColorspaceType),
+  TransformImageColorspace(Image *,const ColorspaceType),
+  TransformRGBImage(Image *,const ColorspaceType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/compare.c b/MagickCore/compare.c
new file mode 100644
index 0000000..f7cad2b
--- /dev/null
+++ b/MagickCore/compare.c
@@ -0,0 +1,1904 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               CCCC   OOO   M   M  PPPP    AAA   RRRR    EEEEE               %
+%              C      O   O  MM MM  P   P  A   A  R   R   E                   %
+%              C      O   O  M M M  PPPP   AAAAA  RRRR    EEE                 %
+%              C      O   O  M   M  P      A   A  R R     E                   %
+%               CCCC   OOO   M   M  P      A   A  R  R    EEEEE               %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Comparison Methods                    %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               December 2003                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/compare.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e I m a g e C h a n n e l s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareImageChannels() compares one or more image channels of an image
+%  to a reconstructed image and returns the difference image.
+%
+%  The format of the CompareImageChannels method is:
+%
+%      Image *CompareImageChannels(const Image *image,
+%        const Image *reconstruct_image,const ChannelType channel,
+%        const MetricType metric,double *distortion,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o reconstruct_image: the reconstruct image.
+%
+%    o channel: the channel.
+%
+%    o metric: the metric.
+%
+%    o distortion: the computed distortion between the images.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *CompareImages(Image *image,const Image *reconstruct_image,
+  const MetricType metric,double *distortion,ExceptionInfo *exception)
+{
+  Image
+    *highlight_image;
+
+  highlight_image=CompareImageChannels(image,reconstruct_image,CompositeChannels,
+    metric,distortion,exception);
+  return(highlight_image);
+}
+
+MagickExport Image *CompareImageChannels(Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  const MetricType metric,double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *highlight_view,
+    *image_view,
+    *reconstruct_view;
+
+  const char
+    *artifact;
+
+  Image
+    *difference_image,
+    *highlight_image;
+
+  ssize_t
+    y;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    highlight,
+    lowlight,
+    zero;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(reconstruct_image != (const Image *) NULL);
+  assert(reconstruct_image->signature == MagickSignature);
+  assert(distortion != (double *) NULL);
+  *distortion=0.0;
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((reconstruct_image->columns != image->columns) ||
+      (reconstruct_image->rows != image->rows))
+    ThrowImageException(ImageError,"ImageSizeDiffers");
+  status=GetImageChannelDistortion(image,reconstruct_image,channel,metric,
+    distortion,exception);
+  if (status == MagickFalse)
+    return((Image *) NULL);
+  difference_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (difference_image == (Image *) NULL)
+    return((Image *) NULL);
+  (void) SetImageAlphaChannel(difference_image,OpaqueAlphaChannel);
+  highlight_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (highlight_image == (Image *) NULL)
+    {
+      difference_image=DestroyImage(difference_image);
+      return((Image *) NULL);
+    }
+  if (SetImageStorageClass(highlight_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&highlight_image->exception);
+      difference_image=DestroyImage(difference_image);
+      highlight_image=DestroyImage(highlight_image);
+      return((Image *) NULL);
+    }
+  (void) SetImageAlphaChannel(highlight_image,OpaqueAlphaChannel);
+  (void) QueryMagickColor("#f1001ecc",&highlight,exception);
+  artifact=GetImageArtifact(image,"highlight-color");
+  if (artifact != (const char *) NULL)
+    (void) QueryMagickColor(artifact,&highlight,exception);
+  (void) QueryMagickColor("#ffffffcc",&lowlight,exception);
+  artifact=GetImageArtifact(image,"lowlight-color");
+  if (artifact != (const char *) NULL)
+    (void) QueryMagickColor(artifact,&lowlight,exception);
+  if (highlight_image->colorspace == CMYKColorspace)
+    {
+      ConvertRGBToCMYK(&highlight);
+      ConvertRGBToCMYK(&lowlight);
+    }
+  /*
+    Generate difference image.
+  */
+  status=MagickTrue;
+  GetPixelInfo(image,&zero);
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+  highlight_view=AcquireCacheView(highlight_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    PixelInfo
+      pixel,
+      reconstruct_pixel;
+
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict r;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    r=QueueCacheViewAuthenticPixels(highlight_view,0,y,highlight_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) ||
+        (q == (const Quantum *) NULL) || (r == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    reconstruct_pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickStatusType
+        difference;
+
+      SetPixelInfo(image,p,&pixel);
+      SetPixelInfo(reconstruct_image,q,&reconstruct_pixel);
+      difference=MagickFalse;
+      if (channel == CompositeChannels)
+        {
+          if (IsFuzzyEquivalencePixelInfo(&pixel,&reconstruct_pixel) == MagickFalse)
+            difference=MagickTrue;
+        }
+      else
+        {
+          if (((channel & RedChannel) != 0) &&
+              (GetPixelRed(image,p) != GetPixelRed(reconstruct_image,q)))
+            difference=MagickTrue;
+          if (((channel & GreenChannel) != 0) &&
+              (GetPixelGreen(image,p) != GetPixelGreen(reconstruct_image,q)))
+            difference=MagickTrue;
+          if (((channel & BlueChannel) != 0) &&
+              (GetPixelBlue(image,p) != GetPixelBlue(reconstruct_image,q)))
+            difference=MagickTrue;
+          if (((channel & OpacityChannel) != 0) &&
+              (image->matte != MagickFalse) &&
+              (GetPixelAlpha(image,p) != GetPixelAlpha(reconstruct_image,q)))
+            difference=MagickTrue;
+          if ((((channel & BlackChannel) != 0) &&
+               (image->colorspace == CMYKColorspace) &&
+               (reconstruct_image->colorspace == CMYKColorspace)) &&
+              (GetPixelBlack(image,p) != GetPixelBlack(reconstruct_image,q)))
+            difference=MagickTrue;
+        }
+      if (difference != MagickFalse)
+        SetPixelPixelInfo(highlight_image,&highlight,r);
+      else
+        SetPixelPixelInfo(highlight_image,&lowlight,r);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+      r+=GetPixelChannels(highlight_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(highlight_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+  }
+  highlight_view=DestroyCacheView(highlight_view);
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  (void) CompositeImage(difference_image,image->compose,highlight_image,0,0);
+  highlight_image=DestroyImage(highlight_image);
+  if (status == MagickFalse)
+    difference_image=DestroyImage(difference_image);
+  return(difference_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l D i s t o r t i o n                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelDistortion() compares one or more image channels of an image
+%  to a reconstructed image and returns the specified distortion metric.
+%
+%  The format of the CompareImageChannels method is:
+%
+%      MagickBooleanType GetImageChannelDistortion(const Image *image,
+%        const Image *reconstruct_image,const ChannelType channel,
+%        const MetricType metric,double *distortion,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o reconstruct_image: the reconstruct image.
+%
+%    o channel: the channel.
+%
+%    o metric: the metric.
+%
+%    o distortion: the computed distortion between the images.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType GetImageDistortion(Image *image,
+  const Image *reconstruct_image,const MetricType metric,double *distortion,
+  ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetImageChannelDistortion(image,reconstruct_image,CompositeChannels,
+    metric,distortion,exception);
+  return(status);
+}
+
+static MagickBooleanType GetAbsoluteDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,double *distortion,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  ssize_t
+    y;
+
+  /*
+    Compute the absolute difference in pixels between two images.
+  */
+  status=MagickTrue;
+  GetPixelInfo(image,&zero);
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[CompositeChannels+1];
+
+    PixelInfo
+      pixel,
+      reconstruct_pixel;
+
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    reconstruct_pixel=pixel;
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,p,&pixel);
+      SetPixelInfo(reconstruct_image,q,&reconstruct_pixel);
+      if (IsFuzzyEquivalencePixelInfo(&pixel,&reconstruct_pixel) == MagickFalse)
+        {
+          if ((channel & RedChannel) != 0)
+            channel_distortion[RedChannel]++;
+          if ((channel & GreenChannel) != 0)
+            channel_distortion[GreenChannel]++;
+          if ((channel & BlueChannel) != 0)
+            channel_distortion[BlueChannel]++;
+          if (((channel & OpacityChannel) != 0) &&
+              (image->matte != MagickFalse))
+            channel_distortion[OpacityChannel]++;
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            channel_distortion[BlackChannel]++;
+          channel_distortion[CompositeChannels]++;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetAbsoluteError)
+#endif
+    for (i=0; i <= (ssize_t) CompositeChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+static size_t GetNumberChannels(const Image *image,
+  const ChannelType channel)
+{
+  size_t
+    channels;
+
+  channels=0;
+  if ((channel & RedChannel) != 0)
+    channels++;
+  if ((channel & GreenChannel) != 0)
+    channels++;
+  if ((channel & BlueChannel) != 0)
+    channels++;
+  if (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    channels++;
+  if (((channel & OpacityChannel) != 0) &&
+       (image->matte != MagickFalse))
+    channels++;
+  return(channels);
+}
+
+static MagickBooleanType GetFuzzDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[CompositeChannels+1];
+
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*(GetPixelRed(image,p)-(MagickRealType)
+            GetPixelRed(reconstruct_image,q));
+          channel_distortion[RedChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*(GetPixelGreen(image,p)-(MagickRealType)
+            GetPixelGreen(reconstruct_image,q));
+          channel_distortion[GreenChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*(GetPixelBlue(image,p)-(MagickRealType)
+            GetPixelBlue(reconstruct_image,q));
+          channel_distortion[BlueChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if (((channel & OpacityChannel) != 0) && ((image->matte != MagickFalse) ||
+          (reconstruct_image->matte != MagickFalse)))
+        {
+          distance=QuantumScale*((image->matte != MagickFalse ?
+            GetPixelAlpha(image,p) : OpaqueAlpha)-(reconstruct_image->matte !=
+            MagickFalse ? GetPixelAlpha(reconstruct_image,q): OpaqueAlpha));
+          channel_distortion[OpacityChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*(GetPixelBlack(image,p)-(MagickRealType)
+            GetPixelBlack(reconstruct_image,q));
+          channel_distortion[BlackChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetMeanSquaredError)
+#endif
+    for (i=0; i <= (ssize_t) CompositeChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (ssize_t) CompositeChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  if (((channel & OpacityChannel) != 0) && ((image->matte != MagickFalse) ||
+      (reconstruct_image->matte != MagickFalse)))
+    distortion[CompositeChannels]/=(double) (GetNumberChannels(image,channel)-1);
+  else
+    distortion[CompositeChannels]/=(double) GetNumberChannels(image,channel);
+  distortion[CompositeChannels]=sqrt(distortion[CompositeChannels]);
+  return(status);
+}
+
+static MagickBooleanType GetMeanAbsoluteDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[CompositeChannels+1];
+
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,
+      reconstruct_image->columns,1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*fabs(GetPixelRed(image,p)-(double)
+            GetPixelRed(reconstruct_image,q));
+          channel_distortion[RedChannel]+=distance;
+          channel_distortion[CompositeChannels]+=distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*fabs(GetPixelGreen(image,p)-(double)
+            GetPixelGreen(reconstruct_image,q));
+          channel_distortion[GreenChannel]+=distance;
+          channel_distortion[CompositeChannels]+=distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*fabs(GetPixelBlue(image,p)-(double)
+            GetPixelBlue(reconstruct_image,q));
+          channel_distortion[BlueChannel]+=distance;
+          channel_distortion[CompositeChannels]+=distance;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*fabs(GetPixelBlack(image,p)-(double)
+            GetPixelBlack(reconstruct_image,q));
+          channel_distortion[BlackChannel]+=distance;
+          channel_distortion[CompositeChannels]+=distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*fabs(GetPixelAlpha(image,p)-(double)
+            GetPixelAlpha(reconstruct_image,q));
+          channel_distortion[OpacityChannel]+=distance;
+          channel_distortion[CompositeChannels]+=distance;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetMeanAbsoluteError)
+#endif
+    for (i=0; i <= (ssize_t) CompositeChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (ssize_t) CompositeChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  distortion[CompositeChannels]/=(double) GetNumberChannels(image,channel);
+  return(status);
+}
+
+static MagickBooleanType GetMeanErrorPerPixel(Image *image,
+  const Image *reconstruct_image,const ChannelType channel,double *distortion,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    alpha,
+    area,
+    beta,
+    maximum_error,
+    mean_error;
+
+  ssize_t
+    y;
+
+  status=MagickTrue;
+  alpha=1.0;
+  beta=1.0;
+  area=0.0;
+  maximum_error=0.0;
+  mean_error=0.0;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        break;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (image->matte != MagickFalse)
+            alpha=(MagickRealType) (QuantumScale*(
+              GetPixelAlpha(reconstruct_image,p)));
+          if (reconstruct_image->matte != MagickFalse)
+            beta=(MagickRealType) (QuantumScale*
+              GetPixelAlpha(reconstruct_image,q));
+        }
+      if ((channel & RedChannel) != 0)
+        {
+          distance=fabs(alpha*GetPixelRed(image,p)-beta*
+            GetPixelRed(reconstruct_image,q));
+          distortion[RedChannel]+=distance;
+          distortion[CompositeChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=fabs(alpha*GetPixelGreen(image,p)-beta*
+            GetPixelGreen(reconstruct_image,q));
+          distortion[GreenChannel]+=distance;
+          distortion[CompositeChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=fabs(alpha*GetPixelBlue(image,p)-beta*
+            GetPixelBlue(reconstruct_image,q));
+          distortion[BlueChannel]+=distance;
+          distortion[CompositeChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=fabs(alpha*GetPixelBlack(image,p)-beta*
+            GetPixelBlack(reconstruct_image,q));
+          distortion[BlackChannel]+=distance;
+          distortion[CompositeChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=fabs((double) GetPixelAlpha(image,p)-
+            GetPixelAlpha(reconstruct_image,q));
+          distortion[OpacityChannel]+=distance;
+          distortion[CompositeChannels]+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  image->error.mean_error_per_pixel=distortion[CompositeChannels]/area;
+  image->error.normalized_mean_error=QuantumScale*QuantumScale*mean_error/area;
+  image->error.normalized_maximum_error=QuantumScale*maximum_error;
+  return(status);
+}
+
+static MagickBooleanType GetMeanSquaredDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[CompositeChannels+1];
+
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,
+      reconstruct_image->columns,1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*(GetPixelRed(image,p)-(MagickRealType)
+             GetPixelRed(reconstruct_image,q));
+          channel_distortion[RedChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*(GetPixelGreen(image,p)-(MagickRealType)
+            GetPixelGreen(reconstruct_image,q));
+          channel_distortion[GreenChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*(GetPixelBlue(image,p)-(MagickRealType)
+            GetPixelBlue(reconstruct_image,q));
+          channel_distortion[BlueChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*(GetPixelBlack(image,p)-(MagickRealType)
+            GetPixelBlack(reconstruct_image,q));
+          channel_distortion[BlackChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*(GetPixelAlpha(image,p)-(MagickRealType)
+            GetPixelAlpha(reconstruct_image,q));
+          channel_distortion[OpacityChannel]+=distance*distance;
+          channel_distortion[CompositeChannels]+=distance*distance;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetMeanSquaredError)
+#endif
+    for (i=0; i <= (ssize_t) CompositeChannels; i++)
+      distortion[i]+=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  for (i=0; i <= (ssize_t) CompositeChannels; i++)
+    distortion[i]/=((double) image->columns*image->rows);
+  distortion[CompositeChannels]/=(double) GetNumberChannels(image,channel);
+  return(status);
+}
+
+static MagickBooleanType GetNormalizedCrossCorrelationDistortion(
+  const Image *image,const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+#define SimilarityImageTag  "Similarity/Image"
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  ChannelStatistics
+    *image_statistics,
+    *reconstruct_statistics;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  MagickRealType
+    area;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Normalize to account for variation due to lighting and exposure condition.
+  */
+  image_statistics=GetImageChannelStatistics(image,exception);
+  reconstruct_statistics=GetImageChannelStatistics(reconstruct_image,exception);
+  status=MagickTrue;
+  progress=0;
+  for (i=0; i <= (ssize_t) CompositeChannels; i++)
+    distortion[i]=0.0;
+  area=1.0/((MagickRealType) image->columns*image->rows);
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        distortion[RedChannel]+=area*QuantumScale*(GetPixelRed(image,p)-
+          image_statistics[RedChannel].mean)*(
+          GetPixelRed(reconstruct_image,q)-
+          reconstruct_statistics[RedChannel].mean);
+      if ((channel & GreenChannel) != 0)
+        distortion[GreenChannel]+=area*QuantumScale*(GetPixelGreen(image,p)-
+          image_statistics[GreenChannel].mean)*(
+          GetPixelGreen(reconstruct_image,q)-
+          reconstruct_statistics[GreenChannel].mean);
+      if ((channel & BlueChannel) != 0)
+        distortion[BlueChannel]+=area*QuantumScale*(GetPixelBlue(image,p)-
+          image_statistics[BlueChannel].mean)*(
+          GetPixelBlue(reconstruct_image,q)-
+          reconstruct_statistics[BlueChannel].mean);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        distortion[BlackChannel]+=area*QuantumScale*(GetPixelBlack(image,p)-
+          image_statistics[OpacityChannel].mean)*(
+          GetPixelBlack(reconstruct_image,q)-
+          reconstruct_statistics[OpacityChannel].mean);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        distortion[OpacityChannel]+=area*QuantumScale*(GetPixelAlpha(image,p)-
+          image_statistics[OpacityChannel].mean)*
+          (GetPixelAlpha(reconstruct_image,q)-
+          reconstruct_statistics[OpacityChannel].mean);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(image);
+    }
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,SimilarityImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  /*
+    Divide by the standard deviation.
+  */
+  for (i=0; i < (ssize_t) CompositeChannels; i++)
+  {
+    MagickRealType
+      gamma;
+
+    gamma=image_statistics[i].standard_deviation*
+      reconstruct_statistics[i].standard_deviation;
+    gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+    distortion[i]=QuantumRange*gamma*distortion[i];
+  }
+  distortion[CompositeChannels]=0.0;
+  if ((channel & RedChannel) != 0)
+    distortion[CompositeChannels]+=distortion[RedChannel]*
+      distortion[RedChannel];
+  if ((channel & GreenChannel) != 0)
+    distortion[CompositeChannels]+=distortion[GreenChannel]*
+      distortion[GreenChannel];
+  if ((channel & BlueChannel) != 0)
+    distortion[CompositeChannels]+=distortion[BlueChannel]*
+      distortion[BlueChannel];
+  if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
+    distortion[CompositeChannels]+=distortion[OpacityChannel]*
+      distortion[OpacityChannel];
+  if (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    distortion[CompositeChannels]+=distortion[BlackChannel]*
+      distortion[BlackChannel];
+  distortion[CompositeChannels]=sqrt(distortion[CompositeChannels]/
+    GetNumberChannels(image,channel));
+  /*
+    Free resources.
+  */
+  reconstruct_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+    reconstruct_statistics);
+  image_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+    image_statistics);
+  return(status);
+}
+
+static MagickBooleanType GetPeakAbsoluteDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      channel_distortion[CompositeChannels+1];
+
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,
+      reconstruct_image->columns,1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    (void) ResetMagickMemory(channel_distortion,0,sizeof(channel_distortion));
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      if ((channel & RedChannel) != 0)
+        {
+          distance=QuantumScale*fabs(GetPixelRed(image,p)-(double)
+            GetPixelRed(reconstruct_image,q));
+          if (distance > channel_distortion[RedChannel])
+            channel_distortion[RedChannel]=distance;
+          if (distance > channel_distortion[CompositeChannels])
+            channel_distortion[CompositeChannels]=distance;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          distance=QuantumScale*fabs(GetPixelGreen(image,p)-(double)
+            GetPixelGreen(reconstruct_image,q));
+          if (distance > channel_distortion[GreenChannel])
+            channel_distortion[GreenChannel]=distance;
+          if (distance > channel_distortion[CompositeChannels])
+            channel_distortion[CompositeChannels]=distance;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          distance=QuantumScale*fabs(GetPixelBlue(image,p)-(double)
+            GetPixelBlue(reconstruct_image,q));
+          if (distance > channel_distortion[BlueChannel])
+            channel_distortion[BlueChannel]=distance;
+          if (distance > channel_distortion[CompositeChannels])
+            channel_distortion[CompositeChannels]=distance;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=QuantumScale*fabs(GetPixelBlack(image,p)-(double)
+            GetPixelBlack(reconstruct_image,q));
+          if (distance > channel_distortion[BlackChannel])
+            channel_distortion[BlackChannel]=distance;
+          if (distance > channel_distortion[CompositeChannels])
+            channel_distortion[CompositeChannels]=distance;
+        }
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte != MagickFalse))
+        {
+          distance=QuantumScale*fabs(GetPixelAlpha(image,p)-(double)
+            GetPixelAlpha(reconstruct_image,q));
+          if (distance > channel_distortion[OpacityChannel])
+            channel_distortion[OpacityChannel]=distance;
+          if (distance > channel_distortion[CompositeChannels])
+            channel_distortion[CompositeChannels]=distance;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(image);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetPeakAbsoluteError)
+#endif
+    for (i=0; i <= (ssize_t) CompositeChannels; i++)
+      if (channel_distortion[i] > distortion[i])
+        distortion[i]=channel_distortion[i];
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+static MagickBooleanType GetPeakSignalToNoiseRatio(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetMeanSquaredDistortion(image,reconstruct_image,channel,distortion,
+    exception);
+  if ((channel & RedChannel) != 0)
+    distortion[RedChannel]=20.0*log10((double) 1.0/sqrt(
+      distortion[RedChannel]));
+  if ((channel & GreenChannel) != 0)
+    distortion[GreenChannel]=20.0*log10((double) 1.0/sqrt(
+      distortion[GreenChannel]));
+  if ((channel & BlueChannel) != 0)
+    distortion[BlueChannel]=20.0*log10((double) 1.0/sqrt(
+      distortion[BlueChannel]));
+  if (((channel & OpacityChannel) != 0) &&
+      (image->matte != MagickFalse))
+    distortion[OpacityChannel]=20.0*log10((double) 1.0/sqrt(
+      distortion[OpacityChannel]));
+  if (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    distortion[BlackChannel]=20.0*log10((double) 1.0/sqrt(
+      distortion[BlackChannel]));
+  distortion[CompositeChannels]=20.0*log10((double) 1.0/sqrt(
+    distortion[CompositeChannels]));
+  return(status);
+}
+
+static MagickBooleanType GetRootMeanSquaredDistortion(const Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  double *distortion,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetMeanSquaredDistortion(image,reconstruct_image,channel,distortion,
+    exception);
+  if ((channel & RedChannel) != 0)
+    distortion[RedChannel]=sqrt(distortion[RedChannel]);
+  if ((channel & GreenChannel) != 0)
+    distortion[GreenChannel]=sqrt(distortion[GreenChannel]);
+  if ((channel & BlueChannel) != 0)
+    distortion[BlueChannel]=sqrt(distortion[BlueChannel]);
+  if (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    distortion[BlackChannel]=sqrt(distortion[BlackChannel]);
+  if (((channel & OpacityChannel) != 0) &&
+      (image->matte != MagickFalse))
+    distortion[OpacityChannel]=sqrt(distortion[OpacityChannel]);
+  distortion[CompositeChannels]=sqrt(distortion[CompositeChannels]);
+  return(status);
+}
+
+MagickExport MagickBooleanType GetImageChannelDistortion(Image *image,
+  const Image *reconstruct_image,const ChannelType channel,
+  const MetricType metric,double *distortion,ExceptionInfo *exception)
+{
+  double
+    *channel_distortion;
+
+  MagickBooleanType
+    status;
+
+  size_t
+    length;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(reconstruct_image != (const Image *) NULL);
+  assert(reconstruct_image->signature == MagickSignature);
+  assert(distortion != (double *) NULL);
+  *distortion=0.0;
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((reconstruct_image->columns != image->columns) ||
+      (reconstruct_image->rows != image->rows))
+    ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
+  /*
+    Get image distortion.
+  */
+  length=CompositeChannels+1UL;
+  channel_distortion=(double *) AcquireQuantumMemory(length,
+    sizeof(*channel_distortion));
+  if (channel_distortion == (double *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(channel_distortion,0,length*
+    sizeof(*channel_distortion));
+  switch (metric)
+  {
+    case AbsoluteErrorMetric:
+    {
+      status=GetAbsoluteDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case FuzzErrorMetric:
+    {
+      status=GetFuzzDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanAbsoluteErrorMetric:
+    {
+      status=GetMeanAbsoluteDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanErrorPerPixelMetric:
+    {
+      status=GetMeanErrorPerPixel(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanSquaredErrorMetric:
+    {
+      status=GetMeanSquaredDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case NormalizedCrossCorrelationErrorMetric:
+    default:
+    {
+      status=GetNormalizedCrossCorrelationDistortion(image,reconstruct_image,
+        channel,channel_distortion,exception);
+      break;
+    }
+    case PeakAbsoluteErrorMetric:
+    {
+      status=GetPeakAbsoluteDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case PeakSignalToNoiseRatioMetric:
+    {
+      status=GetPeakSignalToNoiseRatio(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+    case RootMeanSquaredErrorMetric:
+    {
+      status=GetRootMeanSquaredDistortion(image,reconstruct_image,channel,
+        channel_distortion,exception);
+      break;
+    }
+  }
+  *distortion=channel_distortion[CompositeChannels];
+  channel_distortion=(double *) RelinquishMagickMemory(channel_distortion);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l D i s t o r t i o n s                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelDistrortion() compares the image channels of an image to a
+%  reconstructed image and returns the specified distortion metric for each
+%  channel.
+%
+%  The format of the CompareImageChannels method is:
+%
+%      double *GetImageChannelDistortions(const Image *image,
+%        const Image *reconstruct_image,const MetricType metric,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o reconstruct_image: the reconstruct image.
+%
+%    o metric: the metric.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport double *GetImageChannelDistortions(Image *image,
+  const Image *reconstruct_image,const MetricType metric,
+  ExceptionInfo *exception)
+{
+  double
+    *channel_distortion;
+
+  MagickBooleanType
+    status;
+
+  size_t
+    length;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(reconstruct_image != (const Image *) NULL);
+  assert(reconstruct_image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((reconstruct_image->columns != image->columns) ||
+      (reconstruct_image->rows != image->rows))
+    {
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        ImageError,"ImageSizeDiffers","`%s'",image->filename);
+      return((double *) NULL);
+    }
+  /*
+    Get image distortion.
+  */
+  length=CompositeChannels+1UL;
+  channel_distortion=(double *) AcquireQuantumMemory(length,
+    sizeof(*channel_distortion));
+  if (channel_distortion == (double *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(channel_distortion,0,length*
+    sizeof(*channel_distortion));
+  status=MagickTrue;
+  switch (metric)
+  {
+    case AbsoluteErrorMetric:
+    {
+      status=GetAbsoluteDistortion(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case FuzzErrorMetric:
+    {
+      status=GetFuzzDistortion(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanAbsoluteErrorMetric:
+    {
+      status=GetMeanAbsoluteDistortion(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanErrorPerPixelMetric:
+    {
+      status=GetMeanErrorPerPixel(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case MeanSquaredErrorMetric:
+    {
+      status=GetMeanSquaredDistortion(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case NormalizedCrossCorrelationErrorMetric:
+    default:
+    {
+      status=GetNormalizedCrossCorrelationDistortion(image,reconstruct_image,
+        CompositeChannels,channel_distortion,exception);
+      break;
+    }
+    case PeakAbsoluteErrorMetric:
+    {
+      status=GetPeakAbsoluteDistortion(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case PeakSignalToNoiseRatioMetric:
+    {
+      status=GetPeakSignalToNoiseRatio(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+    case RootMeanSquaredErrorMetric:
+    {
+      status=GetRootMeanSquaredDistortion(image,reconstruct_image,CompositeChannels,
+        channel_distortion,exception);
+      break;
+    }
+  }
+  if (status == MagickFalse)
+    {
+      channel_distortion=(double *) RelinquishMagickMemory(channel_distortion);
+      return((double *) NULL);
+    }
+  return(channel_distortion);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I s I m a g e s E q u a l                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImagesEqual() measures the difference between colors at each pixel
+%  location of two images.  A value other than 0 means the colors match
+%  exactly.  Otherwise an error measure is computed by summing over all
+%  pixels in an image the distance squared in RGB space between each image
+%  pixel and its corresponding pixel in the reconstruct image.  The error
+%  measure is assigned to these image members:
+%
+%    o mean_error_per_pixel:  The mean error for any single pixel in
+%      the image.
+%
+%    o normalized_mean_error:  The normalized mean quantization error for
+%      any single pixel in the image.  This distance measure is normalized to
+%      a range between 0 and 1.  It is independent of the range of red, green,
+%      and blue values in the image.
+%
+%    o normalized_maximum_error:  The normalized maximum quantization
+%      error for any single pixel in the image.  This distance measure is
+%      normalized to a range between 0 and 1.  It is independent of the range
+%      of red, green, and blue values in your image.
+%
+%  A small normalized mean square error, accessed as
+%  image->normalized_mean_error, suggests the images are very similar in
+%  spatial layout and color.
+%
+%  The format of the IsImagesEqual method is:
+%
+%      MagickBooleanType IsImagesEqual(Image *image,
+%        const Image *reconstruct_image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o reconstruct_image: the reconstruct image.
+%
+*/
+MagickExport MagickBooleanType IsImagesEqual(Image *image,
+  const Image *reconstruct_image)
+{
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    area,
+    maximum_error,
+    mean_error,
+    mean_error_per_pixel;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(reconstruct_image != (const Image *) NULL);
+  assert(reconstruct_image->signature == MagickSignature);
+  if ((reconstruct_image->columns != image->columns) ||
+      (reconstruct_image->rows != image->rows))
+    ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
+  area=0.0;
+  maximum_error=0.0;
+  mean_error_per_pixel=0.0;
+  mean_error=0.0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        distance;
+
+      distance=fabs(GetPixelRed(image,p)-(double)
+        GetPixelRed(reconstruct_image,q));
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      area++;
+      distance=fabs(GetPixelGreen(image,p)-(double)
+        GetPixelGreen(reconstruct_image,q));
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      area++;
+      distance=fabs(GetPixelBlue(image,p)-(double)
+        GetPixelBlue(reconstruct_image,q));
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      area++;
+      if (image->matte != MagickFalse)
+        {
+          distance=fabs(GetPixelAlpha(image,p)-(double)
+            GetPixelAlpha(reconstruct_image,q));
+          mean_error_per_pixel+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      if ((image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        {
+          distance=fabs(GetPixelBlack(image,p)-(double)
+            GetPixelBlack(reconstruct_image,q));
+          mean_error_per_pixel+=distance;
+          mean_error+=distance*distance;
+          if (distance > maximum_error)
+            maximum_error=distance;
+          area++;
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  image->error.mean_error_per_pixel=(double) (mean_error_per_pixel/area);
+  image->error.normalized_mean_error=(double) (QuantumScale*QuantumScale*
+    mean_error/area);
+  image->error.normalized_maximum_error=(double) (QuantumScale*maximum_error);
+  status=image->error.mean_error_per_pixel == 0.0 ? MagickTrue : MagickFalse;
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S i m i l a r i t y I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SimilarityImage() compares the reference image of the image and returns the
+%  best match offset.  In addition, it returns a similarity image such that an
+%  exact match location is completely white and if none of the pixels match,
+%  black, otherwise some gray level in-between.
+%
+%  The format of the SimilarityImageImage method is:
+%
+%      Image *SimilarityImage(const Image *image,const Image *reference,
+%        RectangleInfo *offset,double *similarity,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o reference: find an area of the image that closely resembles this image.
+%
+%    o the best match offset of the reference image within the image.
+%
+%    o similarity: the computed similarity between the images.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static double GetNCCDistortion(const Image *image,
+  const Image *reconstruct_image,
+  const ChannelStatistics *reconstruct_statistics,ExceptionInfo *exception)
+{
+#define SimilarityImageTag  "Similarity/Image"
+
+  CacheView
+    *image_view,
+    *reconstruct_view;
+
+  ChannelStatistics
+    *image_statistics;
+
+  double
+    distortion;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    area,
+    gamma;
+
+  ssize_t
+    y;
+
+  unsigned long
+    number_channels;
+  
+  /*
+    Normalize to account for variation due to lighting and exposure condition.
+  */
+  image_statistics=GetImageChannelStatistics(image,exception);
+  status=MagickTrue;
+  distortion=0.0;
+  area=1.0/((MagickRealType) image->columns*image->rows);
+  image_view=AcquireCacheView(image);
+  reconstruct_view=AcquireCacheView(reconstruct_image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewVirtualPixels(reconstruct_view,0,y,reconstruct_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      distortion+=area*QuantumScale*(GetPixelRed(image,p)-
+        image_statistics[RedChannel].mean)*(
+        GetPixelRed(reconstruct_image,q)-
+        reconstruct_statistics[RedChannel].mean);
+      distortion+=area*QuantumScale*(GetPixelGreen(image,p)-
+        image_statistics[GreenChannel].mean)*(
+        GetPixelGreen(reconstruct_image,q)-
+        reconstruct_statistics[GreenChannel].mean);
+      distortion+=area*QuantumScale*(GetPixelBlue(image,p)-
+        GetPixelBlue(reconstruct_image,q)-
+        image_statistics[BlueChannel].mean)*(
+        reconstruct_statistics[BlueChannel].mean);
+      if ((image->colorspace == CMYKColorspace) &&
+          (reconstruct_image->colorspace == CMYKColorspace))
+        distortion+=area*QuantumScale*(GetPixelBlack(image,p)-
+          image_statistics[BlackChannel].mean)*(
+          GetPixelBlack(reconstruct_image,q)-
+          reconstruct_statistics[BlackChannel].mean);
+      if (image->matte != MagickFalse)
+        distortion+=area*QuantumScale*(GetPixelAlpha(image,p)-
+          image_statistics[OpacityChannel].mean)*(
+          GetPixelAlpha(reconstruct_image,q)-
+          reconstruct_statistics[OpacityChannel].mean);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(reconstruct_image);
+    }
+  }
+  reconstruct_view=DestroyCacheView(reconstruct_view);
+  image_view=DestroyCacheView(image_view);
+  /*
+    Divide by the standard deviation.
+  */
+  gamma=image_statistics[CompositeChannels].standard_deviation*
+    reconstruct_statistics[CompositeChannels].standard_deviation;
+  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+  distortion=QuantumRange*gamma*distortion;
+  number_channels=3;
+  if (image->matte != MagickFalse)
+    number_channels++;
+  if (image->colorspace == CMYKColorspace)
+    number_channels++;
+  distortion=sqrt(distortion/number_channels);
+  /*
+    Free resources.
+  */
+  image_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+    image_statistics);
+  return(1.0-distortion);
+}
+
+static double GetSimilarityMetric(const Image *image,const Image *reference,
+  const ChannelStatistics *reference_statistics,const ssize_t x_offset,
+  const ssize_t y_offset,ExceptionInfo *exception)
+{
+  double
+    distortion;
+
+  Image
+    *similarity_image;
+
+  RectangleInfo
+    geometry;
+
+  SetGeometry(reference,&geometry);
+  geometry.x=x_offset;
+  geometry.y=y_offset;
+  similarity_image=CropImage(image,&geometry,exception);
+  if (similarity_image == (Image *) NULL)
+    return(0.0);
+  distortion=GetNCCDistortion(reference,similarity_image,reference_statistics,
+    exception);
+  similarity_image=DestroyImage(similarity_image);
+  return(distortion);
+}
+
+MagickExport Image *SimilarityImage(Image *image,const Image *reference,
+  RectangleInfo *offset,double *similarity_metric,ExceptionInfo *exception)
+{
+#define SimilarityImageTag  "Similarity/Image"
+
+  CacheView
+    *similarity_view;
+
+  ChannelStatistics
+    *reference_statistics;
+
+  Image
+    *similarity_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert(offset != (RectangleInfo *) NULL);
+  SetGeometry(reference,offset);
+  *similarity_metric=1.0;
+  if ((reference->columns > image->columns) || (reference->rows > image->rows))
+    ThrowImageException(ImageError,"ImageSizeDiffers");
+  similarity_image=CloneImage(image,image->columns-reference->columns+1,
+    image->rows-reference->rows+1,MagickTrue,exception);
+  if (similarity_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(similarity_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&similarity_image->exception);
+      similarity_image=DestroyImage(similarity_image);
+      return((Image *) NULL);
+    }
+  /*
+    Measure similarity of reference image against image.
+  */
+  status=MagickTrue;
+  progress=0;
+  reference_statistics=GetImageChannelStatistics(reference,exception);
+  similarity_view=AcquireCacheView(similarity_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) (image->rows-reference->rows+1); y++)
+  {
+    double
+      similarity;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(similarity_view,0,y,similarity_image->columns,
+      1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) (image->columns-reference->columns+1); x++)
+    {
+      similarity=GetSimilarityMetric(image,reference,reference_statistics,x,y,
+        exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SimilarityImage)
+#endif
+      if (similarity < *similarity_metric)
+        {
+          *similarity_metric=similarity;
+          offset->x=x;
+          offset->y=y;
+        }
+      SetPixelRed(similarity_image,ClampToQuantum(QuantumRange-
+        QuantumRange*similarity),q);
+      SetPixelGreen(similarity_image,GetPixelRed(image,q),q);
+      SetPixelBlue(similarity_image,GetPixelRed(image,q),q);
+      q+=GetPixelChannels(similarity_image);
+    }
+    if (SyncCacheViewAuthenticPixels(similarity_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SimilarityImage)
+#endif
+        proceed=SetImageProgress(image,SimilarityImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  similarity_view=DestroyCacheView(similarity_view);
+  reference_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+    reference_statistics);
+  return(similarity_image);
+}
diff --git a/MagickCore/compare.h b/MagickCore/compare.h
new file mode 100644
index 0000000..bccb133
--- /dev/null
+++ b/MagickCore/compare.h
@@ -0,0 +1,64 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image compare methods.
+*/
+#ifndef _MAGICKCORE_COMPARE_H
+#define _MAGICKCORE_COMPARE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/image.h"
+
+typedef enum
+{
+  UndefinedMetric,
+  AbsoluteErrorMetric,
+  MeanAbsoluteErrorMetric,
+  MeanErrorPerPixelMetric,
+  MeanSquaredErrorMetric,
+  PeakAbsoluteErrorMetric,
+  PeakSignalToNoiseRatioMetric,
+  RootMeanSquaredErrorMetric,
+  NormalizedCrossCorrelationErrorMetric,
+  FuzzErrorMetric
+} MetricType;
+
+extern MagickExport double
+  *GetImageChannelDistortions(Image *,const Image *,const MetricType,
+    ExceptionInfo *);
+
+extern MagickExport Image
+  *CompareImageChannels(Image *,const Image *,const ChannelType,
+    const MetricType,double *,ExceptionInfo *),
+  *CompareImages(Image *,const Image *,const MetricType,double *,
+    ExceptionInfo *),
+  *SimilarityImage(Image *,const Image *,RectangleInfo *,double *,
+    ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  GetImageChannelDistortion(Image *,const Image *,const ChannelType,
+    const MetricType,double *,ExceptionInfo *),
+  GetImageDistortion(Image *,const Image *,const MetricType,double *,
+    ExceptionInfo *),
+  IsImagesEqual(Image *,const Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/composite-private.h b/MagickCore/composite-private.h
new file mode 100644
index 0000000..745c617
--- /dev/null
+++ b/MagickCore/composite-private.h
@@ -0,0 +1,177 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image composite private methods.
+*/
+#ifndef _MAGICKCORE_COMPOSITE_PRIVATE_H
+#define _MAGICKCORE_COMPOSITE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+  ImageMagick Alpha Composite Inline Methods (special export)
+*/
+
+#include "MagickCore/color.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/pixel-accessor.h"
+
+static inline MagickRealType MagickOver_(const MagickRealType p,
+  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
+{
+  MagickRealType
+    Da,
+    Sa;
+
+  Sa=QuantumScale*alpha;
+  Da=QuantumScale*beta;
+  return(Sa*p-Sa*Da*q+Da*q);
+}
+
+static inline void CompositePixelOver(const Image *image,const PixelPacket *p,
+  const MagickRealType alpha,const Quantum *q,const MagickRealType beta,
+  Quantum *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  /*
+    Compose pixel p over pixel q with the given opacities.
+  */
+  if (alpha == TransparentAlpha)
+    {
+      if (composite != q)
+        {
+          SetPixelRed(image,GetPixelRed(image,q),composite);
+          SetPixelGreen(image,GetPixelGreen(image,q),composite);
+          SetPixelBlue(image,GetPixelBlue(image,q),composite);
+          SetPixelAlpha(image,GetPixelAlpha(image,q),composite);
+        }
+      return;
+    }
+  Sa=QuantumScale*alpha;
+  Da=QuantumScale*beta,
+  gamma=Sa*(-Da)+Sa+Da;
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  SetPixelAlpha(image,(Quantum) (QuantumRange*gamma+0.5),composite);
+  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+  SetPixelRed(image,(Quantum) (gamma*MagickOver_((MagickRealType) p->red,
+    alpha,(MagickRealType) GetPixelRed(image,q),beta)+0.5),composite);
+  SetPixelGreen(image,(Quantum) (gamma*MagickOver_((MagickRealType) p->green,
+    alpha,(MagickRealType) GetPixelGreen(image,q),beta)+0.5),composite);
+  SetPixelBlue(image,(Quantum) (gamma*MagickOver_((MagickRealType) p->blue,
+    alpha,(MagickRealType) GetPixelBlue(image,q),beta)+0.5),composite);
+#else
+  SetPixelAlpha(image,QuantumRange*gamma,composite);
+  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+  SetPixelRed(image,(Quantum) (gamma*MagickOver_((MagickRealType) p->red,
+    alpha,(MagickRealType) GetPixelRed(image,q),beta)),composite);
+  SetPixelGreen(image,(Quantum) (gamma*MagickOver_((MagickRealType) p->green,
+    alpha,(MagickRealType) GetPixelGreen(image,q),beta)),composite);
+  SetPixelBlue(image,(Quantum) (gamma*MagickOver_((MagickRealType) p->blue,
+    alpha,(MagickRealType) GetPixelBlue(image,q),beta)),composite);
+#endif
+}
+
+static inline void CompositePixelInfoOver(const PixelInfo *p,
+  const MagickRealType alpha,const PixelInfo *q,const MagickRealType beta,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  /*
+    Compose pixel p over pixel q with the given opacities.
+  */
+  if (alpha == OpaqueAlpha)
+    {
+      *composite=(*p);
+      return;
+    }
+  Sa=QuantumScale*alpha;
+  Da=QuantumScale*beta,
+  gamma=Sa*(-Da)+Sa+Da;
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
+  composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
+  composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
+}
+
+static inline MagickRealType RoundToUnity(const MagickRealType value)
+{
+  return(value < 0.0 ? 0.0 : (value > 1.0) ? 1.0 : value);
+}
+
+static inline void CompositePixelInfoPlus(const PixelInfo *p,
+  const MagickRealType alpha,const PixelInfo *q,const MagickRealType beta,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  /*
+    Add two pixels with the given opacities.
+  */
+  Sa=QuantumScale*alpha;
+  Da=QuantumScale*beta;
+  gamma=RoundToUnity(Sa+Da);  /* 'Plus' blending -- not 'Over' blending */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*(Sa*p->red+Da*q->red);
+  composite->green=gamma*(Sa*p->green+Da*q->green);
+  composite->blue=gamma*(Sa*p->blue+Da*q->blue);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*(Sa*p->black+Da*q->black);
+}
+
+static inline void CompositePixelInfoAreaBlend(const PixelInfo *p,
+  const MagickRealType alpha,const PixelInfo *q,const MagickRealType beta,
+  const MagickRealType area,PixelInfo *composite)
+{
+  /*
+    Blend pixel colors p and q by the amount given and area.
+  */
+  CompositePixelInfoPlus(p,(MagickRealType) (1.0-area)*alpha,q,(MagickRealType)
+    (area*beta),composite);
+}
+
+static inline void CompositePixelInfoBlend(const PixelInfo *p,
+  const MagickRealType alpha,const PixelInfo *q,const MagickRealType beta,
+  PixelInfo *composite)
+{
+  /*
+    Blend pixel colors p and q by the amount given.
+  */
+  CompositePixelInfoPlus(p,(MagickRealType) (alpha*p->alpha),q,(MagickRealType)
+    (beta*q->alpha),composite);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/composite.c b/MagickCore/composite.c
new file mode 100644
index 0000000..428d827
--- /dev/null
+++ b/MagickCore/composite.c
@@ -0,0 +1,2922 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        CCCC   OOO   M   M  PPPP    OOO   SSSSS  IIIII  TTTTT  EEEEE         %
+%       C      O   O  MM MM  P   P  O   O  SS       I      T    E             %
+%       C      O   O  M M M  PPPP   O   O   SSS     I      T    EEE           %
+%       C      O   O  M   M  P      O   O     SS    I      T    E             %
+%        CCCC   OOO   M   M  P       OOO   SSSSS  IIIII    T    EEEEE         %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Composite Methods                      %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p o s i t e I m a g e C h a n n e l                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompositeImageChannel() returns the second image composited onto the first
+%  at the specified offset, using the specified composite method.
+%
+%  The format of the CompositeImageChannel method is:
+%
+%      MagickBooleanType CompositeImage(Image *image,
+%        const CompositeOperator compose,Image *composite_image,
+%        const ssize_t x_offset,const ssize_t y_offset)
+%      MagickBooleanType CompositeImageChannel(Image *image,
+%        const ChannelType channel,const CompositeOperator compose,
+%        Image *composite_image,const ssize_t x_offset,const ssize_t y_offset)
+%
+%  A description of each parameter follows:
+%
+%    o image: the destination image, modified by he composition
+%
+%    o channel: the channel.
+%
+%    o compose: This operator affects how the composite is applied to
+%      the image.  The operators and how they are utilized are listed here
+%      http://www.w3.org/TR/SVG12/#compositing.
+%
+%    o composite_image: the composite (source) image.
+%
+%    o x_offset: the column offset of the composited image.
+%
+%    o y_offset: the row offset of the composited image.
+%
+%  Extra Controls from Image meta-data in 'composite_image' (artifacts)
+%
+%    o "compose:args"
+%        A string containing extra numerical arguments for specific compose
+%        methods, generally expressed as a 'geometry' or a comma separated list
+%        of numbers.
+%
+%        Compose methods needing such arguments include "BlendCompositeOp" and
+%        "DisplaceCompositeOp".
+%
+%    o "compose:outside-overlay"
+%        Modify how the composition is to effect areas not directly covered
+%        by the 'composite_image' at the offset given.  Normally this is
+%        dependant on the 'compose' method, especially Duff-Porter methods.
+%
+%        If set to "false" then disable all normal handling of pixels not
+%        covered by the composite_image.  Typically used for repeated tiling
+%        of the composite_image by the calling API.
+%
+%        Previous to IM v6.5.3-3  this was called "modify-outside-overlay"
+%
+*/
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+/*
+   Programmers notes on SVG specification.
+  
+   A Composition is defined by...
+     Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
+      Blending areas :  X = 1    for area of overlap   ie: f(Sc,Dc)
+                        Y = 1    for source preserved
+                        Z = 1    for destination preserved
+  
+   Conversion to transparency (then optimized)
+      Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
+      Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
+  
+   Where...
+     Sca = Sc*Sa     normalized Source color divided by Source alpha
+     Dca = Dc*Da     normalized Dest color divided by Dest alpha
+     Dc' = Dca'/Da'  the desired color value for this channel.
+  
+   Da' in in the follow formula as 'gamma'  The resulting alpla value.
+  
+   Most functions use a blending mode of over (X=1,Y=1,Z=1)
+   this results in the following optimizations...
+     gamma = Sa+Da-Sa*Da;
+     gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
+     opacity = QuantiumScale*alpha*beta;  // over blend, optimized 1-Gamma
+  
+   The above SVG definitions also definate that Mathematical Composition
+   methods should use a 'Over' blending mode for Alpha Channel.
+   It however was not applied for composition modes of 'Plus', 'Minus',
+   the modulus versions of 'Add' and 'Subtract'.
+  
+   Mathematical operator changes to be applied from IM v6.7...
+  
+    1/ Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
+       'ModulusAdd' and 'ModulusSubtract' for clarity.
+  
+    2/ All mathematical compositions work as per the SVG specification
+       with regard to blending.  This now includes 'ModulusAdd' and
+       'ModulusSubtract'.
+  
+    3/ When the special channel flag 'sync' (syncronize channel updates)
+       is turned off (enabled by default) then mathematical compositions are
+       only performed on the channels specified, and are applied
+       independantally of each other.  In other words the mathematics is
+       performed as 'pure' mathematical operations, rather than as image
+       operations.
+*/
+
+static inline MagickRealType Atop(const MagickRealType p,
+  const MagickRealType Sa,const MagickRealType q,
+  const MagickRealType magick_unused(Da))
+{
+  return(p*Sa+q*(1.0-Sa));  /* Da optimized out,  Da/gamma => 1.0 */
+}
+
+static inline void CompositeAtop(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  composite->alpha=q->alpha;   /* optimized  Da = 1.0-Gamma */
+  composite->red=Atop(p->red,Sa,q->red,1.0);
+  composite->green=Atop(p->green,Sa,q->green,1.0);
+  composite->blue=Atop(p->blue,Sa,q->blue,1.0);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=Atop(p->black,Sa,q->black,1.0);
+}
+
+/*
+  What is this Composition method for? Can't find any specification!
+  WARNING this is not doing correct 'over' blend handling (Anthony Thyssen).
+*/
+static inline void CompositeBumpmap(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    intensity;
+
+  intensity=(MagickRealType) GetPixelInfoIntensity(p);
+  composite->red=QuantumScale*intensity*q->red;
+  composite->green=QuantumScale*intensity*q->green;
+  composite->blue=QuantumScale*intensity*q->blue;
+  composite->alpha=(MagickRealType) QuantumScale*intensity*p->alpha;
+  if (q->colorspace == CMYKColorspace)
+    composite->black=QuantumScale*intensity*q->black;
+}
+
+static inline void CompositeClear(const PixelInfo *q,PixelInfo *composite)
+{
+  composite->alpha=(MagickRealType) TransparentAlpha;
+  composite->red=0.0;
+  composite->green=0.0;
+  composite->blue=0.0;
+  if (q->colorspace == CMYKColorspace)
+    composite->black=0.0;
+}
+
+static MagickRealType ColorBurn(const MagickRealType Sca,
+  const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
+{
+  if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
+    return(Sa*Da+Dca*(1.0-Sa));
+  if (Sca < MagickEpsilon)
+    return(Dca*(1.0-Sa));
+  return(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeColorBurn(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*ColorBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*ColorBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*ColorBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*ColorBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+
+static MagickRealType ColorDodge(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    Working from first principles using the original formula:
+
+       f(Sc,Dc) = Dc/(1-Sc)
+
+    This works correctly!  Looks like the 2004 SVG model was right but just
+    required a extra condition for correct handling.
+  */
+  if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
+    return(Sca*(1.0-Da)+Dca*(1.0-Sa));
+  if (fabs(Sca-Sa) < MagickEpsilon)
+    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeColorDodge(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*ColorDodge(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*ColorDodge(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*ColorDodge(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*ColorDodge(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static inline MagickRealType Darken(const MagickRealType p,
+  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
+{
+  if (p < q)
+    return(MagickOver_(p,alpha,q,beta));  /* src-over */
+  return(MagickOver_(q,beta,p,alpha));    /* dst-over */
+}
+
+static inline void CompositeDarken(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    gamma;
+
+  /*
+    Darken is equivalent to a 'Minimum' method OR a greyscale version of a
+    binary 'Or' OR the 'Intersection' of pixel sets.
+  */
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=MagickMin(p->red,q->red);
+      if ((channel & GreenChannel) != 0)
+        composite->green=MagickMin(p->green,q->green);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=MagickMin(p->blue,q->blue);
+      if ((channel & BlackChannel) != 0 &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=MagickMin(p->black,q->black);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=MagickMax(p->alpha,q->alpha);
+      return;
+    }
+  composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
+  gamma=1.0-QuantumScale*composite->alpha;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Darken(p->red,p->alpha,q->red,q->alpha);
+  composite->green=gamma*Darken(p->green,p->alpha,q->green,q->alpha);
+  composite->blue=gamma*Darken(p->blue,p->alpha,q->blue,q->alpha);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Darken(p->black,p->alpha,q->black,q->alpha);
+}
+
+static inline void CompositeDarkenIntensity(const PixelInfo *p,
+  const PixelInfo *q,const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    Sa;
+
+  /*
+    Select the pixel based on the intensity level.
+    If 'Sync' flag select whole pixel based on alpha weighted intensity.
+    Otherwise use intensity only, but restrict copy according to channel.
+  */
+  if ((channel & SyncChannels) == 0)
+    {
+      MagickBooleanType
+        from_p;
+
+      from_p=GetPixelInfoIntensity(p) < GetPixelInfoIntensity(q) ? MagickTrue :
+        MagickFalse;
+      if ((channel & RedChannel) != 0)
+        composite->red=from_p != MagickFalse ? p->red : q->red;
+      if ((channel & GreenChannel) != 0)
+        composite->green=from_p != MagickFalse ? p->green : q->green;
+      if ((channel & BlueChannel) != 0)
+        composite->blue=from_p != MagickFalse ? p->blue : q->blue;
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=from_p != MagickFalse ? p->black : q->black;
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
+      return;
+    }
+  Sa=QuantumScale*p->alpha;
+  Da=QuantumScale*q->alpha;
+  *composite=(Sa*GetPixelInfoIntensity(p) < Da*GetPixelInfoIntensity(q)) ?
+    *p : *q;
+}
+
+static inline MagickRealType Difference(const MagickRealType p,
+  const MagickRealType Sa,const MagickRealType q,const MagickRealType Da)
+{
+  /*
+    Optimized by Multipling by QuantumRange (taken from gamma).
+  */
+  return(Sa*p+Da*q-Sa*Da*2.0*MagickMin(p,q));
+}
+
+static inline void CompositeDifference(const PixelInfo *p,
+  const PixelInfo *q,const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=fabs((double) (p->red-q->red));
+      if ((channel & GreenChannel) != 0)
+        composite->green=fabs((double) (p->green-q->green));
+      if ((channel & BlueChannel) != 0)
+        composite->blue=fabs((double) (p->blue-q->blue));
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=fabs((double) (p->black-q->black));
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=fabs((double) (p->alpha-q->alpha));
+     return;
+   }
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Difference(p->red,Sa,q->red,Da);
+  composite->green=gamma*Difference(p->green,Sa,q->green,Da);
+  composite->blue=gamma*Difference(p->blue,Sa,q->blue,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Difference(p->black,Sa,q->black,Da);
+}
+
+static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
+  const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    Divide Source by Destination
+
+      f(Sc,Dc) = Sc / Dc
+
+    But with appropriate handling for special case of Dc == 0 specifically
+    so that   f(Black,Black)=Black  and  f(non-Black,Black)=White.
+    It is however also important to correctly do 'over' alpha blending which
+    is why the formula becomes so complex.
+  */
+  if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
+    return(Sca*(1.0-Da)+Dca*(1.0-Sa));
+  if (fabs(Dca) < MagickEpsilon)
+    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeDivide(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=QuantumRange*Divide(QuantumScale*p->red,1.0,
+          QuantumScale*q->red,1.0);
+      if ((channel & GreenChannel) != 0)
+        composite->green=QuantumRange*Divide(QuantumScale*p->green,1.0,
+          QuantumScale*q->green,1.0);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=QuantumRange*Divide(QuantumScale*p->blue,1.0,
+          QuantumScale*q->blue,1.0);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=QuantumRange*Divide(QuantumScale*p->black,1.0,
+          QuantumScale*q->black,1.0);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=QuantumRange*(1.0-Divide(Sa,1.0,Da,1.0));
+      return;
+    }
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Divide(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*Divide(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*Divide(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Divide(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static MagickRealType Exclusion(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  return(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeExclusion(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    gamma,
+    Sa,
+    Da;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=QuantumRange*Exclusion(QuantumScale*p->red,1.0,
+          QuantumScale*q->red,1.0);
+      if ((channel & GreenChannel) != 0)
+        composite->green=QuantumRange*Exclusion(QuantumScale*p->green,1.0,
+          QuantumScale*q->green,1.0);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=QuantumRange*Exclusion(QuantumScale*p->blue,1.0,
+          QuantumScale*q->blue,1.0);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=QuantumRange*Exclusion(QuantumScale*p->black,1.0,
+          QuantumScale*q->black,1.0);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=QuantumRange*(1.0-Exclusion(Sa,1.0,Da,1.0));
+      return;
+    }
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Exclusion(QuantumScale*p->black*Sa,Sa,
+      QuantumScale*q->black*Da,Da);
+}
+
+static MagickRealType HardLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  if ((2.0*Sca) < Sa)
+    return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeHardLight(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*HardLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static void CompositeHSB(const MagickRealType red,const MagickRealType green,
+  const MagickRealType blue,double *hue,double *saturation,double *brightness)
+{
+  MagickRealType
+    delta,
+    max,
+    min;
+
+  /*
+    Convert RGB to HSB colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(saturation != (double *) NULL);
+  assert(brightness != (double *) NULL);
+  max=(red > green ? red : green);
+  if (blue > max)
+    max=blue;
+  min=(red < green ? red : green);
+  if (blue < min)
+    min=blue;
+  *hue=0.0;
+  *saturation=0.0;
+  *brightness=(double) (QuantumScale*max);
+  if (max == 0.0)
+    return;
+  *saturation=(double) (1.0-min/max);
+  delta=max-min;
+  if (delta == 0.0)
+    return;
+  if (red == max)
+    *hue=(double) ((green-blue)/delta);
+  else
+    if (green == max)
+      *hue=(double) (2.0+(blue-red)/delta);
+    else
+      if (blue == max)
+        *hue=(double) (4.0+(red-green)/delta);
+  *hue/=6.0;
+  if (*hue < 0.0)
+    *hue+=1.0;
+}
+
+static inline MagickRealType In(const MagickRealType p,const MagickRealType Sa,
+  const MagickRealType magick_unused(q),const MagickRealType Da)
+{
+  return(Sa*p*Da);
+}
+
+static inline void CompositeIn(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    gamma,
+    Sa,
+    Da;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=Sa*Da;
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*In(p->red,Sa,q->red,Da);
+  composite->green=gamma*In(p->green,Sa,q->green,Da);
+  composite->blue=gamma*In(p->blue,Sa,q->blue,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*In(p->black,Sa,q->black,Da);
+}
+
+static inline MagickRealType Lighten(const MagickRealType p,
+  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
+{
+   if (p > q)
+     return(MagickOver_(p,alpha,q,beta));  /* src-over */
+   return(MagickOver_(q,beta,p,alpha));    /* dst-over */
+}
+
+static inline void CompositeLighten(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    gamma;
+
+  /*
+    Lighten is also equvalent to a 'Maximum' method OR a greyscale version of a
+    binary 'And' OR the 'Union' of pixel sets.
+  */
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=MagickMax(p->red,q->red);
+      if ((channel & GreenChannel) != 0)
+        composite->green=MagickMax(p->green,q->green);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=MagickMax(p->blue,q->blue);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=MagickMax(p->black,q->black);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=MagickMin(p->alpha,q->alpha);
+      return;
+    }
+  composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
+  gamma=1.0-QuantumScale*composite->alpha;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Lighten(p->red,p->alpha,q->red,q->alpha);
+  composite->green=gamma*Lighten(p->green,p->alpha,q->green,q->alpha);
+  composite->blue=gamma*Lighten(p->blue,p->alpha,q->blue,q->alpha);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Lighten(p->black,p->alpha,q->black,q->alpha);
+}
+
+static inline void CompositeLightenIntensity(const PixelInfo *p,
+  const PixelInfo *q,const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    Sa;
+
+  /*
+    Select the pixel based on the intensity level.
+    If 'Sync' flag select whole pixel based on alpha weighted intensity.
+    Otherwise use Intenisty only, but restrict copy according to channel.
+  */
+  if ((channel & SyncChannels) == 0)
+    {
+      MagickBooleanType
+        from_p;
+
+      from_p=GetPixelInfoIntensity(p) > GetPixelInfoIntensity(q) ? MagickTrue :
+        MagickFalse;
+      if ((channel & RedChannel) != 0)
+        composite->red=from_p != MagickFalse ? p->red : q->red;
+      if ((channel & GreenChannel) != 0)
+        composite->green=from_p != MagickFalse ? p->green : q->green;
+      if ((channel & BlueChannel) != 0)
+        composite->blue=from_p != MagickFalse ? p->blue : q->blue;
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=from_p != MagickFalse ? p->black : q->black;
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
+      return;
+    }
+  Sa=QuantumScale*p->alpha;
+  Da=QuantumScale*q->alpha;
+  *composite=(Sa*GetPixelInfoIntensity(p) > Da*GetPixelInfoIntensity(q)) ?
+    *p : *q;
+}
+
+static inline void CompositeLinearDodge(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*(p->red*Sa+q->red*Da);
+  composite->green=gamma*(p->green*Sa+q->green*Da);
+  composite->blue=gamma*(p->blue*Sa+q->blue*Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*(p->black*Sa+q->black*Da);
+}
+
+
+static inline MagickRealType LinearBurn(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    LinearBurn: as defined by Abode Photoshop, according to
+    http://www.simplefilter.de/en/basics/mixmods.html is:
+
+      f(Sc,Dc) = Sc + Dc - 1
+  */
+  return(Sca+Dca-Sa*Da);
+}
+
+static inline void CompositeLinearBurn(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*LinearBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static inline MagickRealType LinearLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    LinearLight: as defined by Abode Photoshop, according to
+    http://www.simplefilter.de/en/basics/mixmods.html is:
+
+      f(Sc,Dc) = Dc + 2*Sc - 1
+  */
+  return((Sca-Sa)*Da+Sca+Dca);
+}
+
+static inline void CompositeLinearLight(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*LinearLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*LinearLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*LinearLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*LinearLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static inline MagickRealType Mathematics(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
+  const GeometryInfo *geometry_info)
+{
+  MagickRealType
+    gamma;
+
+  /*
+    'Mathematics' a free form user control mathematical composition is defined
+    as...
+
+       f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
+
+    Where the arguments A,B,C,D are (currently) passed to composite as
+    a command separated 'geometry' string in "compose:args" image artifact.
+
+       A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
+
+    Applying the SVG transparency formula (see above), we get...
+
+     Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
+
+     Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
+       Dca*(1.0-Sa)
+  */
+  gamma=geometry_info->rho*Sca*Dca+geometry_info->sigma*Sca*Da+
+    geometry_info->xi*Dca*Sa+geometry_info->psi*Sa*Da+Sca*(1.0-Da)+
+    Dca*(1.0-Sa);
+  return(gamma);
+}
+
+static inline void CompositeMathematics(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel, const GeometryInfo *args, PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha; /* ??? - AT */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=QuantumRange*Mathematics(QuantumScale*p->red,1.0,
+          QuantumScale*q->red,1.0,args);
+      if ((channel & GreenChannel) != 0)
+        composite->green=QuantumRange*Mathematics(QuantumScale*p->green,1.0,
+          QuantumScale*q->green,1.0,args);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=QuantumRange*Mathematics(QuantumScale*p->blue,1.0,
+          QuantumScale*q->blue,1.0,args);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=QuantumRange*Mathematics(QuantumScale*p->black,1.0,
+          QuantumScale*q->black,1.0,args);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=QuantumRange*(1.0-Mathematics(Sa,1.0,Da,1.0,args));
+      return;
+    }
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Mathematics(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da,args);
+  composite->green=gamma*Mathematics(QuantumScale*p->green*Sa,Sa,
+    QuantumScale*q->green*Da,Da,args);
+  composite->blue=gamma*Mathematics(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da,args);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Mathematics(QuantumScale*p->black*Sa,Sa,
+      QuantumScale*q->black*Da,Da,args);
+}
+
+static inline void CompositePlus(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  /*
+    NOTE: "Plus" does not use 'over' alpha-blending but uses a special
+    'plus' form of alph-blending. It is the ONLY mathematical operator to
+    do this. this is what makes it different to the otherwise equivalent
+    "LinearDodge" composition method.
+
+    Note however that color channels are still effected by the alpha channel
+    as a result of the blending, making it just as useless for independant
+    channel maths, just like all other mathematical composition methods.
+
+    As such the removal of the 'sync' flag, is still a usful convention.
+
+    The CompositePixelInfoPlus() function is defined in
+    "composite-private.h" so it can also be used for Image Blending.
+  */
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=p->red+q->red;
+      if ((channel & GreenChannel) != 0)
+        composite->green=p->green+q->green;
+      if ((channel & BlueChannel) != 0)
+        composite->blue=p->blue+q->blue;
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=p->black+q->black;
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=p->alpha+q->alpha-QuantumRange;
+      return;
+    }
+  CompositePixelInfoPlus(p,p->alpha,q,q->alpha,composite);
+}
+
+static inline MagickRealType Minus(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,
+  const MagickRealType magick_unused(Da))
+{
+  /*
+    Minus Source from Destination
+
+      f(Sc,Dc) = Sc - Dc
+  */
+  return(Sca+Dca-2.0*Dca*Sa);
+}
+
+static inline void CompositeMinus(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=p->red-q->red;
+      if ((channel & GreenChannel) != 0)
+        composite->green=p->green-q->green;
+      if ((channel & BlueChannel) != 0)
+        composite->blue=p->blue-q->blue;
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=p->black-q->black;
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=QuantumRange*(1.0-(Sa-Da));
+      return;
+    }
+  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Minus(p->red*Sa,Sa,q->red*Da,Da);
+  composite->green=gamma*Minus(p->green*Sa,Sa,q->green*Da,Da);
+  composite->blue=gamma*Minus(p->blue*Sa,Sa,q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Minus(p->black*Sa,Sa,q->black*Da,Da);
+}
+
+static inline MagickRealType ModulusAdd(const MagickRealType p,
+  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
+{
+  MagickRealType
+    pixel;
+
+  pixel=p+q;
+  if (pixel > QuantumRange)
+    pixel-=(QuantumRange+1.0);
+  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
+}
+
+static inline void CompositeModulusAdd(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=ModulusAdd(p->red,1.0,q->red,1.0);
+      if ((channel & GreenChannel) != 0)
+        composite->green=ModulusAdd(p->green,1.0,q->green,1.0);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=ModulusAdd(p->blue,1.0,q->blue,1.0);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=ModulusAdd(p->black,1.0,q->black,1.0);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=ModulusAdd(p->alpha,1.0,q->alpha,1.0);
+      return;
+    }
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=ModulusAdd(p->red,Sa,q->red,Da);
+  composite->green=ModulusAdd(p->green,Sa,q->green,Da);
+  composite->blue=ModulusAdd(p->blue,Sa,q->blue,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=ModulusAdd(p->black,Sa,q->black,Da);
+}
+
+static inline MagickRealType ModulusSubtract(const MagickRealType p,
+  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
+{
+  MagickRealType
+    pixel;
+
+  pixel=p-q;
+  if (pixel < 0.0)
+    pixel+=(QuantumRange+1.0);
+  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
+}
+
+static inline void CompositeModulusSubtract(const PixelInfo *p,
+  const PixelInfo *q, const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels,
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=ModulusSubtract(p->red,1.0,q->red,1.0);
+      if ((channel & GreenChannel) != 0)
+        composite->green=ModulusSubtract(p->green,1.0,q->green,1.0);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=ModulusSubtract(p->blue,1.0,q->blue,1.0);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=ModulusSubtract(p->black,1.0,q->black,1.0);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=ModulusSubtract(p->alpha,1.0,q->alpha,1.0);
+      return;
+    }
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma = RoundToUnity(Sa+Da-Sa*Da);
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=ModulusSubtract(p->red,Sa,q->red,Da);
+  composite->green=ModulusSubtract(p->green,Sa,q->green,Da);
+  composite->blue=ModulusSubtract(p->blue,Sa,q->blue,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=ModulusSubtract(p->black,Sa,q->black,Da);
+}
+
+static  inline MagickRealType Multiply(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  return(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeMultiply(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=QuantumScale*p->red*q->red;
+      if ((channel & GreenChannel) != 0)
+        composite->green=QuantumScale*p->green*q->green;
+      if ((channel & BlueChannel) != 0)
+        composite->blue=QuantumScale*p->blue*q->blue;
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=QuantumScale*p->black*q->black;
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=QuantumRange*(1.0-Sa*Da);
+      return;
+    }
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Multiply(QuantumScale*p->black*Sa,Sa,
+      QuantumScale*q->black*Da,Da);
+}
+
+static inline MagickRealType Out(const MagickRealType p,const MagickRealType Sa,
+  const MagickRealType magick_unused(q),const MagickRealType Da)
+{
+  return(Sa*p*(1.0-Da));
+}
+
+static inline void CompositeOut(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Sa,
+    Da,
+    gamma;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=Sa*(1.0-Da);
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Out(p->red,Sa,q->red,Da);
+  composite->green=gamma*Out(p->green,Sa,q->green,Da);
+  composite->blue=gamma*Out(p->blue,Sa,q->blue,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Out(p->black,Sa,q->black,Da);
+}
+
+static MagickRealType PegtopLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    PegTop: A Soft-Light alternative: A continuous version of the Softlight
+    function, producing very similar results.
+
+    f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
+
+    See http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
+  */
+  if (fabs(Da) < MagickEpsilon)
+    return(Sca);
+  return(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositePegtopLight(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*PegtopLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*PegtopLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*PegtopLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*PegtopLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static MagickRealType PinLight(const MagickRealType Sca,const MagickRealType Sa,
+  const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    PinLight: A Photoshop 7 composition method
+    http://www.simplefilter.de/en/basics/mixmods.html
+
+    f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
+  */
+  if (Dca*Sa < Da*(2.0*Sca-Sa))
+    return(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
+  if ((Dca*Sa) > (2.0*Sca*Da))
+    return(Sca*Da+Sca+Dca*(1.0-Sa));
+  return(Sca*(1.0-Da)+Dca);
+}
+
+static inline void CompositePinLight(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*PinLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*PinLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*PinLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*PinLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static inline MagickRealType Screen(const MagickRealType Sca,
+  const MagickRealType Dca)
+{
+  /*
+    Screen:  A negated multiply
+      f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
+  */
+  return(Sca+Dca-Sca*Dca);
+}
+
+static inline void CompositeScreen(const PixelInfo *p,const PixelInfo *q,
+  const ChannelType channel,PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  if ((channel & SyncChannels) == 0)
+    {
+      /*
+        Handle channels as separate grayscale channels.
+      */
+      if ((channel & RedChannel) != 0)
+        composite->red=QuantumRange*Screen(QuantumScale*p->red,
+          QuantumScale*q->red);
+      if ((channel & GreenChannel) != 0)
+        composite->green=QuantumRange*Screen(QuantumScale*p->green,
+          QuantumScale*q->green);
+      if ((channel & BlueChannel) != 0)
+        composite->blue=QuantumRange*Screen(QuantumScale*p->blue,
+          QuantumScale*q->blue);
+      if (((channel & BlackChannel) != 0) &&
+          (q->colorspace == CMYKColorspace))
+        composite->black=QuantumRange*Screen(QuantumScale*p->black,
+          QuantumScale*q->black);
+      if ((channel & AlphaChannel) != 0)
+        composite->alpha=QuantumRange*(1.0-Screen(Sa,Da));
+      return;
+    }
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  Sa*=QuantumScale; Da*=QuantumScale; /* optimization */
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Screen(p->red*Sa,q->red*Da);
+  composite->green=gamma*Screen(p->green*Sa,q->green*Da);
+  composite->blue=gamma*Screen(p->blue*Sa,q->blue*Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Screen(p->black*Sa,q->black*Da);
+}
+
+static MagickRealType SoftLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  MagickRealType
+    alpha,
+    beta;
+
+  /*
+    New specification:  March 2009 SVG specification.
+  */
+  alpha=Dca/Da;
+  if ((2.0*Sca) < Sa)
+    return(Dca*(Sa+(2.0*Sca-Sa)*(1.0-alpha))+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
+    {
+      beta=Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*alpha*(4.0*alpha+1.0)*(alpha-1.0)+7.0*
+        alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
+      return(beta);
+    }
+  beta=Dca*Sa+Da*(2.0*Sca-Sa)*(pow(alpha,0.5)-alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
+  return(beta);
+}
+
+static inline void CompositeSoftLight(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*SoftLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*SoftLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*SoftLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*SoftLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static inline MagickRealType Threshold(const MagickRealType p,
+  const MagickRealType q,const MagickRealType threshold,
+  const MagickRealType amount)
+{
+  MagickRealType
+    delta;
+
+  /*
+    Multiply difference by amount, if differance larger than threshold???
+    What use this is is completely unknown.  The Opacity calculation appears to
+    be inverted  -- Anthony Thyssen
+
+    Deprecated.
+  */
+  delta=p-q;
+  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
+    return(q);
+  return(q+delta*amount);
+}
+
+static inline void CompositeThreshold(const PixelInfo *p,const PixelInfo *q,
+  const MagickRealType threshold,const MagickRealType amount,
+  PixelInfo *composite)
+{
+  composite->red=Threshold(p->red,q->red,threshold,amount);
+  composite->green=Threshold(p->green,q->green,threshold,amount);
+  composite->blue=Threshold(p->blue,q->blue,threshold,amount);
+  composite->alpha=Threshold(p->alpha,q->alpha,threshold,amount);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=Threshold(p->black,q->black,threshold,amount);
+}
+
+
+static MagickRealType VividLight(const MagickRealType Sca,
+  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+  /*
+    VividLight: A Photoshop 7 composition method.  See
+    http://www.simplefilter.de/en/basics/mixmods.html.
+
+    f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
+  */
+  if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
+    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  if ((2.0*Sca) <= Sa)
+    return(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
+  return(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeVividLight(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*VividLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
+    q->red*Da,Da);
+  composite->green=gamma*VividLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
+    q->green*Da,Da);
+  composite->blue=gamma*VividLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+    q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*VividLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
+      q->black*Da,Da);
+}
+
+static MagickRealType Xor(const MagickRealType Sca,const MagickRealType Sa,
+  const MagickRealType Dca,const MagickRealType Da)
+{
+  return(Sca*(1.0-Da)+Dca*(1.0-Sa));
+}
+
+static inline void CompositeXor(const PixelInfo *p,const PixelInfo *q,
+  PixelInfo *composite)
+{
+  MagickRealType
+    Da,
+    gamma,
+    Sa;
+
+  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
+  Da=QuantumScale*q->alpha;
+  gamma=Sa+Da-2.0*Sa*Da;        /* Xor blend mode X=0,Y=1,Z=1 */
+  composite->alpha=(MagickRealType) QuantumRange*gamma;
+  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+  composite->red=gamma*Xor(p->red*Sa,Sa,q->red*Da,Da);
+  composite->green=gamma*Xor(p->green*Sa,Sa,q->green*Da,Da);
+  composite->blue=gamma*Xor(p->blue*Sa,Sa,q->blue*Da,Da);
+  if (q->colorspace == CMYKColorspace)
+    composite->black=gamma*Xor(p->black*Sa,Sa,q->black*Da,Da);
+}
+
+static void HSBComposite(const double hue,const double saturation,
+  const double brightness,MagickRealType *red,MagickRealType *green,
+  MagickRealType *blue)
+{
+  MagickRealType
+    f,
+    h,
+    p,
+    q,
+    t;
+
+  /*
+    Convert HSB to RGB colorspace.
+  */
+  assert(red != (MagickRealType *) NULL);
+  assert(green != (MagickRealType *) NULL);
+  assert(blue != (MagickRealType *) NULL);
+  if (saturation == 0.0)
+    {
+      *red=(MagickRealType) QuantumRange*brightness;
+      *green=(*red);
+      *blue=(*red);
+      return;
+    }
+  h=6.0*(hue-floor(hue));
+  f=h-floor((double) h);
+  p=brightness*(1.0-saturation);
+  q=brightness*(1.0-saturation*f);
+  t=brightness*(1.0-saturation*(1.0-f));
+  switch ((int) h)
+  {
+    case 0:
+    default:
+    {
+      *red=(MagickRealType) QuantumRange*brightness;
+      *green=(MagickRealType) QuantumRange*t;
+      *blue=(MagickRealType) QuantumRange*p;
+      break;
+    }
+    case 1:
+    {
+      *red=(MagickRealType) QuantumRange*q;
+      *green=(MagickRealType) QuantumRange*brightness;
+      *blue=(MagickRealType) QuantumRange*p;
+      break;
+    }
+    case 2:
+    {
+      *red=(MagickRealType) QuantumRange*p;
+      *green=(MagickRealType) QuantumRange*brightness;
+      *blue=(MagickRealType) QuantumRange*t;
+      break;
+    }
+    case 3:
+    {
+      *red=(MagickRealType) QuantumRange*p;
+      *green=(MagickRealType) QuantumRange*q;
+      *blue=(MagickRealType) QuantumRange*brightness;
+      break;
+    }
+    case 4:
+    {
+      *red=(MagickRealType) QuantumRange*t;
+      *green=(MagickRealType) QuantumRange*p;
+      *blue=(MagickRealType) QuantumRange*brightness;
+      break;
+    }
+    case 5:
+    {
+      *red=(MagickRealType) QuantumRange*brightness;
+      *green=(MagickRealType) QuantumRange*p;
+      *blue=(MagickRealType) QuantumRange*q;
+      break;
+    }
+  }
+}
+
+MagickExport MagickBooleanType CompositeImage(Image *image,
+  const CompositeOperator compose,const Image *composite_image,
+  const ssize_t x_offset,const ssize_t y_offset)
+{
+  MagickBooleanType
+    status;
+
+  status=CompositeImageChannel(image,DefaultChannels,compose,composite_image,
+    x_offset,y_offset);
+  return(status);
+}
+
+MagickExport MagickBooleanType CompositeImageChannel(Image *image,
+  const ChannelType channel,const CompositeOperator compose,
+  const Image *composite_image,const ssize_t x_offset,const ssize_t y_offset)
+{
+#define CompositeImageTag  "Composite/Image"
+
+  CacheView
+    *composite_view,
+    *image_view;
+
+  const char
+    *value;
+
+  double
+    sans;
+
+  ExceptionInfo
+    *exception;
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *destination_image;
+
+  MagickBooleanType
+    modify_outside_overlay,
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    amount,
+    destination_dissolve,
+    midpoint,
+    percent_brightness,
+    percent_saturation,
+    source_dissolve,
+    threshold;
+
+  MagickStatusType
+    flags;
+
+  ssize_t
+    y;
+
+  /*
+    Prepare composite image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(composite_image != (Image *) NULL);
+  assert(composite_image->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  GetPixelInfo(image,&zero);
+  destination_image=(Image *) NULL;
+  amount=0.5;
+  destination_dissolve=1.0;
+  modify_outside_overlay=MagickFalse;
+  percent_brightness=100.0;
+  percent_saturation=100.0;
+  source_dissolve=1.0;
+  threshold=0.05f;
+  switch (compose)
+  {
+    case ClearCompositeOp:
+    case SrcCompositeOp:
+    case InCompositeOp:
+    case SrcInCompositeOp:
+    case OutCompositeOp:
+    case SrcOutCompositeOp:
+    case DstInCompositeOp:
+    case DstAtopCompositeOp:
+    {
+      /*
+        Modify destination outside the overlaid region.
+      */
+      modify_outside_overlay=MagickTrue;
+      break;
+    }
+    case CopyCompositeOp:
+    {
+      if ((x_offset < 0) || (y_offset < 0))
+        break;
+      if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
+        break;
+      if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
+        break;
+      status=MagickTrue;
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+      composite_view=AcquireCacheView(composite_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) composite_image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const Quantum
+          *p;
+
+        register Quantum
+          *q;
+
+        register ssize_t
+          x;
+
+        if (status == MagickFalse)
+          continue;
+        p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
+          1,exception);
+        q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
+          composite_image->columns,1,exception);
+        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) composite_image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelRed(composite_image,p),q);
+          SetPixelGreen(image,GetPixelGreen(composite_image,p),q);
+          SetPixelBlue(image,GetPixelBlue(composite_image,p),q);
+          SetPixelAlpha(image,GetPixelAlpha(composite_image,p),q);
+          if (image->colorspace == CMYKColorspace)
+            SetPixelBlack(image,GetPixelBlack(composite_image,p),q);
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp critical (MagickCore_CompositeImage)
+#endif
+            proceed=SetImageProgress(image,CompositeImageTag,
+              (MagickOffsetType) y,image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      composite_view=DestroyCacheView(composite_view);
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case CopyOpacityCompositeOp:
+    case ChangeMaskCompositeOp:
+    {
+      /*
+        Modify destination outside the overlaid region and require an alpha
+        channel to exist, to add transparency.
+      */
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      modify_outside_overlay=MagickTrue;
+      break;
+    }
+    case BlurCompositeOp:
+    {
+      CacheView
+        *composite_view,
+        *destination_view;
+
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        angle_range,
+        angle_start,
+        height,
+        width;
+
+      ResampleFilter
+        *resample_filter;
+
+      SegmentInfo
+        blur;
+
+      /*
+        Blur Image dictated by an overlay gradient map: X = red_channel;
+          Y = green_channel; compose:args =  x_scale[,y_scale[,angle]].
+      */
+      destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+        &image->exception);
+      if (destination_image == (Image *) NULL)
+        return(MagickFalse);
+      /*
+        Determine the horizontal and vertical maximim blur.
+      */
+      SetGeometryInfo(&geometry_info);
+      flags=NoValue;
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        flags=ParseGeometry(value,&geometry_info);
+      if ((flags & WidthValue) == 0 )
+        {
+          destination_image=DestroyImage(destination_image);
+          return(MagickFalse);
+        }
+      width=geometry_info.rho;
+      height=geometry_info.sigma;
+      blur.x1=geometry_info.rho;
+      blur.x2=0.0;
+      blur.y1=0.0;
+      blur.y2=geometry_info.sigma;
+      angle_start=0.0;
+      angle_range=0.0;
+      if ((flags & HeightValue) == 0)
+        blur.y2=blur.x1;
+      if ((flags & XValue) != 0 )
+        {
+          MagickRealType
+            angle;
+
+          angle=DegreesToRadians(geometry_info.xi);
+          blur.x1=width*cos(angle);
+          blur.x2=width*sin(angle);
+          blur.y1=(-height*sin(angle));
+          blur.y2=height*cos(angle);
+        }
+      if ((flags & YValue) != 0 )
+        {
+          angle_start=DegreesToRadians(geometry_info.xi);
+          angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
+        }
+      /*
+        Blur Image by resampling.
+      */
+      pixel=zero;
+      exception=(&image->exception);
+      resample_filter=AcquireResampleFilter(image,&image->exception);
+      SetResampleFilter(resample_filter,CubicFilter,2.0);
+      destination_view=AcquireCacheView(destination_image);
+      composite_view=AcquireCacheView(composite_image);
+      for (y=0; y < (ssize_t) composite_image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const Quantum
+          *restrict p;
+
+        register Quantum
+          *restrict q;
+
+        register ssize_t
+          x;
+
+        if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
+          continue;
+        p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
+          1,exception);
+        q=QueueCacheViewAuthenticPixels(destination_view,0,y,
+          destination_image->columns,1,&image->exception);
+        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+          break;
+        for (x=0; x < (ssize_t) composite_image->columns; x++)
+        {
+          if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
+            {
+              p+=GetPixelChannels(composite_image);
+              continue;
+            }
+          if (fabs(angle_range) > MagickEpsilon)
+            {
+              MagickRealType
+                angle;
+
+              angle=angle_start+angle_range*QuantumScale*
+                GetPixelBlue(composite_image,p);
+              blur.x1=width*cos(angle);
+              blur.x2=width*sin(angle);
+              blur.y1=(-height*sin(angle));
+              blur.y2=height*cos(angle);
+            }
+          ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
+            GetPixelRed(composite_image,p),blur.y1*QuantumScale*
+            GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
+            GetPixelRed(composite_image,p),blur.y2*QuantumScale*
+            GetPixelGreen(composite_image,p));
+          (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
+            (double) y_offset+y,&pixel);
+          SetPixelPixelInfo(destination_image,&pixel,q);
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(destination_image);
+        }
+        sync=SyncCacheViewAuthenticPixels(destination_view,exception);
+        if (sync == MagickFalse)
+          break;
+      }
+      resample_filter=DestroyResampleFilter(resample_filter);
+      composite_view=DestroyCacheView(composite_view);
+      destination_view=DestroyCacheView(destination_view);
+      composite_image=destination_image;
+      break;
+    }
+    case DisplaceCompositeOp:
+    case DistortCompositeOp:
+    {
+      CacheView
+        *composite_view,
+        *destination_view,
+        *image_view;
+
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        horizontal_scale,
+        vertical_scale;
+
+      PointInfo
+        center,
+        offset;
+
+      /*
+        Displace/Distort based on overlay gradient map:
+          X = red_channel;  Y = green_channel;
+          compose:args = x_scale[,y_scale[,center.x,center.y]]
+      */
+      destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+        &image->exception);
+      if (destination_image == (Image *) NULL)
+        return(MagickFalse);
+      SetGeometryInfo(&geometry_info);
+      flags=NoValue;
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        flags=ParseGeometry(value,&geometry_info);
+      if ((flags & (WidthValue|HeightValue)) == 0 )
+        {
+          if ((flags & AspectValue) == 0)
+            {
+              horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
+                2.0;
+              vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
+            }
+          else
+            {
+              horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
+              vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
+            }
+        }
+      else
+        {
+          horizontal_scale=geometry_info.rho;
+          vertical_scale=geometry_info.sigma;
+          if ((flags & PercentValue) != 0)
+            {
+              if ((flags & AspectValue) == 0)
+                {
+                  horizontal_scale*=(composite_image->columns-1.0)/200.0;
+                  vertical_scale*=(composite_image->rows-1.0)/200.0;
+                }
+              else
+                {
+                  horizontal_scale*=(image->columns-1.0)/200.0;
+                  vertical_scale*=(image->rows-1.0)/200.0;
+                }
+            }
+          if ((flags & HeightValue) == 0)
+            vertical_scale=horizontal_scale;
+        }
+      /*
+        Determine fixed center point for absolute distortion map
+         Absolute distort ==
+           Displace offset relative to a fixed absolute point
+           Select that point according to +X+Y user inputs.
+           default = center of overlay image
+           arg flag '!' = locations/percentage relative to background image
+      */
+      center.x=(MagickRealType) x_offset;
+      center.y=(MagickRealType) y_offset;
+      if (compose == DistortCompositeOp)
+        {
+          if ((flags & XValue) == 0)
+            if ((flags & AspectValue) == 0)
+              center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
+                2.0;
+            else
+              center.x=((MagickRealType) image->columns-1)/2.0;
+          else
+            if ((flags & AspectValue) == 0)
+              center.x=(MagickRealType) x_offset+geometry_info.xi;
+            else
+              center.x=geometry_info.xi;
+          if ((flags & YValue) == 0)
+            if ((flags & AspectValue) == 0)
+              center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
+            else
+              center.y=((MagickRealType) image->rows-1)/2.0;
+          else
+            if ((flags & AspectValue) == 0)
+              center.y=(MagickRealType) y_offset+geometry_info.psi;
+            else
+              center.y=geometry_info.psi;
+        }
+      /*
+        Shift the pixel offset point as defined by the provided,
+        displacement/distortion map.  -- Like a lens...
+      */
+      pixel=zero;
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+      destination_view=AcquireCacheView(destination_image);
+      composite_view=AcquireCacheView(composite_image);
+      for (y=0; y < (ssize_t) composite_image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const Quantum
+          *restrict p;
+
+        register Quantum
+          *restrict q;
+
+        register ssize_t
+          x;
+
+        if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
+          continue;
+        p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
+          1,exception);
+        q=QueueCacheViewAuthenticPixels(destination_view,0,y,
+          destination_image->columns,1,&image->exception);
+        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+          break;
+        for (x=0; x < (ssize_t) composite_image->columns; x++)
+        {
+          if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
+            {
+              p+=GetPixelChannels(composite_image);
+              continue;
+            }
+          /*
+            Displace the offset.
+          */
+          offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
+            (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
+            QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
+            x : 0);
+          offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
+            (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
+            QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
+            y : 0);
+          (void) InterpolatePixelInfo(image,image_view,
+            UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
+            &pixel,exception);
+          /*
+            Mask with the 'invalid pixel mask' in alpha channel.
+          */
+          pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
+            pixel.alpha)*(1.0-QuantumScale*
+            GetPixelAlpha(composite_image,p)));
+          SetPixelPixelInfo(destination_image,&pixel,q);
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(destination_image);
+        }
+        sync=SyncCacheViewAuthenticPixels(destination_view,exception);
+        if (sync == MagickFalse)
+          break;
+      }
+      destination_view=DestroyCacheView(destination_view);
+      composite_view=DestroyCacheView(composite_view);
+      image_view=DestroyCacheView(image_view);
+      composite_image=destination_image;
+      break;
+    }
+    case DissolveCompositeOp:
+    {
+      /*
+        Geometry arguments to dissolve factors.
+      */
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        {
+          flags=ParseGeometry(value,&geometry_info);
+          source_dissolve=geometry_info.rho/100.0;
+          destination_dissolve=1.0;
+          if ((source_dissolve-MagickEpsilon) < 0.0)
+            source_dissolve=0.0;
+          if ((source_dissolve+MagickEpsilon) > 1.0)
+            {
+              destination_dissolve=2.0-source_dissolve;
+              source_dissolve=1.0;
+            }
+          if ((flags & SigmaValue) != 0)
+            destination_dissolve=geometry_info.sigma/100.0;
+          if ((destination_dissolve-MagickEpsilon) < 0.0)
+            destination_dissolve=0.0;
+          modify_outside_overlay=MagickTrue;
+          if ((destination_dissolve+MagickEpsilon) > 1.0 )
+            {
+              destination_dissolve=1.0;
+              modify_outside_overlay=MagickFalse;
+            }
+        }
+      break;
+    }
+    case BlendCompositeOp:
+    {
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        {
+          flags=ParseGeometry(value,&geometry_info);
+          source_dissolve=geometry_info.rho/100.0;
+          destination_dissolve=1.0-source_dissolve;
+          if ((flags & SigmaValue) != 0)
+            destination_dissolve=geometry_info.sigma/100.0;
+          modify_outside_overlay=MagickTrue;
+          if ((destination_dissolve+MagickEpsilon) > 1.0)
+            modify_outside_overlay=MagickFalse;
+        }
+      break;
+    }
+    case MathematicsCompositeOp:
+    {
+      /*
+        Just collect the values from "compose:args", setting.
+        Unused values are set to zero automagically.
+
+        Arguments are normally a comma separated list, so this probably should
+        be changed to some 'general comma list' parser, (with a minimum
+        number of values)
+      */
+      SetGeometryInfo(&geometry_info);
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        (void) ParseGeometry(value,&geometry_info);
+      break;
+    }
+    case ModulateCompositeOp:
+    {
+      /*
+        Determine the brightness and saturation scale.
+      */
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        {
+          flags=ParseGeometry(value,&geometry_info);
+          percent_brightness=geometry_info.rho;
+          if ((flags & SigmaValue) != 0)
+            percent_saturation=geometry_info.sigma;
+        }
+      break;
+    }
+    case ThresholdCompositeOp:
+    {
+      /*
+        Determine the amount and threshold.
+      */
+      value=GetImageArtifact(composite_image,"compose:args");
+      if (value != (char *) NULL)
+        {
+          flags=ParseGeometry(value,&geometry_info);
+          amount=geometry_info.rho;
+          threshold=geometry_info.sigma;
+          if ((flags & SigmaValue) == 0)
+            threshold=0.05f;
+        }
+      threshold*=QuantumRange;
+      break;
+    }
+    default:
+      break;
+  }
+  value=GetImageArtifact(composite_image,"compose:outside-overlay");
+  if (value != (const char *) NULL)
+    modify_outside_overlay=IsMagickTrue(value);
+  /*
+    Composite image.
+  */
+  status=MagickTrue;
+  progress=0;
+  midpoint=((MagickRealType) QuantumRange+1.0)/2;
+  GetPixelInfo(composite_image,&zero);
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  composite_view=AcquireCacheView(composite_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const Quantum
+      *pixels;
+
+    double
+      brightness,
+      hue,
+      saturation;
+
+    PixelInfo
+      composite,
+      destination,
+      source;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    if (modify_outside_overlay == MagickFalse)
+      {
+        if (y < y_offset)
+          continue;
+        if ((y-y_offset) >= (ssize_t) composite_image->rows)
+          continue;
+      }
+    /*
+      If pixels is NULL, y is outside overlay region.
+    */
+    pixels=(Quantum *) NULL;
+    p=(Quantum *) NULL;
+    if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
+      {
+        p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
+          composite_image->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        pixels=p;
+        if (x_offset < 0)
+          p-=x_offset*GetPixelChannels(composite_image);
+      }
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    source=zero;
+    destination=zero;
+    hue=0.0;
+    saturation=0.0;
+    brightness=0.0;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (modify_outside_overlay == MagickFalse)
+        {
+          if (x < x_offset)
+            {
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          if ((x-x_offset) >= (ssize_t) composite_image->columns)
+            break;
+        }
+      destination.red=(MagickRealType) GetPixelRed(image,q);
+      destination.green=(MagickRealType) GetPixelGreen(image,q);
+      destination.blue=(MagickRealType) GetPixelBlue(image,q);
+      if (image->colorspace == CMYKColorspace)
+        destination.black=(MagickRealType) GetPixelBlack(image,q);
+      if (image->colorspace == CMYKColorspace)
+        {
+          destination.red=(MagickRealType) QuantumRange-destination.red;
+          destination.green=(MagickRealType) QuantumRange-destination.green;
+          destination.blue=(MagickRealType) QuantumRange-destination.blue;
+          destination.black=(MagickRealType) QuantumRange-destination.black;
+        }
+      if (image->matte != MagickFalse)
+        destination.alpha=(MagickRealType) GetPixelAlpha(image,q);
+      /*
+        Handle destination modifications outside overlaid region.
+      */
+      composite=destination;
+      if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
+          ((x-x_offset) >= (ssize_t) composite_image->columns))
+        {
+          switch (compose)
+          {
+            case DissolveCompositeOp:
+            case BlendCompositeOp:
+            {
+              composite.alpha=destination_dissolve*(composite.alpha);
+              break;
+            }
+            case ClearCompositeOp:
+            case SrcCompositeOp:
+            {
+              CompositeClear(&destination,&composite);
+              break;
+            }
+            case InCompositeOp:
+            case SrcInCompositeOp:
+            case OutCompositeOp:
+            case SrcOutCompositeOp:
+            case DstInCompositeOp:
+            case DstAtopCompositeOp:
+            case CopyOpacityCompositeOp:
+            case ChangeMaskCompositeOp:
+            {
+              composite.alpha=(MagickRealType) TransparentAlpha;
+              break;
+            }
+            default:
+            {
+              (void) GetOneVirtualMagickPixel(composite_image,x-x_offset,y-
+                y_offset,&composite,exception);
+              break;
+            }
+          }
+          if (image->colorspace == CMYKColorspace)
+            {
+              composite.red=(MagickRealType) QuantumRange-composite.red;
+              composite.green=(MagickRealType) QuantumRange-composite.green;
+              composite.blue=(MagickRealType) QuantumRange-composite.blue;
+              composite.black=(MagickRealType) QuantumRange-composite.black;
+            }
+          SetPixelRed(image,ClampToQuantum(composite.red),q);
+          SetPixelGreen(image,ClampToQuantum(composite.green),q);
+          SetPixelBlue(image,ClampToQuantum(composite.blue),q);
+          if (image->matte != MagickFalse)
+            SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
+          if (image->colorspace == CMYKColorspace)
+            SetPixelBlack(image,ClampToQuantum(composite.black),q);
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      /*
+        Handle normal overlay of source onto destination.
+      */
+      source.red=(MagickRealType) GetPixelRed(composite_image,p);
+      source.green=(MagickRealType) GetPixelGreen(composite_image,p);
+      source.blue=(MagickRealType) GetPixelBlue(composite_image,p);
+      if (composite_image->colorspace == CMYKColorspace)
+        source.black=(MagickRealType) GetPixelBlack(composite_image,p);
+      if (composite_image->colorspace == CMYKColorspace)
+        {
+          source.red=(MagickRealType) QuantumRange-source.red;
+          source.green=(MagickRealType) QuantumRange-source.green;
+          source.blue=(MagickRealType) QuantumRange-source.blue;
+          source.black=(MagickRealType) QuantumRange-source.black;
+        }
+      if (composite_image->matte != MagickFalse)
+        source.alpha=(MagickRealType) GetPixelAlpha(composite_image,p);
+      /*
+        Porter-Duff compositions.
+      */
+      switch (compose)
+      {
+        case ClearCompositeOp:
+        {
+          CompositeClear(&destination,&composite);
+          break;
+        }
+        case SrcCompositeOp:
+        case CopyCompositeOp:
+        case ReplaceCompositeOp:
+        {
+          composite=source;
+          break;
+        }
+        case NoCompositeOp:
+        case DstCompositeOp:
+          break;
+        case OverCompositeOp:
+        case SrcOverCompositeOp:
+        {
+          CompositePixelInfoOver(&source,source.alpha,&destination,
+            destination.alpha,&composite);
+          break;
+        }
+        case DstOverCompositeOp:
+        {
+          CompositePixelInfoOver(&destination,destination.alpha,&source,
+            source.alpha,&composite);
+          break;
+        }
+        case SrcInCompositeOp:
+        case InCompositeOp:
+        {
+          CompositeIn(&source,&destination,&composite);
+          break;
+        }
+        case DstInCompositeOp:
+        {
+          CompositeIn(&destination,&source,&composite);
+          break;
+        }
+        case OutCompositeOp:
+        case SrcOutCompositeOp:
+        {
+          CompositeOut(&source,&destination,&composite);
+          break;
+        }
+        case DstOutCompositeOp:
+        {
+          CompositeOut(&destination,&source,&composite);
+          break;
+        }
+        case AtopCompositeOp:
+        case SrcAtopCompositeOp:
+        {
+          CompositeAtop(&source,&destination,&composite);
+          break;
+        }
+        case DstAtopCompositeOp:
+        {
+          CompositeAtop(&destination,&source,&composite);
+          break;
+        }
+        case XorCompositeOp:
+        {
+          CompositeXor(&source,&destination,&composite);
+          break;
+        }
+        case PlusCompositeOp:
+        {
+          CompositePlus(&source,&destination,channel,&composite);
+          break;
+        }
+        case MinusDstCompositeOp:
+        {
+          CompositeMinus(&source,&destination,channel,&composite);
+          break;
+        }
+        case MinusSrcCompositeOp:
+        {
+          CompositeMinus(&destination,&source,channel,&composite);
+          break;
+        }
+        case ModulusAddCompositeOp:
+        {
+          CompositeModulusAdd(&source,&destination,channel,&composite);
+          break;
+        }
+        case ModulusSubtractCompositeOp:
+        {
+          CompositeModulusSubtract(&source,&destination,channel,&composite);
+          break;
+        }
+        case DifferenceCompositeOp:
+        {
+          CompositeDifference(&source,&destination,channel,&composite);
+          break;
+        }
+        case ExclusionCompositeOp:
+        {
+          CompositeExclusion(&source,&destination,channel,&composite);
+          break;
+        }
+        case MultiplyCompositeOp:
+        {
+          CompositeMultiply(&source,&destination,channel,&composite);
+          break;
+        }
+        case ScreenCompositeOp:
+        {
+          CompositeScreen(&source,&destination,channel,&composite);
+          break;
+        }
+        case DivideDstCompositeOp:
+        {
+          CompositeDivide(&source,&destination,channel,&composite);
+          break;
+        }
+        case DivideSrcCompositeOp:
+        {
+          CompositeDivide(&destination,&source,channel,&composite);
+          break;
+        }
+        case DarkenCompositeOp:
+        {
+          CompositeDarken(&source,&destination,channel,&composite);
+          break;
+        }
+        case LightenCompositeOp:
+        {
+          CompositeLighten(&source,&destination,channel,&composite);
+          break;
+        }
+        case DarkenIntensityCompositeOp:
+        {
+          CompositeDarkenIntensity(&source,&destination,channel,&composite);
+          break;
+        }
+        case LightenIntensityCompositeOp:
+        {
+          CompositeLightenIntensity(&source,&destination,channel,&composite);
+          break;
+        }
+        case MathematicsCompositeOp:
+        {
+          CompositeMathematics(&source,&destination,channel,&geometry_info,
+            &composite);
+          break;
+        }
+        case ColorDodgeCompositeOp:
+        {
+          CompositeColorDodge(&source,&destination,&composite);
+          break;
+        }
+        case ColorBurnCompositeOp:
+        {
+          CompositeColorBurn(&source,&destination,&composite);
+          break;
+        }
+        case LinearDodgeCompositeOp:
+        {
+          CompositeLinearDodge(&source,&destination,&composite);
+          break;
+        }
+        case LinearBurnCompositeOp:
+        {
+          CompositeLinearBurn(&source,&destination,&composite);
+          break;
+        }
+        case HardLightCompositeOp:
+        {
+          CompositeHardLight(&source,&destination,&composite);
+          break;
+        }
+        case OverlayCompositeOp:
+        {
+          CompositeHardLight(&destination,&source,&composite);
+          break;
+        }
+        case SoftLightCompositeOp:
+        {
+          CompositeSoftLight(&source,&destination,&composite);
+          break;
+        }
+        case LinearLightCompositeOp:
+        {
+          CompositeLinearLight(&source,&destination,&composite);
+          break;
+        }
+        case PegtopLightCompositeOp:
+        {
+          CompositePegtopLight(&source,&destination,&composite);
+          break;
+        }
+        case VividLightCompositeOp:
+        {
+          CompositeVividLight(&source,&destination,&composite);
+          break;
+        }
+        case PinLightCompositeOp:
+        {
+          CompositePinLight(&source,&destination,&composite);
+          break;
+        }
+        case ChangeMaskCompositeOp:
+        {
+          if ((composite.alpha > ((MagickRealType) QuantumRange/2.0)) ||
+              (IsFuzzyEquivalencePixelInfo(&source,&destination) != MagickFalse))
+            composite.alpha=(MagickRealType) TransparentAlpha;
+          else
+            composite.alpha=(MagickRealType) OpaqueAlpha;
+          break;
+        }
+        case BumpmapCompositeOp:
+        {
+          if (source.alpha == TransparentAlpha)
+            break;
+          CompositeBumpmap(&source,&destination,&composite);
+          break;
+        }
+        case DissolveCompositeOp:
+        {
+          CompositePixelInfoOver(&source,source_dissolve*source.alpha,
+            &destination,(MagickRealType) (destination_dissolve*
+            destination.alpha),&composite);
+          break;
+        }
+        case BlendCompositeOp:
+        {
+          CompositePixelInfoBlend(&source,source_dissolve,&destination,
+            destination_dissolve,&composite);
+          break;
+        }
+        case ThresholdCompositeOp:
+        {
+          CompositeThreshold(&source,&destination,threshold,amount,&composite);
+          break;
+        }
+        case ModulateCompositeOp:
+        {
+          ssize_t
+            offset;
+
+          if (source.alpha == TransparentAlpha)
+            break;
+          offset=(ssize_t) (GetPixelInfoIntensity(&source)-midpoint);
+          if (offset == 0)
+            break;
+          CompositeHSB(destination.red,destination.green,destination.blue,&hue,
+            &saturation,&brightness);
+          brightness+=(0.01*percent_brightness*offset)/midpoint;
+          saturation*=0.01*percent_saturation;
+          HSBComposite(hue,saturation,brightness,&composite.red,
+            &composite.green,&composite.blue);
+          break;
+        }
+        case HueCompositeOp:
+        {
+          if (source.alpha == TransparentAlpha)
+            break;
+          if (destination.alpha == TransparentAlpha)
+            {
+              composite=source;
+              break;
+            }
+          CompositeHSB(destination.red,destination.green,destination.blue,&hue,
+            &saturation,&brightness);
+          CompositeHSB(source.red,source.green,source.blue,&hue,&sans,&sans);
+          HSBComposite(hue,saturation,brightness,&composite.red,
+            &composite.green,&composite.blue);
+          if (source.alpha < destination.alpha)
+            composite.alpha=source.alpha;
+          break;
+        }
+        case SaturateCompositeOp:
+        {
+          if (source.alpha == TransparentAlpha)
+            break;
+          if (destination.alpha == TransparentAlpha)
+            {
+              composite=source;
+              break;
+            }
+          CompositeHSB(destination.red,destination.green,destination.blue,&hue,
+            &saturation,&brightness);
+          CompositeHSB(source.red,source.green,source.blue,&sans,&saturation,
+            &sans);
+          HSBComposite(hue,saturation,brightness,&composite.red,
+            &composite.green,&composite.blue);
+          if (source.alpha < destination.alpha)
+            composite.alpha=source.alpha;
+          break;
+        }
+        case LuminizeCompositeOp:
+        {
+          if (source.alpha == TransparentAlpha)
+            break;
+          if (destination.alpha == TransparentAlpha)
+            {
+              composite=source;
+              break;
+            }
+          CompositeHSB(destination.red,destination.green,destination.blue,&hue,
+            &saturation,&brightness);
+          CompositeHSB(source.red,source.green,source.blue,&sans,&sans,
+            &brightness);
+          HSBComposite(hue,saturation,brightness,&composite.red,
+            &composite.green,&composite.blue);
+          if (source.alpha < destination.alpha)
+            composite.alpha=source.alpha;
+          break;
+        }
+        case ColorizeCompositeOp:
+        {
+          if (source.alpha == TransparentAlpha)
+            break;
+          if (destination.alpha == TransparentAlpha)
+            {
+              composite=source;
+              break;
+            }
+          CompositeHSB(destination.red,destination.green,destination.blue,&sans,
+            &sans,&brightness);
+          CompositeHSB(source.red,source.green,source.blue,&hue,&saturation,
+            &sans);
+          HSBComposite(hue,saturation,brightness,&composite.red,
+            &composite.green,&composite.blue);
+          if (source.alpha < destination.alpha)
+            composite.alpha=source.alpha;
+          break;
+        }
+        case CopyRedCompositeOp:
+        case CopyCyanCompositeOp:
+        {
+          composite.red=source.red;
+          break;
+        }
+        case CopyGreenCompositeOp:
+        case CopyMagentaCompositeOp:
+        {
+          composite.green=source.green;
+          break;
+        }
+        case CopyBlueCompositeOp:
+        case CopyYellowCompositeOp:
+        {
+          composite.blue=source.blue;
+          break;
+        }
+        case CopyOpacityCompositeOp:
+        {
+          if (source.matte == MagickFalse)
+            {
+              composite.alpha=(MagickRealType) GetPixelInfoIntensity(&source);
+              break;
+            }
+          composite.alpha=source.alpha;
+          break;
+        }
+        case CopyBlackCompositeOp:
+        {
+          if (source.colorspace != CMYKColorspace)
+            ConvertRGBToCMYK(&source);
+          composite.black=source.black;
+          break;
+        }
+        case BlurCompositeOp:
+        case DisplaceCompositeOp:
+        case DistortCompositeOp:
+        {
+          composite=source;
+          break;
+        }
+        default:
+          break;
+      }
+      if (image->colorspace == CMYKColorspace)
+        {
+          composite.red=(MagickRealType) QuantumRange-composite.red;
+          composite.green=(MagickRealType) QuantumRange-composite.green;
+          composite.blue=(MagickRealType) QuantumRange-composite.blue;
+          composite.black=(MagickRealType) QuantumRange-composite.black;
+        }
+      SetPixelRed(image,ClampToQuantum(composite.red),q);
+      SetPixelGreen(image,ClampToQuantum(composite.green),q);
+      SetPixelBlue(image,ClampToQuantum(composite.blue),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(image,ClampToQuantum(composite.black),q);
+      SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
+      p+=GetPixelChannels(composite_image);
+      if (p >= (pixels+composite_image->columns*GetPixelChannels(composite_image)))
+        p=pixels;
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_CompositeImageChannel)
+#endif
+        proceed=SetImageProgress(image,CompositeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  composite_view=DestroyCacheView(composite_view);
+  image_view=DestroyCacheView(image_view);
+  if (destination_image != (Image * ) NULL)
+    destination_image=DestroyImage(destination_image);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T e x t u r e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TextureImage() repeatedly tiles the texture image across and down the image
+%  canvas.
+%
+%  The format of the TextureImage method is:
+%
+%      MagickBooleanType TextureImage(Image *image,const Image *texture)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o texture: This image is the texture to layer on the background.
+%
+*/
+MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture)
+{
+#define TextureImageTag  "Texture/Image"
+
+  CacheView
+    *image_view,
+    *texture_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (texture == (const Image *) NULL)
+    return(MagickFalse);
+  (void) SetImageVirtualPixelMethod(texture,TileVirtualPixelMethod);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  if ((image->compose != CopyCompositeOp) &&
+      ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
+       (texture->matte != MagickFalse)))
+    {
+      /*
+        Tile texture onto the image background.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture->rows)
+      {
+        register ssize_t
+          x;
+
+        if (status == MagickFalse)
+          continue;
+        for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
+        {
+          MagickBooleanType
+            thread_status;
+
+          thread_status=CompositeImage(image,image->compose,texture,x+
+            texture->tile_offset.x,y+texture->tile_offset.y);
+          if (thread_status == MagickFalse)
+            {
+              status=thread_status;
+              break;
+            }
+        }
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TextureImage)
+#endif
+            proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
+              y,image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
+        image->rows,image->rows);
+      return(status);
+    }
+  /*
+    Tile texture onto the image background (optimized).
+  */
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  texture_view=AcquireCacheView(texture);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *p,
+      *pixels;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *q;
+
+    size_t
+      width;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewVirtualPixels(texture_view,texture->tile_offset.x,(y+
+      texture->tile_offset.y) % texture->rows,texture->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+      exception);
+    if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
+    {
+      register ssize_t
+        i;
+
+      p=pixels;
+      width=texture->columns;
+      if ((x+(ssize_t) width) > (ssize_t) image->columns)
+        width=image->columns-x;
+      for (i=0; i < (ssize_t) width; i++)
+      {
+        SetPixelRed(image,GetPixelRed(texture,p),q);
+        SetPixelGreen(image,GetPixelGreen(texture,p),q);
+        SetPixelBlue(image,GetPixelBlue(texture,p),q);
+        SetPixelAlpha(image,GetPixelAlpha(texture,p),q);
+        if ((image->colorspace == CMYKColorspace)  &&
+            (texture->colorspace == CMYKColorspace))
+          SetPixelBlack(image,GetPixelBlack(texture,p),q);
+        p+=GetPixelChannels(texture);
+        q+=GetPixelChannels(image);
+      }
+    }
+    sync=SyncCacheViewAuthenticPixels(image_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_TextureImage)
+#endif
+        proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  texture_view=DestroyCacheView(texture_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/MagickCore/composite.h b/MagickCore/composite.h
new file mode 100644
index 0000000..6808094
--- /dev/null
+++ b/MagickCore/composite.h
@@ -0,0 +1,108 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image composite methods.
+*/
+#ifndef _MAGICKCORE_COMPOSITE_H
+#define _MAGICKCORE_COMPOSITE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  AtopCompositeOp,
+  BlendCompositeOp,
+  BlurCompositeOp,
+  BumpmapCompositeOp,
+  ChangeMaskCompositeOp,
+  ClearCompositeOp,
+  ColorBurnCompositeOp,
+  ColorDodgeCompositeOp,
+  ColorizeCompositeOp,
+  CopyBlackCompositeOp,
+  CopyBlueCompositeOp,
+  CopyCompositeOp,
+  CopyCyanCompositeOp,
+  CopyGreenCompositeOp,
+  CopyMagentaCompositeOp,
+  CopyOpacityCompositeOp,
+  CopyRedCompositeOp,
+  CopyYellowCompositeOp,
+  DarkenCompositeOp,
+  DarkenIntensityCompositeOp,
+  DifferenceCompositeOp,
+  DisplaceCompositeOp,
+  DissolveCompositeOp,
+  DistortCompositeOp,
+  DivideDstCompositeOp,
+  DivideSrcCompositeOp,
+  DstAtopCompositeOp,
+  DstCompositeOp,
+  DstInCompositeOp,
+  DstOutCompositeOp,
+  DstOverCompositeOp,
+  ExclusionCompositeOp,
+  HardLightCompositeOp,
+  HueCompositeOp,
+  InCompositeOp,
+  LightenCompositeOp,
+  LightenIntensityCompositeOp,
+  LinearBurnCompositeOp,
+  LinearDodgeCompositeOp,
+  LinearLightCompositeOp,
+  LuminizeCompositeOp,
+  MathematicsCompositeOp,
+  MinusDstCompositeOp,
+  MinusSrcCompositeOp,
+  ModulateCompositeOp,
+  ModulusAddCompositeOp,
+  ModulusSubtractCompositeOp,
+  MultiplyCompositeOp,
+  NoCompositeOp,
+  OutCompositeOp,
+  OverCompositeOp,
+  OverlayCompositeOp,
+  PegtopLightCompositeOp,
+  PinLightCompositeOp,
+  PlusCompositeOp,
+  ReplaceCompositeOp,
+  SaturateCompositeOp,
+  ScreenCompositeOp,
+  SoftLightCompositeOp,
+  SrcAtopCompositeOp,
+  SrcCompositeOp,
+  SrcInCompositeOp,
+  SrcOutCompositeOp,
+  SrcOverCompositeOp,
+  ThresholdCompositeOp,
+  UndefinedCompositeOp,
+  VividLightCompositeOp,
+  XorCompositeOp
+} CompositeOperator;
+
+extern MagickExport MagickBooleanType
+  CompositeImage(Image *,const CompositeOperator,const Image *,const ssize_t,
+    const ssize_t),
+  CompositeImageChannel(Image *,const ChannelType,const CompositeOperator,
+    const Image *,const ssize_t,const ssize_t),
+  TextureImage(Image *,const Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/compress.c b/MagickCore/compress.c
new file mode 100644
index 0000000..6e735ed
--- /dev/null
+++ b/MagickCore/compress.c
@@ -0,0 +1,1309 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           CCCC   OOO   M   M  PPPP   RRRR   EEEEE   SSSSS  SSSSS            %
+%          C      O   O  MM MM  P   P  R   R  E       SS     SS               %
+%          C      O   O  M M M  PPPP   RRRR   EEE      SSS    SSS             %
+%          C      O   O  M   M  P      R R    E          SS     SS            %
+%           CCCC   OOO   M   M  P      R  R   EEEEE   SSSSS  SSSSS            %
+%                                                                             %
+%                                                                             %
+%             MagickCore Image Compression/Decompression Methods              %
+%                                                                             %
+%                           Software Design                                   %
+%                             John Cristy                                     %
+%                              May  1993                                      %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/compress.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/string_.h"
+#if defined(MAGICKCORE_TIFF_DELEGATE)
+#if defined(MAGICKCORE_HAVE_TIFFCONF_H)
+#include "tiffconf.h"
+#endif
+#include "tiffio.h"
+#define CCITTParam  "-1"
+#else
+#define CCITTParam  "0"
+#endif
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+#include "zlib.h"
+#endif
+
+/*
+  Typedef declarations.
+*/
+struct _Ascii85Info
+{
+  ssize_t
+    offset,
+    line_break;
+
+  unsigned char
+    buffer[10];
+};
+
+typedef struct HuffmanTable
+{
+  size_t
+    id,
+    code,
+    length,
+    count;
+} HuffmanTable;
+
+/*
+  Huffman coding declarations.
+*/
+#define TWId  23
+#define MWId  24
+#define TBId  25
+#define MBId  26
+#define EXId  27
+
+static const HuffmanTable
+  MBTable[]=
+  {
+    { MBId, 0x0f, 10, 64 }, { MBId, 0xc8, 12, 128 },
+    { MBId, 0xc9, 12, 192 }, { MBId, 0x5b, 12, 256 },
+    { MBId, 0x33, 12, 320 }, { MBId, 0x34, 12, 384 },
+    { MBId, 0x35, 12, 448 }, { MBId, 0x6c, 13, 512 },
+    { MBId, 0x6d, 13, 576 }, { MBId, 0x4a, 13, 640 },
+    { MBId, 0x4b, 13, 704 }, { MBId, 0x4c, 13, 768 },
+    { MBId, 0x4d, 13, 832 }, { MBId, 0x72, 13, 896 },
+    { MBId, 0x73, 13, 960 }, { MBId, 0x74, 13, 1024 },
+    { MBId, 0x75, 13, 1088 }, { MBId, 0x76, 13, 1152 },
+    { MBId, 0x77, 13, 1216 }, { MBId, 0x52, 13, 1280 },
+    { MBId, 0x53, 13, 1344 }, { MBId, 0x54, 13, 1408 },
+    { MBId, 0x55, 13, 1472 }, { MBId, 0x5a, 13, 1536 },
+    { MBId, 0x5b, 13, 1600 }, { MBId, 0x64, 13, 1664 },
+    { MBId, 0x65, 13, 1728 }, { MBId, 0x00, 0, 0 }
+  };
+
+static const HuffmanTable
+  EXTable[]=
+  {
+    { EXId, 0x08, 11, 1792 }, { EXId, 0x0c, 11, 1856 },
+    { EXId, 0x0d, 11, 1920 }, { EXId, 0x12, 12, 1984 },
+    { EXId, 0x13, 12, 2048 }, { EXId, 0x14, 12, 2112 },
+    { EXId, 0x15, 12, 2176 }, { EXId, 0x16, 12, 2240 },
+    { EXId, 0x17, 12, 2304 }, { EXId, 0x1c, 12, 2368 },
+    { EXId, 0x1d, 12, 2432 }, { EXId, 0x1e, 12, 2496 },
+    { EXId, 0x1f, 12, 2560 }, { EXId, 0x00, 0, 0 }
+  };
+
+static const HuffmanTable
+  MWTable[]=
+  {
+    { MWId, 0x1b, 5, 64 }, { MWId, 0x12, 5, 128 },
+    { MWId, 0x17, 6, 192 }, { MWId, 0x37, 7, 256 },
+    { MWId, 0x36, 8, 320 }, { MWId, 0x37, 8, 384 },
+    { MWId, 0x64, 8, 448 }, { MWId, 0x65, 8, 512 },
+    { MWId, 0x68, 8, 576 }, { MWId, 0x67, 8, 640 },
+    { MWId, 0xcc, 9, 704 }, { MWId, 0xcd, 9, 768 },
+    { MWId, 0xd2, 9, 832 }, { MWId, 0xd3, 9, 896 },
+    { MWId, 0xd4, 9, 960 }, { MWId, 0xd5, 9, 1024 },
+    { MWId, 0xd6, 9, 1088 }, { MWId, 0xd7, 9, 1152 },
+    { MWId, 0xd8, 9, 1216 }, { MWId, 0xd9, 9, 1280 },
+    { MWId, 0xda, 9, 1344 }, { MWId, 0xdb, 9, 1408 },
+    { MWId, 0x98, 9, 1472 }, { MWId, 0x99, 9, 1536 },
+    { MWId, 0x9a, 9, 1600 }, { MWId, 0x18, 6, 1664 },
+    { MWId, 0x9b, 9, 1728 }, { MWId, 0x00, 0, 0 }
+  };
+
+static const HuffmanTable
+  TBTable[]=
+  {
+    { TBId, 0x37, 10, 0 }, { TBId, 0x02, 3, 1 }, { TBId, 0x03, 2, 2 },
+    { TBId, 0x02, 2, 3 }, { TBId, 0x03, 3, 4 }, { TBId, 0x03, 4, 5 },
+    { TBId, 0x02, 4, 6 }, { TBId, 0x03, 5, 7 }, { TBId, 0x05, 6, 8 },
+    { TBId, 0x04, 6, 9 }, { TBId, 0x04, 7, 10 }, { TBId, 0x05, 7, 11 },
+    { TBId, 0x07, 7, 12 }, { TBId, 0x04, 8, 13 }, { TBId, 0x07, 8, 14 },
+    { TBId, 0x18, 9, 15 }, { TBId, 0x17, 10, 16 }, { TBId, 0x18, 10, 17 },
+    { TBId, 0x08, 10, 18 }, { TBId, 0x67, 11, 19 }, { TBId, 0x68, 11, 20 },
+    { TBId, 0x6c, 11, 21 }, { TBId, 0x37, 11, 22 }, { TBId, 0x28, 11, 23 },
+    { TBId, 0x17, 11, 24 }, { TBId, 0x18, 11, 25 }, { TBId, 0xca, 12, 26 },
+    { TBId, 0xcb, 12, 27 }, { TBId, 0xcc, 12, 28 }, { TBId, 0xcd, 12, 29 },
+    { TBId, 0x68, 12, 30 }, { TBId, 0x69, 12, 31 }, { TBId, 0x6a, 12, 32 },
+    { TBId, 0x6b, 12, 33 }, { TBId, 0xd2, 12, 34 }, { TBId, 0xd3, 12, 35 },
+    { TBId, 0xd4, 12, 36 }, { TBId, 0xd5, 12, 37 }, { TBId, 0xd6, 12, 38 },
+    { TBId, 0xd7, 12, 39 }, { TBId, 0x6c, 12, 40 }, { TBId, 0x6d, 12, 41 },
+    { TBId, 0xda, 12, 42 }, { TBId, 0xdb, 12, 43 }, { TBId, 0x54, 12, 44 },
+    { TBId, 0x55, 12, 45 }, { TBId, 0x56, 12, 46 }, { TBId, 0x57, 12, 47 },
+    { TBId, 0x64, 12, 48 }, { TBId, 0x65, 12, 49 }, { TBId, 0x52, 12, 50 },
+    { TBId, 0x53, 12, 51 }, { TBId, 0x24, 12, 52 }, { TBId, 0x37, 12, 53 },
+    { TBId, 0x38, 12, 54 }, { TBId, 0x27, 12, 55 }, { TBId, 0x28, 12, 56 },
+    { TBId, 0x58, 12, 57 }, { TBId, 0x59, 12, 58 }, { TBId, 0x2b, 12, 59 },
+    { TBId, 0x2c, 12, 60 }, { TBId, 0x5a, 12, 61 }, { TBId, 0x66, 12, 62 },
+    { TBId, 0x67, 12, 63 }, { TBId, 0x00, 0, 0 }
+  };
+
+static const HuffmanTable
+  TWTable[]=
+  {
+    { TWId, 0x35, 8, 0 }, { TWId, 0x07, 6, 1 }, { TWId, 0x07, 4, 2 },
+    { TWId, 0x08, 4, 3 }, { TWId, 0x0b, 4, 4 }, { TWId, 0x0c, 4, 5 },
+    { TWId, 0x0e, 4, 6 }, { TWId, 0x0f, 4, 7 }, { TWId, 0x13, 5, 8 },
+    { TWId, 0x14, 5, 9 }, { TWId, 0x07, 5, 10 }, { TWId, 0x08, 5, 11 },
+    { TWId, 0x08, 6, 12 }, { TWId, 0x03, 6, 13 }, { TWId, 0x34, 6, 14 },
+    { TWId, 0x35, 6, 15 }, { TWId, 0x2a, 6, 16 }, { TWId, 0x2b, 6, 17 },
+    { TWId, 0x27, 7, 18 }, { TWId, 0x0c, 7, 19 }, { TWId, 0x08, 7, 20 },
+    { TWId, 0x17, 7, 21 }, { TWId, 0x03, 7, 22 }, { TWId, 0x04, 7, 23 },
+    { TWId, 0x28, 7, 24 }, { TWId, 0x2b, 7, 25 }, { TWId, 0x13, 7, 26 },
+    { TWId, 0x24, 7, 27 }, { TWId, 0x18, 7, 28 }, { TWId, 0x02, 8, 29 },
+    { TWId, 0x03, 8, 30 }, { TWId, 0x1a, 8, 31 }, { TWId, 0x1b, 8, 32 },
+    { TWId, 0x12, 8, 33 }, { TWId, 0x13, 8, 34 }, { TWId, 0x14, 8, 35 },
+    { TWId, 0x15, 8, 36 }, { TWId, 0x16, 8, 37 }, { TWId, 0x17, 8, 38 },
+    { TWId, 0x28, 8, 39 }, { TWId, 0x29, 8, 40 }, { TWId, 0x2a, 8, 41 },
+    { TWId, 0x2b, 8, 42 }, { TWId, 0x2c, 8, 43 }, { TWId, 0x2d, 8, 44 },
+    { TWId, 0x04, 8, 45 }, { TWId, 0x05, 8, 46 }, { TWId, 0x0a, 8, 47 },
+    { TWId, 0x0b, 8, 48 }, { TWId, 0x52, 8, 49 }, { TWId, 0x53, 8, 50 },
+    { TWId, 0x54, 8, 51 }, { TWId, 0x55, 8, 52 }, { TWId, 0x24, 8, 53 },
+    { TWId, 0x25, 8, 54 }, { TWId, 0x58, 8, 55 }, { TWId, 0x59, 8, 56 },
+    { TWId, 0x5a, 8, 57 }, { TWId, 0x5b, 8, 58 }, { TWId, 0x4a, 8, 59 },
+    { TWId, 0x4b, 8, 60 }, { TWId, 0x32, 8, 61 }, { TWId, 0x33, 8, 62 },
+    { TWId, 0x34, 8, 63 }, { TWId, 0x00, 0, 0 }
+  };
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A S C I I 8 5 E n c o d e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ASCII85Encode() encodes data in ASCII base-85 format.  ASCII base-85
+%  encoding produces five ASCII printing characters from every four bytes of
+%  binary data.
+%
+%  The format of the ASCII85Encode method is:
+%
+%      void Ascii85Encode(Image *image,const size_t code)
+%
+%  A description of each parameter follows:
+%
+%    o code: a binary unsigned char to encode to ASCII 85.
+%
+%    o file: write the encoded ASCII character to this file.
+%
+%
+*/
+#define MaxLineExtent  36
+
+static char *Ascii85Tuple(unsigned char *data)
+{
+  static char
+    tuple[6];
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    code,
+    quantum;
+
+  code=((((size_t) data[0] << 8) | (size_t) data[1]) << 16) |
+    ((size_t) data[2] << 8) | (size_t) data[3];
+  if (code == 0L)
+    {
+      tuple[0]='z';
+      tuple[1]='\0';
+      return(tuple);
+    }
+  quantum=85UL*85UL*85UL*85UL;
+  for (i=0; i < 4; i++)
+  {
+    x=(ssize_t) (code/quantum);
+    code-=quantum*x;
+    tuple[i]=(char) (x+(int) '!');
+    quantum/=85L;
+  }
+  tuple[4]=(char) ((code % 85L)+(int) '!');
+  tuple[5]='\0';
+  return(tuple);
+}
+
+MagickExport void Ascii85Initialize(Image *image)
+{
+  /*
+    Allocate image structure.
+  */
+  if (image->ascii85 == (Ascii85Info *) NULL)
+    image->ascii85=(Ascii85Info *) AcquireMagickMemory(sizeof(*image->ascii85));
+  if (image->ascii85 == (Ascii85Info *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(image->ascii85,0,sizeof(*image->ascii85));
+  image->ascii85->line_break=MaxLineExtent << 1;
+  image->ascii85->offset=0;
+}
+
+MagickExport void Ascii85Flush(Image *image)
+{
+  register char
+    *tuple;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->ascii85 != (Ascii85Info *) NULL);
+  if (image->ascii85->offset > 0)
+    {
+      image->ascii85->buffer[image->ascii85->offset]='\0';
+      image->ascii85->buffer[image->ascii85->offset+1]='\0';
+      image->ascii85->buffer[image->ascii85->offset+2]='\0';
+      tuple=Ascii85Tuple(image->ascii85->buffer);
+      (void) WriteBlob(image,(size_t) image->ascii85->offset+1,
+        (const unsigned char *) (*tuple == 'z' ? "!!!!" : tuple));
+    }
+  (void) WriteBlobByte(image,'~');
+  (void) WriteBlobByte(image,'>');
+  (void) WriteBlobByte(image,'\n');
+}
+
+MagickExport void Ascii85Encode(Image *image,const unsigned char code)
+{
+  register char
+    *q;
+
+  register unsigned char
+    *p;
+
+  ssize_t
+    n;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image->ascii85 != (Ascii85Info *) NULL);
+  image->ascii85->buffer[image->ascii85->offset]=code;
+  image->ascii85->offset++;
+  if (image->ascii85->offset < 4)
+    return;
+  p=image->ascii85->buffer;
+  for (n=image->ascii85->offset; n >= 4; n-=4)
+  {
+    for (q=Ascii85Tuple(p); *q != '\0'; q++)
+    {
+      image->ascii85->line_break--;
+      if ((image->ascii85->line_break < 0) && (*q != '%'))
+        {
+          (void) WriteBlobByte(image,'\n');
+          image->ascii85->line_break=2*MaxLineExtent;
+        }
+      (void) WriteBlobByte(image,(unsigned char) *q);
+    }
+    p+=8;
+  }
+  image->ascii85->offset=n;
+  p-=4;
+  for (n=0; n < 4; n++)
+    image->ascii85->buffer[n]=(*p++);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H u f f m a n D e c o d e I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  HuffmanDecodeImage() uncompresses an image via Huffman-coding.
+%
+%  The format of the HuffmanDecodeImage method is:
+%
+%      MagickBooleanType HuffmanDecodeImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType HuffmanDecodeImage(Image *image)
+{
+#define HashSize  1021
+#define MBHashA  293
+#define MBHashB  2695
+#define MWHashA  3510
+#define MWHashB  1178
+
+#define InitializeHashTable(hash,table,a,b) \
+{ \
+  entry=table; \
+  while (entry->code != 0) \
+  {  \
+    hash[((entry->length+a)*(entry->code+b)) % HashSize]=(HuffmanTable *) entry; \
+    entry++; \
+  } \
+}
+
+#define InputBit(bit)  \
+{  \
+  if ((mask & 0xff) == 0)  \
+    {  \
+      byte=ReadBlobByte(image);  \
+      if (byte == EOF)  \
+        break;  \
+      mask=0x80;  \
+    }  \
+  runlength++;  \
+  bit=(size_t) ((byte & mask) != 0 ? 0x01 : 0x00); \
+  mask>>=1;  \
+  if (bit != 0)  \
+    runlength=0;  \
+}
+
+  CacheView
+    *image_view;
+
+  const HuffmanTable
+    *entry;
+
+  ExceptionInfo
+    *exception;
+
+  HuffmanTable
+    **mb_hash,
+    **mw_hash;
+
+  int
+    byte;
+
+  MagickBooleanType
+    proceed;
+
+  Quantum
+    index;
+
+  register ssize_t
+    i;
+
+  register unsigned char
+    *p;
+
+  size_t
+    bit,
+    code,
+    mask,
+    length,
+    null_lines,
+    runlength;
+
+  ssize_t
+    count,
+    y;
+
+  unsigned char
+    *scanline;
+
+  unsigned int
+    bail,
+    color;
+
+  /*
+    Allocate buffers.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  mb_hash=(HuffmanTable **) AcquireQuantumMemory(HashSize,sizeof(*mb_hash));
+  mw_hash=(HuffmanTable **) AcquireQuantumMemory(HashSize,sizeof(*mw_hash));
+  scanline=(unsigned char *) AcquireQuantumMemory((size_t) image->columns,
+    sizeof(*scanline));
+  if ((mb_hash == (HuffmanTable **) NULL) ||
+      (mw_hash == (HuffmanTable **) NULL) ||
+      (scanline == (unsigned char *) NULL))
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  /*
+    Initialize Huffman tables.
+  */
+  for (i=0; i < HashSize; i++)
+  {
+    mb_hash[i]=(HuffmanTable *) NULL;
+    mw_hash[i]=(HuffmanTable *) NULL;
+  }
+  InitializeHashTable(mw_hash,TWTable,MWHashA,MWHashB);
+  InitializeHashTable(mw_hash,MWTable,MWHashA,MWHashB);
+  InitializeHashTable(mw_hash,EXTable,MWHashA,MWHashB);
+  InitializeHashTable(mb_hash,TBTable,MBHashA,MBHashB);
+  InitializeHashTable(mb_hash,MBTable,MBHashA,MBHashB);
+  InitializeHashTable(mb_hash,EXTable,MBHashA,MBHashB);
+  /*
+    Uncompress 1D Huffman to runlength encoded pixels.
+  */
+  byte=0;
+  mask=0;
+  null_lines=0;
+  runlength=0;
+  while (runlength < 11)
+   InputBit(bit);
+  do { InputBit(bit); } while ((int) bit == 0);
+  image->x_resolution=204.0;
+  image->y_resolution=196.0;
+  image->units=PixelsPerInchResolution;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; ((y < (ssize_t) image->rows) && (null_lines < 3)); )
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    /*
+      Initialize scanline to white.
+    */
+    p=scanline;
+    for (x=0; x < (ssize_t) image->columns; x++)
+      *p++=(unsigned char) 0;
+    /*
+      Decode Huffman encoded scanline.
+    */
+    color=MagickTrue;
+    code=0;
+    count=0;
+    length=0;
+    runlength=0;
+    x=0;
+    for ( ; ; )
+    {
+      if (byte == EOF)
+        break;
+      if (x >= (ssize_t) image->columns)
+        {
+          while (runlength < 11)
+            InputBit(bit);
+          do { InputBit(bit); } while ((int) bit == 0);
+          break;
+        }
+      bail=MagickFalse;
+      do
+      {
+        if (runlength < 11)
+          InputBit(bit)
+        else
+          {
+            InputBit(bit);
+            if ((int) bit != 0)
+              {
+                null_lines++;
+                if (x != 0)
+                  null_lines=0;
+                bail=MagickTrue;
+                break;
+              }
+          }
+        code=(code << 1)+(size_t) bit;
+        length++;
+      } while (code == 0);
+      if (bail != MagickFalse)
+        break;
+      if (length > 13)
+        {
+          while (runlength < 11)
+           InputBit(bit);
+          do { InputBit(bit); } while ((int) bit == 0);
+          break;
+        }
+      if (color != MagickFalse)
+        {
+          if (length < 4)
+            continue;
+          entry=mw_hash[((length+MWHashA)*(code+MWHashB)) % HashSize];
+        }
+      else
+        {
+          if (length < 2)
+            continue;
+          entry=mb_hash[((length+MBHashA)*(code+MBHashB)) % HashSize];
+        }
+      if (entry == (const HuffmanTable *) NULL)
+        continue;
+      if ((entry->length != length) || (entry->code != code))
+        continue;
+      switch (entry->id)
+      {
+        case TWId:
+        case TBId:
+        {
+          count+=(ssize_t) entry->count;
+          if ((x+count) > (ssize_t) image->columns)
+            count=(ssize_t) image->columns-x;
+          if (count > 0)
+            {
+              if (color != MagickFalse)
+                {
+                  x+=count;
+                  count=0;
+                }
+              else
+                for ( ; count > 0; count--)
+                  scanline[x++]=(unsigned char) 1;
+            }
+          color=(unsigned int)
+            ((color == MagickFalse) ? MagickTrue : MagickFalse);
+          break;
+        }
+        case MWId:
+        case MBId:
+        case EXId:
+        {
+          count+=(ssize_t) entry->count;
+          break;
+        }
+        default:
+          break;
+      }
+      code=0;
+      length=0;
+    }
+    /*
+      Transfer scanline to image pixels.
+    */
+    p=scanline;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      index=(Quantum) (*p++);
+      SetPixelIndex(image,index,q);
+      SetPixelPacket(image,image->colormap+(ssize_t) index,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,LoadImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+    y++;
+  }
+  image_view=DestroyCacheView(image_view);
+  image->rows=(size_t) MagickMax((size_t) y-3,1);
+  image->compression=FaxCompression;
+  /*
+    Free decoder memory.
+  */
+  mw_hash=(HuffmanTable **) RelinquishMagickMemory(mw_hash);
+  mb_hash=(HuffmanTable **) RelinquishMagickMemory(mb_hash);
+  scanline=(unsigned char *) RelinquishMagickMemory(scanline);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H u f f m a n E n c o d e I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  HuffmanEncodeImage() compresses an image via Huffman-coding.
+%
+%  The format of the HuffmanEncodeImage method is:
+%
+%      MagickBooleanType HuffmanEncodeImage(const ImageInfo *image_info,
+%        Image *image,Image *inject_image)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info..
+%
+%    o image: the image.
+%
+%    o inject_image: inject into the image stream.
+%
+*/
+MagickExport MagickBooleanType HuffmanEncodeImage(const ImageInfo *image_info,
+  Image *image,Image *inject_image)
+{
+#define HuffmanOutputCode(entry)  \
+{  \
+  mask=one << (entry->length-1);  \
+  while (mask != 0)  \
+  {  \
+    OutputBit(((entry->code & mask) != 0 ? 1 : 0));  \
+    mask>>=1;  \
+  }  \
+}
+
+#define OutputBit(count)  \
+{  \
+  if (count > 0)  \
+    byte=byte | bit;  \
+  bit>>=1;  \
+  if ((int) (bit & 0xff) == 0)   \
+    {  \
+      if (LocaleCompare(image_info->magick,"FAX") == 0) \
+        (void) WriteBlobByte(image,(unsigned char) byte);  \
+      else \
+        Ascii85Encode(image,byte); \
+      byte='\0';  \
+      bit=(unsigned char) 0x80;  \
+    }  \
+}
+
+  const HuffmanTable
+    *entry;
+
+  ExceptionInfo
+    *exception;
+
+  int
+    k,
+    runlength;
+
+  Image
+    *huffman_image;
+
+  MagickBooleanType
+    proceed;
+
+  register ssize_t
+    i,
+    x;
+
+  register const Quantum
+    *p;
+
+  register unsigned char
+    *q;
+
+  size_t
+    mask,
+    one,
+    width;
+
+  ssize_t
+    n,
+    y;
+
+  unsigned char
+    byte,
+    bit,
+    *scanline;
+
+  /*
+    Allocate scanline buffer.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(inject_image != (Image *) NULL);
+  assert(inject_image->signature == MagickSignature);
+  one=1;
+  width=inject_image->columns;
+  if (LocaleCompare(image_info->magick,"FAX") == 0)
+    width=(size_t) MagickMax(inject_image->columns,1728);
+  scanline=(unsigned char *) AcquireQuantumMemory((size_t) width+1UL,
+    sizeof(*scanline));
+  if (scanline == (unsigned char *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      inject_image->filename);
+  (void) ResetMagickMemory(scanline,0,width*sizeof(*scanline));
+  huffman_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
+  if (huffman_image == (Image *) NULL)
+    {
+      scanline=(unsigned char *) RelinquishMagickMemory(scanline);
+      return(MagickFalse);
+    }
+  (void) SetImageType(huffman_image,BilevelType);
+  byte='\0';
+  bit=(unsigned char) 0x80;
+  if (LocaleCompare(image_info->magick,"FAX") != 0)
+    Ascii85Initialize(image);
+  else
+    {
+      /*
+        End of line.
+      */
+      for (k=0; k < 11; k++)
+        OutputBit(0);
+      OutputBit(1);
+    }
+  /*
+    Compress to 1D Huffman pixels.
+  */
+  exception=(&huffman_image->exception);
+  q=scanline;
+  for (y=0; y < (ssize_t) huffman_image->rows; y++)
+  {
+    p=GetVirtualPixels(huffman_image,0,y,huffman_image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) huffman_image->columns; x++)
+    {
+      *q++=(unsigned char) (GetPixelIntensity(huffman_image,p) >=
+        ((MagickRealType) QuantumRange/2.0) ? 0 : 1);
+      p+=GetPixelChannels(huffman_image);
+    }
+    /*
+      Huffman encode scanline.
+    */
+    q=scanline;
+    for (n=(ssize_t) width; n > 0; )
+    {
+      /*
+        Output white run.
+      */
+      for (runlength=0; ((n > 0) && (*q == 0)); n--)
+      {
+        q++;
+        runlength++;
+      }
+      if (runlength >= 64)
+        {
+          if (runlength < 1792)
+            entry=MWTable+((runlength/64)-1);
+          else
+            entry=EXTable+(MagickMin((size_t) runlength,2560)-1792)/64;
+          runlength-=(long) entry->count;
+          HuffmanOutputCode(entry);
+        }
+      entry=TWTable+MagickMin((size_t) runlength,63);
+      HuffmanOutputCode(entry);
+      if (n != 0)
+        {
+          /*
+            Output black run.
+          */
+          for (runlength=0; ((*q != 0) && (n > 0)); n--)
+          {
+            q++;
+            runlength++;
+          }
+          if (runlength >= 64)
+            {
+              entry=MBTable+((runlength/64)-1);
+              if (runlength >= 1792)
+                entry=EXTable+(MagickMin((size_t) runlength,2560)-1792)/64;
+              runlength-=(long) entry->count;
+              HuffmanOutputCode(entry);
+            }
+          entry=TBTable+MagickMin((size_t) runlength,63);
+          HuffmanOutputCode(entry);
+        }
+    }
+    /*
+      End of line.
+    */
+    for (k=0; k < 11; k++)
+      OutputBit(0);
+    OutputBit(1);
+    q=scanline;
+    if (GetPreviousImageInList(huffman_image) == (Image *) NULL)
+      {
+        proceed=SetImageProgress(huffman_image,LoadImageTag,y,
+          huffman_image->rows);
+        if (proceed == MagickFalse)
+          break;
+      }
+  }
+  /*
+    End of page.
+  */
+  for (i=0; i < 6; i++)
+  {
+    for (k=0; k < 11; k++)
+      OutputBit(0);
+    OutputBit(1);
+  }
+  /*
+    Flush bits.
+  */
+  if (((int) bit != 0x80) != 0)
+    {
+      if (LocaleCompare(image_info->magick,"FAX") == 0)
+        (void) WriteBlobByte(image,byte);
+      else
+        Ascii85Encode(image,byte);
+    }
+  if (LocaleCompare(image_info->magick,"FAX") != 0)
+    Ascii85Flush(image);
+  huffman_image=DestroyImage(huffman_image);
+  scanline=(unsigned char *) RelinquishMagickMemory(scanline);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L Z W E n c o d e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LZWEncodeImage() compresses an image via LZW-coding specific to Postscript
+%  Level II or Portable Document Format.
+%
+%  The format of the LZWEncodeImage method is:
+%
+%      MagickBooleanType LZWEncodeImage(Image *image,const size_t length,
+%        unsigned char *pixels)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o length:  A value that specifies the number of pixels to compress.
+%
+%    o pixels: the address of an unsigned array of characters containing the
+%      pixels to compress.
+%
+*/
+MagickExport MagickBooleanType LZWEncodeImage(Image *image,const size_t length,
+  unsigned char *pixels)
+{
+#define LZWClr  256UL  /* Clear Table Marker */
+#define LZWEod  257UL  /* End of Data marker */
+#define OutputCode(code) \
+{ \
+    accumulator+=code << (32-code_width-number_bits); \
+    number_bits+=code_width; \
+    while (number_bits >= 8) \
+    { \
+        (void) WriteBlobByte(image,(unsigned char) (accumulator >> 24)); \
+        accumulator=accumulator << 8; \
+        number_bits-=8; \
+    } \
+}
+
+  typedef struct _TableType
+  {
+    ssize_t
+      prefix,
+      suffix,
+      next;
+  } TableType;
+
+  register ssize_t
+    i;
+
+  size_t
+    accumulator,
+    number_bits,
+    code_width,
+    last_code,
+    next_index;
+
+  ssize_t
+    index;
+
+  TableType
+    *table;
+
+  /*
+    Allocate string table.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(pixels != (unsigned char *) NULL);
+  table=(TableType *) AcquireQuantumMemory(1UL << 12,sizeof(*table));
+  if (table == (TableType *) NULL)
+    return(MagickFalse);
+  /*
+    Initialize variables.
+  */
+  accumulator=0;
+  code_width=9;
+  number_bits=0;
+  last_code=0;
+  OutputCode(LZWClr);
+  for (index=0; index < 256; index++)
+  {
+    table[index].prefix=(-1);
+    table[index].suffix=(short) index;
+    table[index].next=(-1);
+  }
+  next_index=LZWEod+1;
+  code_width=9;
+  last_code=(size_t) pixels[0];
+  for (i=1; i < (ssize_t) length; i++)
+  {
+    /*
+      Find string.
+    */
+    index=(ssize_t) last_code;
+    while (index != -1)
+      if ((table[index].prefix != (ssize_t) last_code) ||
+          (table[index].suffix != (ssize_t) pixels[i]))
+        index=table[index].next;
+      else
+        {
+          last_code=(size_t) index;
+          break;
+        }
+    if (last_code != (size_t) index)
+      {
+        /*
+          Add string.
+        */
+        OutputCode(last_code);
+        table[next_index].prefix=(ssize_t) last_code;
+        table[next_index].suffix=(short) pixels[i];
+        table[next_index].next=table[last_code].next;
+        table[last_code].next=(ssize_t) next_index;
+        next_index++;
+        /*
+          Did we just move up to next bit width?
+        */
+        if ((next_index >> code_width) != 0)
+          {
+            code_width++;
+            if (code_width > 12)
+              {
+                /*
+                  Did we overflow the max bit width?
+                */
+                code_width--;
+                OutputCode(LZWClr);
+                for (index=0; index < 256; index++)
+                {
+                  table[index].prefix=(-1);
+                  table[index].suffix=index;
+                  table[index].next=(-1);
+                }
+                next_index=LZWEod+1;
+                code_width=9;
+              }
+            }
+          last_code=(size_t) pixels[i];
+      }
+  }
+  /*
+    Flush tables.
+  */
+  OutputCode(last_code);
+  OutputCode(LZWEod);
+  if (number_bits != 0)
+    (void) WriteBlobByte(image,(unsigned char) (accumulator >> 24));
+  table=(TableType *) RelinquishMagickMemory(table);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a c k b i t s E n c o d e I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PackbitsEncodeImage() compresses an image via Macintosh Packbits encoding
+%  specific to Postscript Level II or Portable Document Format.  To ensure
+%  portability, the binary Packbits bytes are encoded as ASCII Base-85.
+%
+%  The format of the PackbitsEncodeImage method is:
+%
+%      MagickBooleanType PackbitsEncodeImage(Image *image,const size_t length,
+%        unsigned char *pixels)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o length:  A value that specifies the number of pixels to compress.
+%
+%    o pixels: the address of an unsigned array of characters containing the
+%      pixels to compress.
+%
+*/
+MagickExport MagickBooleanType PackbitsEncodeImage(Image *image,
+  const size_t length,unsigned char *pixels)
+{
+  int
+    count;
+
+  register ssize_t
+    i,
+    j;
+
+  unsigned char
+    *packbits;
+
+  /*
+    Compress pixels with Packbits encoding.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(pixels != (unsigned char *) NULL);
+  packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
+  if (packbits == (unsigned char *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  for (i=(ssize_t) length; i != 0; )
+  {
+    switch (i)
+    {
+      case 1:
+      {
+        i--;
+        (void) WriteBlobByte(image,(unsigned char) 0);
+        (void) WriteBlobByte(image,*pixels);
+        break;
+      }
+      case 2:
+      {
+        i-=2;
+        (void) WriteBlobByte(image,(unsigned char) 1);
+        (void) WriteBlobByte(image,*pixels);
+        (void) WriteBlobByte(image,pixels[1]);
+        break;
+      }
+      case 3:
+      {
+        i-=3;
+        if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
+          {
+            (void) WriteBlobByte(image,(unsigned char) ((256-3)+1));
+            (void) WriteBlobByte(image,*pixels);
+            break;
+          }
+        (void) WriteBlobByte(image,(unsigned char) 2);
+        (void) WriteBlobByte(image,*pixels);
+        (void) WriteBlobByte(image,pixels[1]);
+        (void) WriteBlobByte(image,pixels[2]);
+        break;
+      }
+      default:
+      {
+        if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
+          {
+            /*
+              Packed run.
+            */
+            count=3;
+            while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
+            {
+              count++;
+              if (count >= 127)
+                break;
+            }
+            i-=count;
+            (void) WriteBlobByte(image,(unsigned char) ((256-count)+1));
+            (void) WriteBlobByte(image,*pixels);
+            pixels+=count;
+            break;
+          }
+        /*
+          Literal run.
+        */
+        count=0;
+        while ((*(pixels+count) != *(pixels+count+1)) ||
+               (*(pixels+count+1) != *(pixels+count+2)))
+        {
+          packbits[count+1]=pixels[count];
+          count++;
+          if (((ssize_t) count >= (i-3)) || (count >= 127))
+            break;
+        }
+        i-=count;
+        *packbits=(unsigned char) (count-1);
+        for (j=0; j <= (ssize_t) count; j++)
+          (void) WriteBlobByte(image,packbits[j]);
+        pixels+=count;
+        break;
+      }
+    }
+  }
+  (void) WriteBlobByte(image,(unsigned char) 128);  /* EOD marker */
+  packbits=(unsigned char *) RelinquishMagickMemory(packbits);
+  return(MagickTrue);
+}
+
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Z L I B E n c o d e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ZLIBEncodeImage compresses an image via ZLIB-coding specific to
+%  Postscript Level II or Portable Document Format.
+%
+%  The format of the ZLIBEncodeImage method is:
+%
+%      MagickBooleanType ZLIBEncodeImage(Image *image,const size_t length,
+%        unsigned char *pixels)
+%
+%  A description of each parameter follows:
+%
+%    o file: the address of a structure of type FILE.  ZLIB encoded pixels
+%      are written to this file.
+%
+%    o length:  A value that specifies the number of pixels to compress.
+%
+%    o pixels: the address of an unsigned array of characters containing the
+%      pixels to compress.
+%
+*/
+
+static voidpf AcquireZIPMemory(voidpf context,unsigned int items,
+  unsigned int size)
+{
+  (void) context;
+  return((voidpf) AcquireQuantumMemory(items,size));
+}
+
+static void RelinquishZIPMemory(voidpf context,voidpf memory)
+{
+  (void) context;
+  memory=RelinquishMagickMemory(memory);
+}
+
+MagickExport MagickBooleanType ZLIBEncodeImage(Image *image,const size_t length,
+  unsigned char *pixels)
+{
+  int
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    compress_packets;
+
+  unsigned char
+    *compress_pixels;
+
+  z_stream
+    stream;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  compress_packets=(size_t) (1.001*length+12);
+  compress_pixels=(unsigned char *) AcquireQuantumMemory(compress_packets,
+    sizeof(*compress_pixels));
+  if (compress_pixels == (unsigned char *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  stream.next_in=pixels;
+  stream.avail_in=(unsigned int) length;
+  stream.next_out=compress_pixels;
+  stream.avail_out=(unsigned int) compress_packets;
+  stream.zalloc=AcquireZIPMemory;
+  stream.zfree=RelinquishZIPMemory;
+  stream.opaque=(voidpf) NULL;
+  status=deflateInit(&stream,(int) (image->quality ==
+    UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9)));
+  if (status == Z_OK)
+    {
+      status=deflate(&stream,Z_FINISH);
+      if (status == Z_STREAM_END)
+        status=deflateEnd(&stream);
+      else
+        (void) deflateEnd(&stream);
+      compress_packets=(size_t) stream.total_out;
+    }
+  if (status != Z_OK)
+    ThrowBinaryException(CoderError,"UnableToZipCompressImage",image->filename)
+  else
+    for (i=0; i < (ssize_t) compress_packets; i++)
+      (void) WriteBlobByte(image,compress_pixels[i]);
+  compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
+  return(status == Z_OK ? MagickTrue : MagickFalse);
+}
+#else
+MagickExport MagickBooleanType ZLIBEncodeImage(Image *image,
+  const size_t magick_unused(length),unsigned char *magick_unused(pixels))
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (ZIP)",
+    image->filename);
+  return(MagickFalse);
+}
+#endif
diff --git a/MagickCore/compress.h b/MagickCore/compress.h
new file mode 100644
index 0000000..313ee3b
--- /dev/null
+++ b/MagickCore/compress.h
@@ -0,0 +1,70 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image compression/decompression methods.
+*/
+#ifndef _MAGICKCORE_COMPRESS_H
+#define _MAGICKCORE_COMPRESS_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedCompression,
+  B44ACompression,
+  B44Compression,
+  BZipCompression,
+  DXT1Compression,
+  DXT3Compression,
+  DXT5Compression,
+  FaxCompression,
+  Group4Compression,
+  JBIG1Compression,        /* ISO/IEC std 11544 / ITU-T rec T.82 */
+  JBIG2Compression,        /* ISO/IEC std 14492 / ITU-T rec T.88 */
+  JPEG2000Compression,     /* ISO/IEC std 15444-1 */
+  JPEGCompression,
+  LosslessJPEGCompression,
+  LZMACompression,         /* Lempel-Ziv-Markov chain algorithm */
+  LZWCompression,
+  NoCompression,
+  PizCompression,
+  Pxr24Compression,
+  RLECompression,
+  ZipCompression,
+  ZipSCompression
+} CompressionType;
+
+typedef struct _Ascii85Info
+  Ascii85Info;
+
+extern MagickExport MagickBooleanType
+  HuffmanDecodeImage(Image *),
+  HuffmanEncodeImage(const ImageInfo *,Image *,Image *),
+  LZWEncodeImage(Image *,const size_t,unsigned char *),
+  PackbitsEncodeImage(Image *,const size_t,unsigned char *),
+  ZLIBEncodeImage(Image *,const size_t,unsigned char *);
+
+extern MagickExport void
+  Ascii85Encode(Image *,const unsigned char),
+  Ascii85Flush(Image *),
+  Ascii85Initialize(Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/config.h_vms b/MagickCore/config.h_vms
new file mode 100644
index 0000000..012e55f
--- /dev/null
+++ b/MagickCore/config.h_vms
@@ -0,0 +1,286 @@
+/* magick/config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef MAGICKCORE_HAVE_DOPRNT
+
+/* Define if you have a working `mmap' system call.  */
+#define MAGICKCORE_HAVE_MMAP 1
+
+/* Define if you have the vprintf function.  */
+#define MAGICKCORE_HAVE_VPRINTF 1
+
+/* Define as __inline if that's what the C compiler calls it.  */
+#define MAGICKCORE_inline __inline
+
+/* Define as the return type of signal handlers (int or void).  */
+#define MAGICKCORE_RETSIGTYPE void
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly.  */
+#undef MAGICKCORE_STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files.  */
+#define MAGICKCORE_STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#define MAGICKCORE_TIME_WITH_SYS_TIME 1
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef MAGICKCORE_WORDS_BIGENDIAN
+
+/* Define if the X Window System is missing or not being used.  */
+#undef MAGICKCORE_X_DISPLAY_MISSING
+
+/* The number of bytes in a int.  */
+#define MAGICKCORE_SIZEOF_INT 4
+
+/* The number of bytes in a long long.  */
+#define MAGICKCORE_SIZEOF_UNSIGNED_LONG_LONG 8
+
+/* Define if you have the getcwd function.  */
+#define MAGICKCORE_HAVE_GETCWD 1
+
+/* Define if you have the getexecname function.  */
+#undef MAGICKCORE_HAVE_GETEXECNAME
+
+/* Define if you have the getpagesize function.  */
+#define MAGICKCORE_HAVE_GETPAGESIZE 1
+
+/* Define if you have the gettimeofday function.  */
+#define MAGICKCORE_HAVE_GETTIMEOFDAY 1
+
+/* Define if you have the mkdir function.  */
+#define MAGICKCORE_HAVE_MKDIR 1
+
+/* Define if you have the poll function.  */
+#undef MAGICKCORE_HAVE_POLL
+
+/* Define if you have the select function.  */
+#undef MAGICKCORE_HAVE_SELECT
+
+/* Define if you have the snprintf function.  */
+#undef MAGICKCORE_HAVE_SNPRINTF
+
+/* Define if you have the strchr function.  */
+#define MAGICKCORE_HAVE_STRCHR 1
+
+/* Define if you have the strerror function.  */
+#define MAGICKCORE_HAVE_STRERROR 1
+
+/* Define if you have the strtol function.  */
+#define MAGICKCORE_HAVE_STRTOL 1
+
+/* Define if you have the sysconf function.  */
+#define MAGICKCORE_HAVE_SYSCONF 1
+
+/* Define if you have the tempnam function.  */
+#define MAGICKCORE_HAVE_TEMPNAM 1
+
+/* Define if you have the vsnprintf function.  */
+#undef MAGICKCORE_HAVE_VSNPRINTF
+
+/* Define if you have the <dirent.h> header file.  */
+#define MAGICKCORE_HAVE_DIRENT_H 1
+
+/* Define if you have the <errno.h> header file.  */
+#define MAGICKCORE_HAVE_ERRNO_H 1
+
+/* Define if you have the <fcntl.h> header file.  */
+#define MAGICKCORE_HAVE_FCNTL_H 1
+
+/* Define if you have the <ft2build.h> header file.  */
+#define MAGICKCORE_HAVE_FT2BUILD_H 1
+
+/* Define if you have the <freetype/freetype.h> header file.  */
+#define MAGICKCORE_HAVE_FREETYPE_FREETYPE_H 1
+
+/* Define if you have the <hdf.h> header file.  */
+#define MAGICKCORE_HAVE_HDF_H 1
+
+/* Define if you have the <hdf/hdf.h> header file.  */
+#undef MAGICKCORE_HAVE_HDF_HDF_H
+
+/* Define if you have the <libxml/xml-error.h> header file.  */
+#undef MAGICKCORE_HAVE_LIBXML_XML_ERROR_H
+
+/* Define if you have the <libxml/xmlerror.h> header file.  */
+#undef MAGICKCORE_HAVE_LIBXML_XMLERROR_H
+
+/* Define if you have the <jp2conf.h> header file.  */
+#undef MAGICKCORE_HAVE_JP2CONF_H
+
+/* Define if you have the <malloc.h> header file.  */
+#undef MAGICKCORE_HAVE_MALLOC_H
+
+/* Define if you have the <math.h> header file.  */
+#define MAGICKCORE_HAVE_MATH_H 1
+
+/* Define if you have the <memory.h> header file.  */
+#define MAGICKCORE_HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file.  */
+#undef MAGICKCORE_HAVE_NDIR_H
+
+/* Define if you have the <pwd.h> header file.  */
+#define MAGICKCORE_HAVE_PWD_H 1
+
+/* Define if you have the <stdarg.h> header file.  */
+#define MAGICKCORE_HAVE_STDARG_H 1
+
+/* Define if you have the <stdint.h> header file.  */
+#undef MAGICKCORE_HAVE_STDINT_H
+
+/* Define if you have the <string.h> header file.  */
+#define MAGICKCORE_HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef MAGICKCORE_HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef MAGICKCORE_HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/select.h> header file.  */
+#define MAGICKCORE_HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/stat.h> header file.  */
+#define MAGICKCORE_HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file.  */
+#define MAGICKCORE_HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/types.h> header file.  */
+#define MAGICKCORE_HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <tiffconf.h> header file.  */
+#define MAGICKCORE_HAVE_TIFFCONF_H 1
+
+/* Define if you have the <unistd.h> header file.  */
+#define MAGICKCORE_HAVE_UNISTD_H 1
+
+/* Define if you have the <varargs.h> header file.  */
+#undef MAGICKCORE_HAVE_VARARGS_H
+
+/* Define if using libltdl to create dynamically loadable modules */
+#undef MAGICKCORE_LTDL_DELEGATE
+
+/* Location of coder modules */
+#undef MAGICKCORE_MagickModulesPath
+
+/* Number of bits in a pixel Quantum (8 or 16) */
+#define MAGICKCORE_QUANTUM_DEPTH 16
+
+/* Pixel cache threshold (default 2047MB) */
+#undef MAGICKCORE_PixelCacheThreshold
+
+/* Define to specify default TrueType font path. */
+#undef MAGICKCORE_TT_FONT_PATH
+
+/* Location of X11 configure files */
+#undef MAGICKCORE_X11ConfigurePath
+
+/* Define if you have Posix thread methods. */
+#undef MAGICKCORE_HasPTHREADS
+
+/* Define if you have zlib compression library */
+#define MAGICKCORE_ZLIB_DELEGATE 1
+
+/* Define if you have the bzip2 library */
+#define MAGICKCORE_BZLIB_DELEGATE 1
+
+/* Define if you have X11 library */
+#define MAGICKCORE_X11_DELEGATE 1
+
+/* X11 server supports shared memory extension */
+#undef MAGICKCORE_HAVE_SHARED_MEMORY
+
+/* X11 server supports shape extension */
+#undef MAGICKCORE_HAVE_SHAPE
+
+/* Define if you have Display Postscript */
+#undef MAGICKCORE_DPS_DELEGATE
+
+/* Define if you have FlashPIX library */
+#undef MAGICKCORE_FPX_DELEGATE
+
+/* Define if you have LCMS library */
+#undef MAGICKCORE_LCMS_DELEGATE
+
+/* Define if you have PNG library */
+#define MAGICKCORE_PNG_DELEGATE 1
+
+/* Define if you have JPEG library */
+#define MAGICKCORE_JPEG_DELEGATE 1
+
+/* Define if you have JPEG version 2 Jasper library */
+#define MAGICKCORE_JP2_DELEGATE 1
+
+/* Define if you have Ghostscript library */
+#undef MAGICKCORE_GS_DELEGATE
+
+/* Define if you have FreeType (TrueType font) library */
+#define MAGICKCORE_FREETYPE_DELEGATE 1
+
+/* Define if you have TIFF library */
+#define MAGICKCORE_TIFF_DELEGATE 1
+
+/* Define if you have HDF4 library */
+#define MAGICKCORE_HDF_DELEGATE 1
+
+/* Define if you have JBIG library */
+#define MAGICKCORE_JBIG_DELEGATE 1
+
+/* Define if you have XML library */
+#undef MAGICKCORE_XML_DELEGATE
+
+/* Define if you have WMF library */
+#undef MAGICKCORE_WMF_DELEGATE
+
+/* Define if you have sys_errlist in libc */
+#undef MAGICKCORE_HAVE_SYS_ERRLIST
+
+/* Define directory where ImageMagick/delegates.xml lives. */
+#undef MAGICKCORE_MagickConfigurePath
+
+/* define MAGICKCORE_if bool is a built-in type */
+#define MAGICKCORE_HAVE_BOOL 1
+
+/* define MAGICKCORE_if the compiler supports const_cast<> */
+#undef MAGICKCORE_HAVE_CONST_CAST
+
+/* define MAGICKCORE_if the compiler supports default template parameters */
+#undef MAGICKCORE_HAVE_DEFAULT_TEMPLATE_PARAMETERS
+
+/* define MAGICKCORE_if the compiler supports exceptions */
+#undef MAGICKCORE_HAVE_EXCEPTIONS
+
+/* define MAGICKCORE_if the compiler implements namespaces */
+#undef MAGICKCORE_HAVE_NAMESPACES
+
+/* define MAGICKCORE_if the compiler supports the explicit keyword */
+#undef MAGICKCORE_HAVE_EXPLICIT
+
+/* define MAGICKCORE_if the compiler supports ISO C++ standard library */
+#define MAGICKCORE_HAVE_STD 1
+
+/* define MAGICKCORE_if the compiler supports Standard Template Library */
+#define MAGICKCORE_HAVE_STL 1
+
+/* define MAGICKCORE_if the compiler supports the mutable keyword */
+#undef MAGICKCORE_HAVE_MUTABLE
+
+/* define MAGICKCORE_if the compiler accepts the new for scoping rules */
+#undef MAGICKCORE_HAVE_NEW_FOR_SCOPING
+
+/* define MAGICKCORE_if the compiler supports static_cast<> */
+#undef MAGICKCORE_HAVE_STATIC_CAST
+
+/* define MAGICKCORE_if the compiler supports basic templates */
+#undef MAGICKCORE_HAVE_TEMPLATES
+
+#define MAGICKCORE_LIBRARY_RELATIVE_PATH "/"
+
+#define MAGICKCORE_HAVE_MKSTEMP 1
+
+#define round nint
+
+#define MAGICKCORE_CIPHER_SUPPORT 1
diff --git a/MagickCore/configure.c b/MagickCore/configure.c
new file mode 100644
index 0000000..b9b2bee
--- /dev/null
+++ b/MagickCore/configure.c
@@ -0,0 +1,1271 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%          CCCC   OOO   N   N  FFFFF  IIIII   GGGG  U   U  RRRR   EEEEE       %
+%         C      O   O  NN  N  F        I    G      U   U  R   R  E           %
+%         C      O   O  N N N  FFF      I    G GG   U   U  RRRR   EEE         %
+%         C      O   O  N  NN  F        I    G   G  U   U  R R    E           %
+%          CCCC   OOO   N   N  F      IIIII   GGG    UUU   R  R   EEEEE       %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Configure Methods                     %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define ConfigureFilename  "configure.xml"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _ConfigureMapInfo
+{
+  const char
+    *name,
+    *value;
+} ConfigureMapInfo;
+
+/*
+  Static declarations.
+*/
+static const ConfigureMapInfo
+  ConfigureMap[] =
+  {
+    { "NAME", "ImageMagick" }
+  };
+
+static LinkedListInfo
+  *configure_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *configure_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_configure = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeConfigureList(ExceptionInfo *),
+  LoadConfigureLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n f i g u r e C o m p o n e n t G e n e s i s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConfigureComponentGenesis() instantiates the configure component.
+%
+%  The format of the ConfigureComponentGenesis method is:
+%
+%      MagickBooleanType ConfigureComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType ConfigureComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&configure_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n f i g u r e C o m p o n e n t T e r m i n u s                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConfigureComponentTerminus() destroys the configure component.
+%
+%  The format of the ConfigureComponentTerminus method is:
+%
+%      ConfigureComponentTerminus(void)
+%
+*/
+
+static void *DestroyConfigureElement(void *configure_info)
+{
+  register ConfigureInfo
+    *p;
+
+  p=(ConfigureInfo *) configure_info;
+  if (p->exempt == MagickFalse)
+    {
+      if (p->value != (char *) NULL)
+        p->value=DestroyString(p->value);
+      if (p->name != (char *) NULL)
+        p->name=DestroyString(p->name);
+      if (p->path != (char *) NULL)
+        p->path=DestroyString(p->path);
+    }
+  p=(ConfigureInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void ConfigureComponentTerminus(void)
+{
+  if (configure_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&configure_semaphore);
+  LockSemaphoreInfo(configure_semaphore);
+  if (configure_list != (LinkedListInfo *) NULL)
+    configure_list=DestroyLinkedList(configure_list,DestroyConfigureElement);
+  configure_list=(LinkedListInfo *) NULL;
+  instantiate_configure=MagickFalse;
+  UnlockSemaphoreInfo(configure_semaphore);
+  DestroySemaphoreInfo(&configure_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y C o n f i g u r e O p t i o n s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyConfigureOptions() releases memory associated with an configure
+%  options.
+%
+%  The format of the DestroyProfiles method is:
+%
+%      LinkedListInfo *DestroyConfigureOptions(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+
+static void *DestroyOptions(void *option)
+{
+  return(DestroyStringInfo((StringInfo *) option));
+}
+
+MagickExport LinkedListInfo *DestroyConfigureOptions(LinkedListInfo *options)
+{
+  assert(options != (LinkedListInfo *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(DestroyLinkedList(options,DestroyOptions));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C o n f i g u r e I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureInfo() searches the configure list for the specified name and if
+%  found returns attributes for that element.
+%
+%  The format of the GetConfigureInfo method is:
+%
+%      const ConfigureInfo *GetConfigureInfo(const char *name,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o configure_info: GetConfigureInfo() searches the configure list for the
+%      specified name and if found returns attributes for that element.
+%
+%    o name: the configure name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const ConfigureInfo *GetConfigureInfo(const char *name,
+  ExceptionInfo *exception)
+{
+  register const ConfigureInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((configure_list == (LinkedListInfo *) NULL) ||
+      (instantiate_configure == MagickFalse))
+    if (InitializeConfigureList(exception) == MagickFalse)
+      return((const ConfigureInfo *) NULL);
+  if ((configure_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(configure_list) != MagickFalse))
+    return((const ConfigureInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    return((const ConfigureInfo *) GetValueFromLinkedList(configure_list,0));
+  /*
+    Search for configure tag.
+  */
+  LockSemaphoreInfo(configure_semaphore);
+  ResetLinkedListIterator(configure_list);
+  p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_list);
+  while (p != (const ConfigureInfo *) NULL)
+  {
+    if (LocaleCompare(name,p->name) == 0)
+      break;
+    p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_list);
+  }
+  if (p != (ConfigureInfo *) NULL)
+    (void) InsertValueInLinkedList(configure_list,0,
+      RemoveElementByValueFromLinkedList(configure_list,p));
+  UnlockSemaphoreInfo(configure_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o n f i g u r e I n f o L i s t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureInfoList() returns any configure options that match the
+%  specified pattern.
+%
+%  The format of the GetConfigureInfoList function is:
+%
+%      const ConfigureInfo **GetConfigureInfoList(const char *pattern,
+%        size_t *number_options,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_options:  This integer returns the number of configure options in
+%    the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int ConfigureInfoCompare(const void *x,const void *y)
+{
+  const ConfigureInfo
+    **p,
+    **q;
+
+  p=(const ConfigureInfo **) x,
+  q=(const ConfigureInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->name,(*q)->name));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const ConfigureInfo **GetConfigureInfoList(const char *pattern,
+  size_t *number_options,ExceptionInfo *exception)
+{
+  const ConfigureInfo
+    **options;
+
+  register const ConfigureInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_options != (size_t *) NULL);
+  *number_options=0;
+  p=GetConfigureInfo("*",exception);
+  if (p == (const ConfigureInfo *) NULL)
+    return((const ConfigureInfo **) NULL);
+  options=(const ConfigureInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(configure_list)+1UL,sizeof(*options));
+  if (options == (const ConfigureInfo **) NULL)
+    return((const ConfigureInfo **) NULL);
+  /*
+    Generate configure list.
+  */
+  LockSemaphoreInfo(configure_semaphore);
+  ResetLinkedListIterator(configure_list);
+  p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_list);
+  for (i=0; p != (const ConfigureInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      options[i++]=p;
+    p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_list);
+  }
+  UnlockSemaphoreInfo(configure_semaphore);
+  qsort((void *) options,(size_t) i,sizeof(*options),ConfigureInfoCompare);
+  options[i]=(ConfigureInfo *) NULL;
+  *number_options=(size_t) i;
+  return(options);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o n f i g u r e L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureList() returns any configure options that match the specified
+%  pattern.
+%
+%  The format of the GetConfigureList function is:
+%
+%      char **GetConfigureList(const char *pattern,
+%        size_t *number_options,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_options:  This integer returns the number of options in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int ConfigureCompare(const void *x,const void *y)
+{
+  register char
+    **p,
+    **q;
+
+  p=(char **) x;
+  q=(char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetConfigureList(const char *pattern,
+  size_t *number_options,ExceptionInfo *exception)
+{
+  char
+    **options;
+
+  register const ConfigureInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_options != (size_t *) NULL);
+  *number_options=0;
+  p=GetConfigureInfo("*",exception);
+  if (p == (const ConfigureInfo *) NULL)
+    return((char **) NULL);
+  options=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(configure_list)+1UL,sizeof(*options));
+  if (options == (char **) NULL)
+    return((char **) NULL);
+  LockSemaphoreInfo(configure_semaphore);
+  ResetLinkedListIterator(configure_list);
+  p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_list);
+  for (i=0; p != (const ConfigureInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      options[i++]=ConstantString(p->name);
+    p=(const ConfigureInfo *) GetNextValueInLinkedList(configure_list);
+  }
+  UnlockSemaphoreInfo(configure_semaphore);
+  qsort((void *) options,(size_t) i,sizeof(*options),ConfigureCompare);
+  options[i]=(char *) NULL;
+  *number_options=(size_t) i;
+  return(options);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o n f i g u r e O p t i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureOption() returns the value associated with the configure option.
+%
+%  The format of the GetConfigureOption method is:
+%
+%      char *GetConfigureOption(const char *option)
+%
+%  A description of each parameter follows:
+%
+%    o configure_info:  The configure info.
+%
+*/
+MagickExport char *GetConfigureOption(const char *option)
+{
+  const char
+    *value;
+
+  const ConfigureInfo
+    *configure_info;
+
+  ExceptionInfo
+    *exception;
+
+  assert(option != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",option);
+  exception=AcquireExceptionInfo();
+  configure_info=GetConfigureInfo(option,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (configure_info == (ConfigureInfo *) NULL)
+    return((char *) NULL);
+  value=GetConfigureValue(configure_info);
+  if ((value == (const char *) NULL) || (*value == '\0'))
+    return((char *) NULL);
+  return(ConstantString(value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t C o n f i g u r e O p t i o n s                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureOptions() returns any Magick configuration options associated
+%  with the specified filename.
+%
+%  The format of the GetConfigureOptions method is:
+%
+%      LinkedListInfo *GetConfigureOptions(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the configure file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport LinkedListInfo *GetConfigureOptions(const char *filename,
+  ExceptionInfo *exception)
+{
+  char
+    path[MaxTextExtent];
+
+  const char
+    *element;
+
+  LinkedListInfo
+    *options,
+    *paths;
+
+  StringInfo
+    *xml;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) CopyMagickString(path,filename,MaxTextExtent);
+  /*
+    Load XML from configuration files to linked-list.
+  */
+  options=NewLinkedList(0);
+  paths=GetConfigurePaths(filename,exception);
+  if (paths != (LinkedListInfo *) NULL)
+    {
+      ResetLinkedListIterator(paths);
+      element=(const char *) GetNextValueInLinkedList(paths);
+      while (element != (const char *) NULL)
+      {
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
+        (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+          "Searching for configure file: \"%s\"",path);
+        xml=ConfigureFileToStringInfo(path);
+        if (xml != (StringInfo *) NULL)
+          (void) AppendValueToLinkedList(options,xml);
+        element=(const char *) GetNextValueInLinkedList(paths);
+      }
+      paths=DestroyLinkedList(paths,RelinquishMagickMemory);
+    }
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    char
+      *blob;
+
+    blob=(char *) NTResourceToBlob(filename);
+    if (blob != (char *) NULL)
+      {
+        xml=StringToStringInfo(blob);
+        SetStringInfoPath(xml,filename);
+        (void) AppendValueToLinkedList(options,xml);
+        blob=DestroyString(blob);
+      }
+  }
+#endif
+  if (GetNumberOfElementsInLinkedList(options) == 0)
+    (void) ThrowMagickException(exception,GetMagickModule(),ConfigureWarning,
+      "UnableToOpenConfigureFile","`%s'",filename);
+  ResetLinkedListIterator(options);
+  return(options);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t C o n f i g u r e P a t h s                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigurePaths() returns any Magick configuration paths associated
+%  with the specified filename.
+%
+%  The format of the GetConfigurePaths method is:
+%
+%      LinkedListInfo *GetConfigurePaths(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the configure file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport LinkedListInfo *GetConfigurePaths(const char *filename,
+  ExceptionInfo *exception)
+{
+  char
+    path[MaxTextExtent];
+
+  LinkedListInfo
+    *paths;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) CopyMagickString(path,filename,MaxTextExtent);
+  paths=NewLinkedList(0);
+  {
+    char
+      *configure_path;
+
+    /*
+      Search $MAGICK_CONFIGURE_PATH.
+    */
+    configure_path=GetEnvironmentValue("MAGICK_CONFIGURE_PATH");
+    if (configure_path != (char *) NULL)
+      {
+        register char
+          *p,
+          *q;
+
+        for (p=configure_path-1; p != (char *) NULL; )
+        {
+          (void) CopyMagickString(path,p+1,MaxTextExtent);
+          q=strchr(path,DirectoryListSeparator);
+          if (q != (char *) NULL)
+            *q='\0';
+          q=path+strlen(path)-1;
+          if ((q >= path) && (*q != *DirectorySeparator))
+            (void) ConcatenateMagickString(path,DirectorySeparator,
+              MaxTextExtent);
+          (void) AppendValueToLinkedList(paths,ConstantString(path));
+          p=strchr(p+1,DirectoryListSeparator);
+        }
+        configure_path=DestroyString(configure_path);
+      }
+  }
+#if defined(MAGICKCORE_INSTALLED_SUPPORT)
+#if defined(MAGICKCORE_SHARE_PATH)
+  (void) AppendValueToLinkedList(paths,ConstantString(
+    MAGICKCORE_SHARE_PATH));
+#endif
+#if defined(MAGICKCORE_CONFIGURE_PATH)
+  (void) AppendValueToLinkedList(paths,ConstantString(
+    MAGICKCORE_CONFIGURE_PATH));
+#endif
+#if defined(MAGICKCORE_DOCUMENTATION_PATH)
+  (void) AppendValueToLinkedList(paths,ConstantString(
+    MAGICKCORE_DOCUMENTATION_PATH));
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !(defined(MAGICKCORE_CONFIGURE_PATH) || defined(MAGICKCORE_SHARE_PATH))
+  {
+    char
+      *registry_key;
+
+    unsigned char
+      *key_value;
+
+    /*
+      Locate file via registry key.
+    */
+    registry_key="ConfigurePath";
+    key_value=NTRegistryKeyLookup(registry_key);
+    if (key_value != (unsigned char *) NULL)
+      {
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",(char *) key_value,
+          DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        key_value=(unsigned char *) RelinquishMagickMemory(key_value);
+      }
+  }
+#endif
+#else
+  {
+    char
+      *home;
+
+    /*
+      Search under MAGICK_HOME.
+    */
+    home=GetEnvironmentValue("MAGICK_HOME");
+    if (home != (char *) NULL)
+      {
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",home,
+          DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+#else
+        (void) FormatLocaleString(path,MaxTextExtent,"%s/etc/%s/",home,
+          MAGICKCORE_CONFIGURE_RELATIVE_PATH);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        (void) FormatLocaleString(path,MaxTextExtent,"%s/share/%s/",home,
+          MAGICKCORE_SHARE_RELATIVE_PATH);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+#endif
+        home=DestroyString(home);
+      }
+    }
+  if (*GetClientPath() != '\0')
+    {
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+      (void) FormatLocaleString(path,MaxTextExtent,"%s%s",GetClientPath(),
+        DirectorySeparator);
+      (void) AppendValueToLinkedList(paths,ConstantString(path));
+#else
+      char
+        prefix[MaxTextExtent];
+
+      /*
+        Search based on executable directory if directory is known.
+      */
+      (void) CopyMagickString(prefix,GetClientPath(),MaxTextExtent);
+      ChopPathComponents(prefix,1);
+      (void) FormatLocaleString(path,MaxTextExtent,"%s/etc/%s/",prefix,
+        MAGICKCORE_CONFIGURE_RELATIVE_PATH);
+      (void) AppendValueToLinkedList(paths,ConstantString(path));
+      (void) FormatLocaleString(path,MaxTextExtent,"%s/share/%s/",prefix,
+        MAGICKCORE_SHARE_RELATIVE_PATH);
+      (void) AppendValueToLinkedList(paths,ConstantString(path));
+#endif
+    }
+  /*
+    Search current directory.
+  */
+  (void) AppendValueToLinkedList(paths,ConstantString(""));
+#endif
+  {
+    char
+      *home;
+
+    home=GetEnvironmentValue("HOME");
+    if (home == (char *) NULL)
+      home=GetEnvironmentValue("USERPROFILE");
+    if (home != (char *) NULL)
+      {
+        /*
+          Search $HOME/.magick.
+        */
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick%s",home,
+          DirectorySeparator,DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        home=DestroyString(home);
+      }
+  }
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    char
+      module_path[MaxTextExtent];
+
+    if ((NTGetModulePath("CORE_RL_magick_.dll",module_path) != MagickFalse) ||
+        (NTGetModulePath("CORE_DB_magick_.dll",module_path) != MagickFalse))
+      {
+        char
+          *element;
+
+        /*
+          Search module path.
+        */
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",module_path,
+          DirectorySeparator);
+        element=(char *) RemoveElementByValueFromLinkedList(paths,path);
+        if (element != (char *) NULL)
+          element=DestroyString(element);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+      }
+    if (NTGetModulePath("Magick.dll",module_path) != MagickFalse)
+      {
+        /*
+          Search PerlMagick module path.
+        */
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",module_path,
+          DirectorySeparator);
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",module_path,
+          "\\inc\\lib\\auto\\Image\\Magick\\");
+        (void) AppendValueToLinkedList(paths,ConstantString(path));
+      }
+  }
+#endif
+  return(paths);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o n f i g u r e V a l u e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetConfigureValue() returns the value associated with the configure info.
+%
+%  The format of the GetConfigureValue method is:
+%
+%      const char *GetConfigureValue(const ConfigureInfo *configure_info)
+%
+%  A description of each parameter follows:
+%
+%    o configure_info:  The configure info.
+%
+*/
+MagickExport const char *GetConfigureValue(const ConfigureInfo *configure_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(configure_info != (ConfigureInfo *) NULL);
+  assert(configure_info->signature == MagickSignature);
+  return(configure_info->value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e C o n f i g u r e L i s t                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeConfigureList() initializes the configure list.
+%
+%  The format of the InitializeConfigureList method is:
+%
+%      MagickBooleanType InitializeConfigureList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeConfigureList(ExceptionInfo *exception)
+{
+  if ((configure_list == (LinkedListInfo *) NULL) &&
+      (instantiate_configure == MagickFalse))
+    {
+      if (configure_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&configure_semaphore);
+      LockSemaphoreInfo(configure_semaphore);
+      if ((configure_list == (LinkedListInfo *) NULL) &&
+          (instantiate_configure == MagickFalse))
+        {
+          (void) LoadConfigureLists(ConfigureFilename,exception);
+          instantiate_configure=MagickTrue;
+        }
+      UnlockSemaphoreInfo(configure_semaphore);
+    }
+  return(configure_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t C o n f i g u r e I n f o                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListConfigureInfo() lists the configure info to a file.
+%
+%  The format of the ListConfigureInfo method is:
+%
+%      MagickBooleanType ListConfigureInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListConfigureInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const char
+    *name,
+    *path,
+    *value;
+
+  const ConfigureInfo
+    **configure_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_options;
+
+  ssize_t
+    j;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  configure_info=GetConfigureInfoList("*",&number_options,exception);
+  if (configure_info == (const ConfigureInfo **) NULL)
+    return(MagickFalse);
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_options; i++)
+  {
+    if (configure_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,configure_info[i]->path) != 0))
+      {
+        if (configure_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",
+            configure_info[i]->path);
+        (void) FormatLocaleFile(file,"Name          Value\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=configure_info[i]->path;
+    name="unknown";
+    if (configure_info[i]->name != (char *) NULL)
+      name=configure_info[i]->name;
+    (void) FormatLocaleFile(file,"%s",name);
+    for (j=(ssize_t) strlen(name); j <= 12; j++)
+      (void) FormatLocaleFile(file," ");
+    (void) FormatLocaleFile(file," ");
+    value="unknown";
+    if (configure_info[i]->value != (char *) NULL)
+      value=configure_info[i]->value;
+    (void) FormatLocaleFile(file,"%s",value);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  configure_info=(const ConfigureInfo **)
+    RelinquishMagickMemory((void *) configure_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d C o n f i g u r e L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadConfigureList() loads the configure configuration file which provides a
+%  mapping between configure attributes and a configure name.
+%
+%  The format of the LoadConfigureList method is:
+%
+%      MagickBooleanType LoadConfigureList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The configure list in XML format.
+%
+%    o filename:  The configure list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadConfigureList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  ConfigureInfo
+    *configure_info;
+
+  const char
+    *q;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Load the configure map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading configure file \"%s\" ...",filename);
+  if (configure_list == (LinkedListInfo *) NULL)
+    {
+      configure_list=NewLinkedList(0);
+      if (configure_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  configure_info=(ConfigureInfo *) NULL;
+  token=AcquireString((char *) xml);
+  for (q=(char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadConfigureList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<configure") == 0)
+      {
+        /*
+          Configure element.
+        */
+        configure_info=(ConfigureInfo *) AcquireMagickMemory(
+          sizeof(*configure_info));
+        if (configure_info == (ConfigureInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(configure_info,0,sizeof(*configure_info));
+        configure_info->path=ConstantString(filename);
+        configure_info->exempt=MagickFalse;
+        configure_info->signature=MagickSignature;
+        continue;
+      }
+    if (configure_info == (ConfigureInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AppendValueToLinkedList(configure_list,configure_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            configure_info->name);
+        configure_info=(ConfigureInfo *) NULL;
+      }
+    /*
+      Parse configure element.
+    */
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'N':
+      case 'n':
+      {
+        if (LocaleCompare((char *) keyword,"name") == 0)
+          {
+            configure_info->name=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            configure_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      case 'V':
+      case 'v':
+      {
+        if (LocaleCompare((char *) keyword,"value") == 0)
+          {
+            configure_info->value=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d C o n f i g u r e L i s t s                                        %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadConfigureList() loads one or more configure configuration files which
+%  provides a mapping between configure attributes and a configure name.
+%
+%  The format of the LoadConfigureLists method is:
+%
+%      MagickBooleanType LoadConfigureLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadConfigureLists(const char *filename,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Load built-in configure map.
+  */
+  status=MagickFalse;
+  if (configure_list == (LinkedListInfo *) NULL)
+    {
+      configure_list=NewLinkedList(0);
+      if (configure_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  for (i=0; i < (ssize_t) (sizeof(ConfigureMap)/sizeof(*ConfigureMap)); i++)
+  {
+    ConfigureInfo
+      *configure_info;
+
+    register const ConfigureMapInfo
+      *p;
+
+    p=ConfigureMap+i;
+    configure_info=(ConfigureInfo *) AcquireMagickMemory(
+      sizeof(*configure_info));
+    if (configure_info == (ConfigureInfo *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",
+          configure_info->name);
+        continue;
+      }
+    (void) ResetMagickMemory(configure_info,0,sizeof(*configure_info));
+    configure_info->path=(char *) "[built-in]";
+    configure_info->name=(char *) p->name;
+    configure_info->value=(char *) p->value;
+    configure_info->exempt=MagickTrue;
+    configure_info->signature=MagickSignature;
+    status=AppendValueToLinkedList(configure_list,configure_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        configure_info->name);
+  }
+  /*
+    Load external configure map.
+  */
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadConfigureList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
diff --git a/MagickCore/configure.h b/MagickCore/configure.h
new file mode 100644
index 0000000..79caa28
--- /dev/null
+++ b/MagickCore/configure.h
@@ -0,0 +1,69 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore configure methods.
+*/
+#ifndef _MAGICKCORE_CONFIGURE_H
+#define _MAGICKCORE_CONFIGURE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/hashmap.h"
+
+typedef struct _ConfigureInfo
+{
+  char
+    *path,
+    *name,
+    *value;
+                                                                                
+  MagickBooleanType
+    exempt,
+    stealth;
+                                                                                
+  size_t
+    signature;
+} ConfigureInfo;
+
+extern MagickExport char
+  **GetConfigureList(const char *,size_t *,ExceptionInfo *),
+  *GetConfigureOption(const char *);
+
+extern MagickExport const char
+  *GetConfigureValue(const ConfigureInfo *);
+
+extern MagickExport const ConfigureInfo
+  *GetConfigureInfo(const char *,ExceptionInfo *),
+  **GetConfigureInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport LinkedListInfo
+  *DestroyConfigureOptions(LinkedListInfo *),
+  *GetConfigurePaths(const char *,ExceptionInfo *),
+  *GetConfigureOptions(const char *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ConfigureComponentGenesis(void),
+  ListConfigureInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  ConfigureComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/constitute.c b/MagickCore/constitute.c
new file mode 100644
index 0000000..d6c9070
--- /dev/null
+++ b/MagickCore/constitute.c
@@ -0,0 +1,1351 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     CCCC   OOO   N   N  SSSSS  TTTTT  IIIII  TTTTT  U   U  TTTTT  EEEEE     %
+%    C      O   O  NN  N  SS       T      I      T    U   U    T    E         %
+%    C      O   O  N N N  ESSS     T      I      T    U   U    T    EEE       %
+%    C      O   O  N  NN     SS    T      I      T    U   U    T    E         %
+%     CCCC   OOO   N   N  SSSSS    T    IIIII    T     UUU     T    EEEEE     %
+%                                                                             %
+%                                                                             %
+%                  MagickCore Methods to Consitute an Image                   %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               October 1998                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/client.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/identify.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+
+static SemaphoreInfo
+  *constitute_semaphore = (SemaphoreInfo *) NULL;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n s t i t u t e C o m p o n e n t G e n e s i s                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConstituteComponentGenesis() instantiates the constitute component.
+%
+%  The format of the ConstituteComponentGenesis method is:
+%
+%      MagickBooleanType ConstituteComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType ConstituteComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&constitute_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n s t i t u t e C o m p o n e n t T e r m i n u s                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConstituteComponentTerminus() destroys the constitute component.
+%
+%  The format of the ConstituteComponentTerminus method is:
+%
+%      ConstituteComponentTerminus(void)
+%
+*/
+MagickExport void ConstituteComponentTerminus(void)
+{
+  if (constitute_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&constitute_semaphore);
+  DestroySemaphoreInfo(&constitute_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n s t i t u t e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConstituteImage() returns an image from the pixel data you supply.
+%  The pixel data must be in scanline order top-to-bottom.  The data can be
+%  char, short int, int, float, or double.  Float and double require the
+%  pixels to be normalized [0..1], otherwise [0..QuantumRange].  For example, to
+%  create a 640x480 image from unsigned red-green-blue character data, use:
+%
+%      image = ConstituteImage(640,480,"RGB",CharPixel,pixels,&exception);
+%
+%  The format of the ConstituteImage method is:
+%
+%      Image *ConstituteImage(const size_t columns,const size_t rows,
+%        const char *map,const StorageType storage,const void *pixels,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o columns: width in pixels of the image.
+%
+%    o rows: height in pixels of the image.
+%
+%    o map:  This string reflects the expected ordering of the pixel array.
+%      It can be any combination or order of R = red, G = green, B = blue,
+%      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
+%      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
+%      P = pad.
+%
+%    o storage: Define the data type of the pixels.  Float and double types are
+%      expected to be normalized [0..1] otherwise [0..QuantumRange].  Choose
+%      from these types: CharPixel, DoublePixel, FloatPixel, IntegerPixel,
+%      LongPixel, QuantumPixel, or ShortPixel.
+%
+%    o pixels: This array of values contain the pixel components as defined by
+%      map and type.  You must preallocate this array where the expected
+%      length varies depending on the values of width, height, map, and type.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ConstituteImage(const size_t columns,
+  const size_t rows,const char *map,const StorageType storage,
+  const void *pixels,ExceptionInfo *exception)
+{
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Allocate image structure.
+  */
+  assert(map != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map);
+  assert(pixels != (void *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  image=AcquireImage((ImageInfo *) NULL);
+  if (image == (Image *) NULL)
+    return((Image *) NULL);
+  if ((columns == 0) || (rows == 0))
+    ThrowImageException(OptionError,"NonZeroWidthAndHeightRequired");
+  image->columns=columns;
+  image->rows=rows;
+  (void) SetImageBackgroundColor(image);
+  status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels);
+  if (status == MagickFalse)
+    {
+      InheritException(exception,&image->exception);
+      image=DestroyImage(image);
+    }
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P i n g I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PingImage() returns all the properties of an image or image sequence
+%  except for the pixels.  It is much faster and consumes far less memory
+%  than ReadImage().  On failure, a NULL image is returned and exception
+%  describes the reason for the failure.
+%
+%  The format of the PingImage method is:
+%
+%      Image *PingImage(const ImageInfo *image_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: Ping the image defined by the file or filename members of
+%      this structure.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static size_t PingStream(const Image *magick_unused(image),
+  const void *magick_unused(pixels),const size_t columns)
+{
+  return(columns);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport Image *PingImage(const ImageInfo *image_info,
+  ExceptionInfo *exception)
+{
+  Image
+    *image;
+
+  ImageInfo
+    *ping_info;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  ping_info=CloneImageInfo(image_info);
+  ping_info->ping=MagickTrue;
+  image=ReadStream(ping_info,&PingStream,exception);
+  if (image != (Image *) NULL)
+    {
+      ResetTimer(&image->timer);
+      if (ping_info->verbose != MagickFalse)
+        (void) IdentifyImage(image,stdout,MagickFalse);
+    }
+  ping_info=DestroyImageInfo(ping_info);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P i n g I m a g e s                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PingImages() pings one or more images and returns them as an image list.
+%
+%  The format of the PingImage method is:
+%
+%      Image *PingImages(const ImageInfo *image_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *PingImages(const ImageInfo *image_info,
+  ExceptionInfo *exception)
+{
+  char
+    filename[MaxTextExtent];
+
+  Image
+    *image,
+    *images;
+
+  ImageInfo
+    *read_info;
+
+  /*
+    Ping image list from a file.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename,
+    (int) image_info->scene,filename);
+  if (LocaleCompare(filename,image_info->filename) != 0)
+    {
+      ExceptionInfo
+        *sans;
+
+      ssize_t
+        extent,
+        scene;
+
+      /*
+        Images of the form image-%d.png[1-5].
+      */
+      read_info=CloneImageInfo(image_info);
+      sans=AcquireExceptionInfo();
+      (void) SetImageInfo(read_info,0,sans);
+      sans=DestroyExceptionInfo(sans);
+      (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
+      images=NewImageList();
+      extent=(ssize_t) (read_info->scene+read_info->number_scenes);
+      for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++)
+      {
+        (void) InterpretImageFilename(image_info,(Image *) NULL,filename,(int)
+          scene,read_info->filename);
+        image=PingImage(read_info,exception);
+        if (image == (Image *) NULL)
+          continue;
+        AppendImageToList(&images,image);
+      }
+      read_info=DestroyImageInfo(read_info);
+      return(images);
+    }
+  return(PingImage(image_info,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e a d I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadImage() reads an image or image sequence from a file or file handle.
+%  The method returns a NULL if there is a memory shortage or if the image
+%  cannot be read.  On failure, a NULL image is returned and exception
+%  describes the reason for the failure.
+%
+%  The format of the ReadImage method is:
+%
+%      Image *ReadImage(const ImageInfo *image_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: Read the image defined by the file or filename members of
+%      this structure.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ReadImage(const ImageInfo *image_info,
+  ExceptionInfo *exception)
+{
+  char
+    filename[MaxTextExtent],
+    magick[MaxTextExtent],
+    magick_filename[MaxTextExtent];
+
+  const char
+    *value;
+
+  const DelegateInfo
+    *delegate_info;
+
+  const MagickInfo
+    *magick_info;
+
+  ExceptionInfo
+    *sans_exception;
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *image,
+    *next;
+
+  ImageInfo
+    *read_info;
+
+  MagickStatusType
+    flags,
+    thread_support;
+
+  PolicyDomain
+    domain;
+
+  PolicyRights
+    rights;
+
+  /*
+    Determine image type from filename prefix or suffix (e.g. image.jpg).
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image_info->filename != (char *) NULL);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  read_info=CloneImageInfo(image_info);
+  (void) CopyMagickString(magick_filename,read_info->filename,MaxTextExtent);
+  (void) SetImageInfo(read_info,0,exception);
+  (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
+  (void) CopyMagickString(magick,read_info->magick,MaxTextExtent);
+  domain=CoderPolicyDomain;
+  rights=ReadPolicyRights;
+  if (IsRightsAuthorized(domain,rights,read_info->magick) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",read_info->filename);
+      return((Image *) NULL);
+    }
+  /*
+    Call appropriate image reader based on image type.
+  */
+  sans_exception=AcquireExceptionInfo();
+  magick_info=GetMagickInfo(read_info->magick,sans_exception);
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  if (magick_info != (const MagickInfo *) NULL)
+    {
+      if (GetMagickEndianSupport(magick_info) == MagickFalse)
+        read_info->endian=UndefinedEndian;
+      else
+        if ((image_info->endian == UndefinedEndian) &&
+            (GetMagickRawSupport(magick_info) != MagickFalse))
+          {
+            size_t
+              lsb_first;
+
+            lsb_first=1;
+            read_info->endian=(*(char *) &lsb_first) == 1 ? LSBEndian :
+              MSBEndian;
+         }
+    }
+  if ((magick_info != (const MagickInfo *) NULL) &&
+      (GetMagickSeekableStream(magick_info) != MagickFalse))
+    {
+      MagickBooleanType
+        status;
+
+      image=AcquireImage(read_info);
+      (void) CopyMagickString(image->filename,read_info->filename,
+        MaxTextExtent);
+      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
+      if (status == MagickFalse)
+        {
+          read_info=DestroyImageInfo(read_info);
+          image=DestroyImage(image);
+          return((Image *) NULL);
+        }
+      if (IsBlobSeekable(image) == MagickFalse)
+        {
+          /*
+            Coder requires a seekable stream.
+          */
+          *read_info->filename='\0';
+          status=ImageToFile(image,read_info->filename,exception);
+          if (status == MagickFalse)
+            {
+              (void) CloseBlob(image);
+              read_info=DestroyImageInfo(read_info);
+              image=DestroyImage(image);
+              return((Image *) NULL);
+            }
+          read_info->temporary=MagickTrue;
+        }
+      (void) CloseBlob(image);
+      image=DestroyImage(image);
+    }
+  image=NewImageList();
+  if (constitute_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&constitute_semaphore);
+  if ((magick_info != (const MagickInfo *) NULL) &&
+      (GetImageDecoder(magick_info) != (DecodeImageHandler *) NULL))
+    {
+      thread_support=GetMagickThreadSupport(magick_info);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        LockSemaphoreInfo(constitute_semaphore);
+      image=GetImageDecoder(magick_info)(read_info,exception);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        UnlockSemaphoreInfo(constitute_semaphore);
+    }
+  else
+    {
+      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
+      if (delegate_info == (const DelegateInfo *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+            read_info->filename);
+          if (read_info->temporary != MagickFalse)
+            (void) RelinquishUniqueFileResource(read_info->filename);
+          read_info=DestroyImageInfo(read_info);
+          return((Image *) NULL);
+        }
+      /*
+        Let our decoding delegate process the image.
+      */
+      image=AcquireImage(read_info);
+      if (image == (Image *) NULL)
+        {
+          read_info=DestroyImageInfo(read_info);
+          return((Image *) NULL);
+        }
+      (void) CopyMagickString(image->filename,read_info->filename,
+        MaxTextExtent);
+      *read_info->filename='\0';
+      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
+        LockSemaphoreInfo(constitute_semaphore);
+      (void) InvokeDelegate(read_info,image,read_info->magick,(char *) NULL,
+        exception);
+      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
+        UnlockSemaphoreInfo(constitute_semaphore);
+      image=DestroyImageList(image);
+      read_info->temporary=MagickTrue;
+      (void) SetImageInfo(read_info,0,exception);
+      magick_info=GetMagickInfo(read_info->magick,exception);
+      if ((magick_info == (const MagickInfo *) NULL) ||
+          (GetImageDecoder(magick_info) == (DecodeImageHandler *) NULL))
+        {
+          if (IsPathAccessible(read_info->filename) != MagickFalse)
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
+              read_info->filename);
+          else
+            ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
+              read_info->filename);
+          read_info=DestroyImageInfo(read_info);
+          return((Image *) NULL);
+        }
+      thread_support=GetMagickThreadSupport(magick_info);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        LockSemaphoreInfo(constitute_semaphore);
+      image=(Image *) (GetImageDecoder(magick_info))(read_info,exception);
+      if ((thread_support & DecoderThreadSupport) == 0)
+        UnlockSemaphoreInfo(constitute_semaphore);
+    }
+  if (read_info->temporary != MagickFalse)
+    {
+      (void) RelinquishUniqueFileResource(read_info->filename);
+      read_info->temporary=MagickFalse;
+      if (image != (Image *) NULL)
+        (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+    }
+  if (image == (Image *) NULL)
+    {
+      read_info=DestroyImageInfo(read_info);
+      return(image);
+    }
+  if (exception->severity >= ErrorException)
+    (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
+      "Coder (%s) generated an image despite an error (%d), "
+      "notify the developers",image->magick,exception->severity);
+  if (IsBlobTemporary(image) != MagickFalse)
+    (void) RelinquishUniqueFileResource(read_info->filename);
+  if ((GetNextImageInList(image) != (Image *) NULL) &&
+      (IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse))
+    {
+      Image
+        *clones;
+
+      clones=CloneImages(image,read_info->scenes,exception);
+      if (clones == (Image *) NULL)
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "SubimageSpecificationReturnsNoImages","`%s'",read_info->filename);
+      else
+        {
+          image=DestroyImageList(image);
+          image=GetFirstImageInList(clones);
+        }
+    }
+  if (GetBlobError(image) != MagickFalse)
+    {
+      ThrowFileException(exception,FileOpenError,
+        "AnErrorHasOccurredReadingFromFile",read_info->filename);
+      image=DestroyImageList(image);
+      read_info=DestroyImageInfo(read_info);
+      return((Image *) NULL);
+    }
+  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    char
+      magick_path[MaxTextExtent],
+      *property,
+      timestamp[MaxTextExtent];
+
+    const char
+      *option;
+
+    const StringInfo
+      *profile;
+
+    next->taint=MagickFalse;
+    GetPathComponent(magick_filename,MagickPath,magick_path);
+    if (*magick_path == '\0')
+      (void) CopyMagickString(next->magick,magick,MaxTextExtent);
+    (void) CopyMagickString(next->magick_filename,magick_filename,
+      MaxTextExtent);
+    if (IsBlobTemporary(image) != MagickFalse)
+      (void) CopyMagickString(next->filename,filename,MaxTextExtent);
+    if (next->magick_columns == 0)
+      next->magick_columns=next->columns;
+    if (next->magick_rows == 0)
+      next->magick_rows=next->rows;
+    value=GetImageProperty(next,"tiff:Orientation");
+    if (value == (char *) NULL)
+      value=GetImageProperty(next,"exif:Orientation");
+    if (value != (char *) NULL)
+      {
+        next->orientation=(OrientationType) StringToLong(value);
+        (void) DeleteImageProperty(next,"tiff:Orientation");
+        (void) DeleteImageProperty(next,"exif:Orientation");
+      }
+    value=GetImageProperty(next,"exif:XResolution");
+    if (value != (char *) NULL)
+      {
+        geometry_info.rho=next->x_resolution;
+        geometry_info.sigma=1.0;
+        flags=ParseGeometry(value,&geometry_info);
+        if (geometry_info.sigma != 0)
+          next->x_resolution=geometry_info.rho/geometry_info.sigma;
+        (void) DeleteImageProperty(next,"exif:XResolution");
+      }
+    value=GetImageProperty(next,"exif:YResolution");
+    if (value != (char *) NULL)
+      {
+        geometry_info.rho=next->y_resolution;
+        geometry_info.sigma=1.0;
+        flags=ParseGeometry(value,&geometry_info);
+        if (geometry_info.sigma != 0)
+          next->y_resolution=geometry_info.rho/geometry_info.sigma;
+        (void) DeleteImageProperty(next,"exif:YResolution");
+      }
+    value=GetImageProperty(next,"tiff:ResolutionUnit");
+    if (value == (char *) NULL)
+      value=GetImageProperty(next,"exif:ResolutionUnit");
+    if (value != (char *) NULL)
+      {
+        next->units=(ResolutionType) (StringToLong(value)-1);
+        (void) DeleteImageProperty(next,"exif:ResolutionUnit");
+        (void) DeleteImageProperty(next,"tiff:ResolutionUnit");
+      }
+    if (next->page.width == 0)
+      next->page.width=next->columns;
+    if (next->page.height == 0)
+      next->page.height=next->rows;
+    option=GetImageOption(read_info,"caption");
+    if (option != (const char *) NULL)
+      {
+        property=InterpretImageProperties(read_info,next,option);
+        (void) SetImageProperty(next,"caption",property);
+        property=DestroyString(property);
+      }
+    option=GetImageOption(read_info,"comment");
+    if (option != (const char *) NULL)
+      {
+        property=InterpretImageProperties(read_info,next,option);
+        (void) SetImageProperty(next,"comment",property);
+        property=DestroyString(property);
+      }
+    option=GetImageOption(read_info,"label");
+    if (option != (const char *) NULL)
+      {
+        property=InterpretImageProperties(read_info,next,option);
+        (void) SetImageProperty(next,"label",property);
+        property=DestroyString(property);
+      }
+    if (LocaleCompare(next->magick,"TEXT") == 0)
+      (void) ParseAbsoluteGeometry("0x0+0+0",&next->page);
+    if ((read_info->extract != (char *) NULL) &&
+        (read_info->stream == (StreamHandler) NULL))
+      {
+        RectangleInfo
+          geometry;
+
+        flags=ParseAbsoluteGeometry(read_info->extract,&geometry);
+        if ((next->columns != geometry.width) ||
+            (next->rows != geometry.height))
+          {
+            if (((flags & XValue) != 0) || ((flags & YValue) != 0))
+              {
+                Image
+                  *crop_image;
+
+                crop_image=CropImage(next,&geometry,exception);
+                if (crop_image != (Image *) NULL)
+                  ReplaceImageInList(&next,crop_image);
+              }
+            else
+              if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0))
+                {
+                  Image
+                    *size_image;
+
+                  flags=ParseRegionGeometry(next,read_info->extract,&geometry,
+                    exception);
+                  size_image=ResizeImage(next,geometry.width,geometry.height,
+                    next->filter,next->blur,exception);
+                  if (size_image != (Image *) NULL)
+                    ReplaceImageInList(&next,size_image);
+                }
+          }
+      }
+    profile=GetImageProfile(next,"icc");
+    if (profile == (const StringInfo *) NULL)
+      profile=GetImageProfile(next,"icm");
+    profile=GetImageProfile(next,"iptc");
+    if (profile == (const StringInfo *) NULL)
+      profile=GetImageProfile(next,"8bim");
+    (void) FormatMagickTime(GetBlobProperties(next)->st_mtime,MaxTextExtent,
+      timestamp);
+    (void) SetImageProperty(next,"date:modify",timestamp);
+    (void) FormatMagickTime(GetBlobProperties(next)->st_ctime,MaxTextExtent,
+      timestamp);
+    (void) SetImageProperty(next,"date:create",timestamp);
+    option=GetImageOption(image_info,"delay");
+    if (option != (const char *) NULL)
+      {
+        GeometryInfo
+          geometry_info;
+
+        flags=ParseGeometry(option,&geometry_info);
+        if ((flags & GreaterValue) != 0)
+          {
+            if (next->delay > (size_t) floor(geometry_info.rho+0.5))
+              next->delay=(size_t) floor(geometry_info.rho+0.5);
+          }
+        else
+          if ((flags & LessValue) != 0)
+            {
+              if (next->delay < (size_t) floor(geometry_info.rho+0.5))
+                next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
+            }
+          else
+            next->delay=(size_t) floor(geometry_info.rho+0.5);
+        if ((flags & SigmaValue) != 0)
+          next->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
+      }
+    option=GetImageOption(image_info,"dispose");
+    if (option != (const char *) NULL)
+      next->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
+        MagickFalse,option);
+    if (read_info->verbose != MagickFalse)
+      (void) IdentifyImage(next,stderr,MagickFalse);
+    image=next;
+  }
+  read_info=DestroyImageInfo(read_info);
+  return(GetFirstImageInList(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e a d I m a g e s                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadImages() reads one or more images and returns them as an image list.
+%
+%  The format of the ReadImage method is:
+%
+%      Image *ReadImages(const ImageInfo *image_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ReadImages(const ImageInfo *image_info,
+  ExceptionInfo *exception)
+{
+  char
+    filename[MaxTextExtent];
+
+  Image
+    *image,
+    *images;
+
+  ImageInfo
+    *read_info;
+
+  /*
+    Read image list from a file.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename,
+    (int) image_info->scene,filename);
+  if (LocaleCompare(filename,image_info->filename) != 0)
+    {
+      ExceptionInfo
+        *sans;
+
+      ssize_t
+        extent,
+        scene;
+
+      /*
+        Images of the form image-%d.png[1-5].
+      */
+      read_info=CloneImageInfo(image_info);
+      sans=AcquireExceptionInfo();
+      (void) SetImageInfo(read_info,0,sans);
+      sans=DestroyExceptionInfo(sans);
+      (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
+      images=NewImageList();
+      extent=(ssize_t) (read_info->scene+read_info->number_scenes);
+      for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++)
+      {
+        (void) InterpretImageFilename(image_info,(Image *) NULL,filename,(int)
+          scene,read_info->filename);
+        image=ReadImage(read_info,exception);
+        if (image == (Image *) NULL)
+          continue;
+        AppendImageToList(&images,image);
+      }
+      read_info=DestroyImageInfo(read_info);
+      return(images);
+    }
+  return(ReadImage(image_info,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e a d I n l i n e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadInlineImage() reads a Base64-encoded inline image or image sequence.
+%  The method returns a NULL if there is a memory shortage or if the image
+%  cannot be read.  On failure, a NULL image is returned and exception
+%  describes the reason for the failure.
+%
+%  The format of the ReadInlineImage method is:
+%
+%      Image *ReadInlineImage(const ImageInfo *image_info,const char *content,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o content: the image encoded in Base64.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ReadInlineImage(const ImageInfo *image_info,
+  const char *content,ExceptionInfo *exception)
+{
+  Image
+    *image;
+
+  ImageInfo
+    *read_info;
+
+  unsigned char
+    *blob;
+
+  size_t
+    length;
+
+  register const char
+    *p;
+
+  /*
+    Skip over header (e.g. data:image/gif;base64,).
+  */
+  image=NewImageList();
+  for (p=content; (*p != ',') && (*p != '\0'); p++) ;
+  if (*p == '\0')
+    ThrowReaderException(CorruptImageError,"CorruptImage");
+  p++;
+  length=0;
+  blob=Base64Decode(p,&length);
+  if (length == 0)
+    ThrowReaderException(CorruptImageError,"CorruptImage");
+  read_info=CloneImageInfo(image_info);
+  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
+    (void *) NULL);
+  *read_info->filename='\0';
+  *read_info->magick='\0';
+  image=BlobToImage(read_info,blob,length,exception);
+  blob=(unsigned char *) RelinquishMagickMemory(blob);
+  read_info=DestroyImageInfo(read_info);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   W r i t e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteImage() writes an image or an image sequence to a file or file handle.
+%  If writing to a file is on disk, the name is defined by the filename member
+%  of the image structure.  WriteImage() returns MagickFalse is there is a
+%  memory shortage or if the image cannot be written.  Check the exception
+%  member of image to determine the cause for any failure.
+%
+%  The format of the WriteImage method is:
+%
+%      MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info,
+  Image *image)
+{
+  char
+    filename[MaxTextExtent];
+
+  const char
+    *option;
+
+  const DelegateInfo
+    *delegate_info;
+
+  const MagickInfo
+    *magick_info;
+
+  ExceptionInfo
+    *sans_exception;
+
+  ImageInfo
+    *write_info;
+
+  MagickBooleanType
+    status,
+    temporary;
+
+  MagickStatusType
+    thread_support;
+
+  PolicyDomain
+    domain;
+
+  PolicyRights
+    rights;
+
+  /*
+    Determine image type from filename prefix or suffix (e.g. image.jpg).
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  sans_exception=AcquireExceptionInfo();
+  write_info=CloneImageInfo(image_info);
+  (void) CopyMagickString(write_info->filename,image->filename,MaxTextExtent);
+  if (*write_info->magick == '\0')
+    (void) CopyMagickString(write_info->magick,image->magick,MaxTextExtent);
+  (void) SetImageInfo(write_info,1,sans_exception);
+  if (LocaleCompare(write_info->magick,"clipmask") == 0)
+    {
+      if (image->clip_mask == (Image *) NULL)
+        {
+          (void) ThrowMagickException(&image->exception,GetMagickModule(),
+            OptionError,"NoClipPathDefined","`%s'",image->filename);
+          return(MagickFalse);
+        }
+      image=image->clip_mask;
+      (void) SetImageInfo(write_info,1,sans_exception);
+    }
+  (void) CopyMagickString(filename,image->filename,MaxTextExtent);
+  (void) CopyMagickString(image->filename,write_info->filename,MaxTextExtent);
+  domain=CoderPolicyDomain;
+  rights=WritePolicyRights;
+  if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse)
+    {
+      sans_exception=DestroyExceptionInfo(sans_exception);
+      errno=EPERM;
+      ThrowBinaryException(PolicyError,"NotAuthorized",filename);
+    }
+  magick_info=GetMagickInfo(write_info->magick,sans_exception);
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  if (magick_info != (const MagickInfo *) NULL)
+    {
+      if (GetMagickEndianSupport(magick_info) == MagickFalse)
+        image->endian=UndefinedEndian;
+      else
+        if ((image_info->endian == UndefinedEndian) &&
+            (GetMagickRawSupport(magick_info) != MagickFalse))
+          {
+            size_t
+              lsb_first;
+
+            lsb_first=1;
+            image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
+         }
+    }
+  (void) SyncImageProfiles(image);
+  option=GetImageOption(image_info,"delegate:bimodal");
+  if ((option != (const char *) NULL) &&
+      (IsMagickTrue(option) != MagickFalse) &&
+      (write_info->page == (char *) NULL) &&
+      (GetPreviousImageInList(image) == (Image *) NULL) &&
+      (GetNextImageInList(image) == (Image *) NULL) &&
+      (IsTaintImage(image) == MagickFalse))
+    {
+      delegate_info=GetDelegateInfo(image->magick,write_info->magick,
+        &image->exception);
+      if ((delegate_info != (const DelegateInfo *) NULL) &&
+          (GetDelegateMode(delegate_info) == 0) &&
+          (IsPathAccessible(image->magick_filename) != MagickFalse))
+        {
+          /*
+            Process image with bi-modal delegate.
+          */
+          (void) CopyMagickString(image->filename,image->magick_filename,
+            MaxTextExtent);
+          status=InvokeDelegate(write_info,image,image->magick,
+            write_info->magick,&image->exception);
+          write_info=DestroyImageInfo(write_info);
+          (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+          return(status);
+        }
+    }
+  status=MagickFalse;
+  temporary=MagickFalse;
+  if ((magick_info != (const MagickInfo *) NULL) &&
+      (GetMagickSeekableStream(magick_info) != MagickFalse))
+    {
+      char
+        filename[MaxTextExtent];
+
+      (void) CopyMagickString(filename,image->filename,MaxTextExtent);
+      status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
+      (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+      if (status != MagickFalse)
+        {
+          if (IsBlobSeekable(image) == MagickFalse)
+            {
+              /*
+                A seekable stream is required by the encoder.
+              */
+              write_info->adjoin=MagickTrue;
+              (void) CopyMagickString(write_info->filename,image->filename,
+                MaxTextExtent);
+              (void) AcquireUniqueFilename(image->filename);
+              temporary=MagickTrue;
+            }
+          (void) CloseBlob(image);
+        }
+    }
+  if (constitute_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&constitute_semaphore);
+  if ((magick_info != (const MagickInfo *) NULL) &&
+      (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL))
+    {
+      /*
+        Call appropriate image writer based on image type.
+      */
+      thread_support=GetMagickThreadSupport(magick_info);
+      if ((thread_support & EncoderThreadSupport) == 0)
+        LockSemaphoreInfo(constitute_semaphore);
+      status=GetImageEncoder(magick_info)(write_info,image);
+      if ((thread_support & EncoderThreadSupport) == 0)
+        UnlockSemaphoreInfo(constitute_semaphore);
+    }
+  else
+    {
+      delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,
+        &image->exception);
+      if (delegate_info != (DelegateInfo *) NULL)
+        {
+          /*
+            Process the image with delegate.
+          */
+          *write_info->filename='\0';
+          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
+            LockSemaphoreInfo(constitute_semaphore);
+          status=InvokeDelegate(write_info,image,(char *) NULL,
+            write_info->magick,&image->exception);
+          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
+            UnlockSemaphoreInfo(constitute_semaphore);
+          (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+        }
+      else
+        {
+          sans_exception=AcquireExceptionInfo();
+          magick_info=GetMagickInfo(write_info->magick,sans_exception);
+          sans_exception=DestroyExceptionInfo(sans_exception);
+          if ((write_info->affirm == MagickFalse) &&
+              (magick_info == (const MagickInfo *) NULL))
+            {
+              (void) CopyMagickString(write_info->magick,image->magick,
+                MaxTextExtent);
+              magick_info=GetMagickInfo(write_info->magick,&image->exception);
+            }
+          if ((magick_info == (const MagickInfo *) NULL) ||
+              (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL))
+            {
+              char
+                extension[MaxTextExtent];
+
+              GetPathComponent(image->filename,ExtensionPath,extension);
+              if (*extension != '\0')
+                magick_info=GetMagickInfo(extension,&image->exception);
+              else
+                magick_info=GetMagickInfo(image->magick,&image->exception);
+              (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+            }
+          if ((magick_info == (const MagickInfo *) NULL) ||
+              (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL))
+            (void) ThrowMagickException(&image->exception,GetMagickModule(),
+              MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
+              image->filename);
+          else
+            {
+              /*
+                Call appropriate image writer based on image type.
+              */
+              thread_support=GetMagickThreadSupport(magick_info);
+              if ((thread_support & EncoderThreadSupport) == 0)
+                LockSemaphoreInfo(constitute_semaphore);
+              status=GetImageEncoder(magick_info)(write_info,image);
+              if ((thread_support & EncoderThreadSupport) == 0)
+                UnlockSemaphoreInfo(constitute_semaphore);
+            }
+        }
+    }
+  if (GetBlobError(image) != MagickFalse)
+    ThrowFileException(&image->exception,FileOpenError,
+      "AnErrorHasOccurredWritingToFile",image->filename);
+  if (temporary == MagickTrue)
+    {
+      /*
+        Copy temporary image file to permanent.
+      */
+      status=OpenBlob(write_info,image,ReadBinaryBlobMode,&image->exception);
+      if (status != MagickFalse)
+        status=ImageToFile(image,write_info->filename,&image->exception);
+      (void) CloseBlob(image);
+      (void) RelinquishUniqueFileResource(image->filename);
+      (void) CopyMagickString(image->filename,write_info->filename,
+        MaxTextExtent);
+    }
+  if ((LocaleCompare(write_info->magick,"info") != 0) &&
+      (write_info->verbose != MagickFalse))
+    (void) IdentifyImage(image,stdout,MagickFalse);
+  write_info=DestroyImageInfo(write_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   W r i t e I m a g e s                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteImages() writes an image sequence into one or more files.  While
+%  WriteImage() can write an image sequence, it is limited to writing
+%  the sequence into a single file using a format which supports multiple
+%  frames.   WriteImages(), however, does not have this limitation, instead it
+%  generates multiple output files if necessary (or when requested).  When
+%  ImageInfo's adjoin flag is set to MagickFalse, the file name is expected
+%  to include a printf-style formatting string for the frame number (e.g.
+%  "image%02d.png").
+%
+%  The format of the WriteImages method is:
+%
+%      MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images,
+%        const char *filename,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o images: the image list.
+%
+%    o filename: the image filename.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
+  Image *images,const char *filename,ExceptionInfo *exception)
+{
+#define WriteImageTag  "Write/Image"
+
+  BlobInfo
+    *blob;
+
+  ExceptionInfo
+    *sans_exception;
+
+  ImageInfo
+    *write_info;
+
+  MagickBooleanType
+    proceed;
+
+  MagickOffsetType
+    i;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  MagickSizeType
+    number_images;
+
+  MagickStatusType
+    status;
+
+  register Image
+    *p;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  write_info=CloneImageInfo(image_info);
+  images=GetFirstImageInList(images);
+  blob=CloneBlobInfo(images->blob);  /* thread specific I/O handler */
+  DestroyBlob(images);
+  images->blob=blob;
+  if (filename != (const char *) NULL)
+    for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+      (void) CopyMagickString(p->filename,filename,MaxTextExtent);
+  (void) CopyMagickString(write_info->filename,images->filename,MaxTextExtent);
+  if (*write_info->magick == '\0')
+    (void) CopyMagickString(write_info->magick,images->magick,MaxTextExtent);
+  sans_exception=AcquireExceptionInfo();
+  (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images),
+    sans_exception);
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  p=images;
+  for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p))
+    if (p->scene >= GetNextImageInList(p)->scene)
+      {
+        register ssize_t
+          i;
+
+        /*
+          Generate consistent scene numbers.
+        */
+        i=(ssize_t) images->scene;
+        for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+          p->scene=(size_t) i++;
+        break;
+      }
+  /*
+    Write images.
+  */
+  status=MagickTrue;
+  progress_monitor=(MagickProgressMonitor) NULL;
+  i=0;
+  number_images=GetImageListLength(images);
+  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
+  {
+    if (number_images != 1)
+      progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL,
+        p->client_data);
+    status&=WriteImage(write_info,p);
+    GetImageException(p,exception);
+    if (number_images != 1)
+      (void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
+    if (write_info->adjoin != MagickFalse)
+      break;
+    if (number_images != 1)
+      {
+        proceed=SetImageProgress(p,WriteImageTag,i++,number_images);
+        if (proceed == MagickFalse)
+          break;
+      }
+  }
+  write_info=DestroyImageInfo(write_info);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
diff --git a/MagickCore/constitute.h b/MagickCore/constitute.h
new file mode 100644
index 0000000..63268dd
--- /dev/null
+++ b/MagickCore/constitute.h
@@ -0,0 +1,58 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image constitute methods.
+*/
+#ifndef _MAGICKCORE_CONSTITUTE_H
+#define _MAGICKCORE_CONSTITUTE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedPixel,
+  CharPixel,
+  DoublePixel,
+  FloatPixel,
+  IntegerPixel,
+  LongPixel,
+  QuantumPixel,
+  ShortPixel
+} StorageType;
+
+extern MagickExport Image
+  *ConstituteImage(const size_t,const size_t,const char *,const StorageType,
+    const void *,ExceptionInfo *),
+  *PingImage(const ImageInfo *,ExceptionInfo *),
+  *PingImages(const ImageInfo *,ExceptionInfo *),
+  *ReadImage(const ImageInfo *,ExceptionInfo *),
+  *ReadImages(const ImageInfo *,ExceptionInfo *),
+  *ReadInlineImage(const ImageInfo *,const char *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ConstituteComponentGenesis(void),
+  WriteImage(const ImageInfo *,Image *),
+  WriteImages(const ImageInfo *,Image *,const char *,ExceptionInfo *);
+
+extern MagickExport void
+  ConstituteComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/decorate.c b/MagickCore/decorate.c
new file mode 100644
index 0000000..2ca3369
--- /dev/null
+++ b/MagickCore/decorate.c
@@ -0,0 +1,888 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            DDDD   EEEEE   CCCC   OOO   RRRR    AAA   TTTTT  EEEEE           %
+%            D   D  E      C      O   O  R   R  A   A    T    E               %
+%            D   D  EEE    C      O   O  RRRR   AAAAA    T    EEE             %
+%            D   D  E      C      O   O  R R    A   A    T    E               %
+%            DDDD   EEEEE   CCCC   OOO   R  R   A   A    T    EEEEE           %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Decoration Methods                     %
+%                                                                             %
+%                                Software Design                              %
+%                                  John Cristy                                %
+%                                   July 1992                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/transform.h"
+
+/*
+  Define declarations.
+*/
+#define AccentuateModulate  ScaleCharToQuantum(80)
+#define HighlightModulate  ScaleCharToQuantum(125)
+#define ShadowModulate  ScaleCharToQuantum(135)
+#define DepthModulate  ScaleCharToQuantum(185)
+#define TroughModulate  ScaleCharToQuantum(110)
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   B o r d e r I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BorderImage() surrounds the image with a border of the color defined by
+%  the bordercolor member of the image structure.  The width and height
+%  of the border are defined by the corresponding members of the border_info
+%  structure.
+%
+%  The format of the BorderImage method is:
+%
+%      Image *BorderImage(const Image *image,const RectangleInfo *border_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o border_info:  Define the width and height of the border.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *BorderImage(const Image *image,
+  const RectangleInfo *border_info,ExceptionInfo *exception)
+{
+  Image
+    *border_image,
+    *clone_image;
+
+  FrameInfo
+    frame_info;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(border_info != (RectangleInfo *) NULL);
+  frame_info.width=image->columns+(border_info->width << 1);
+  frame_info.height=image->rows+(border_info->height << 1);
+  frame_info.x=(ssize_t) border_info->width;
+  frame_info.y=(ssize_t) border_info->height;
+  frame_info.inner_bevel=0;
+  frame_info.outer_bevel=0;
+  clone_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (clone_image == (Image *) NULL)
+    return((Image *) NULL);
+  clone_image->matte_color=image->border_color;
+  border_image=FrameImage(clone_image,&frame_info,exception);
+  clone_image=DestroyImage(clone_image);
+  if (border_image != (Image *) NULL)
+    border_image->matte_color=image->matte_color;
+  return(border_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F r a m e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FrameImage() adds a simulated three-dimensional border around the image.
+%  The color of the border is defined by the matte_color member of image.
+%  Members width and height of frame_info specify the border width of the
+%  vertical and horizontal sides of the frame.  Members inner and outer
+%  indicate the width of the inner and outer shadows of the frame.
+%
+%  The format of the FrameImage method is:
+%
+%      Image *FrameImage(const Image *image,const FrameInfo *frame_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o frame_info: Define the width and height of the frame and its bevels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info,
+  ExceptionInfo *exception)
+{
+#define FrameImageTag  "Frame/Image"
+
+  CacheView
+    *image_view,
+    *frame_view;
+
+  Image
+    *frame_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    accentuate,
+    border,
+    highlight,
+    interior,
+    matte,
+    shadow,
+    trough;
+
+  register ssize_t
+    x;
+
+  size_t
+    bevel_width,
+    height,
+    width;
+
+  ssize_t
+    y;
+
+  /*
+    Check frame geometry.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(frame_info != (FrameInfo *) NULL);
+  if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
+    ThrowImageException(OptionError,"FrameIsLessThanImageSize");
+  bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
+  width=frame_info->width-frame_info->x-bevel_width;
+  height=frame_info->height-frame_info->y-bevel_width;
+  if ((width < image->columns) || (height < image->rows))
+    ThrowImageException(OptionError,"FrameIsLessThanImageSize");
+  /*
+    Initialize framed image attributes.
+  */
+  frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
+    exception);
+  if (frame_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(frame_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&frame_image->exception);
+      frame_image=DestroyImage(frame_image);
+      return((Image *) NULL);
+    }
+  if (frame_image->matte_color.alpha != OpaqueAlpha)
+    frame_image->matte=MagickTrue;
+  frame_image->page=image->page;
+  if ((image->page.width != 0) && (image->page.height != 0))
+    {
+      frame_image->page.width+=frame_image->columns-image->columns;
+      frame_image->page.height+=frame_image->rows-image->rows;
+    }
+  /*
+    Initialize 3D effects color.
+  */
+  GetPixelInfo(frame_image,&interior);
+  SetPixelInfoPacket(frame_image,&image->border_color,&interior);
+  GetPixelInfo(frame_image,&matte);
+  matte.colorspace=RGBColorspace;
+  SetPixelInfoPacket(frame_image,&image->matte_color,&matte);
+  GetPixelInfo(frame_image,&border);
+  border.colorspace=RGBColorspace;
+  SetPixelInfoPacket(frame_image,&image->border_color,&border);
+  GetPixelInfo(frame_image,&accentuate);
+  accentuate.red=(MagickRealType) (QuantumScale*((QuantumRange-
+    AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
+  accentuate.green=(MagickRealType) (QuantumScale*((QuantumRange-
+    AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
+  accentuate.blue=(MagickRealType) (QuantumScale*((QuantumRange-
+    AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
+  accentuate.alpha=matte.alpha;
+  GetPixelInfo(frame_image,&highlight);
+  highlight.red=(MagickRealType) (QuantumScale*((QuantumRange-
+    HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
+  highlight.green=(MagickRealType) (QuantumScale*((QuantumRange-
+    HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
+  highlight.blue=(MagickRealType) (QuantumScale*((QuantumRange-
+    HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
+  highlight.alpha=matte.alpha;
+  GetPixelInfo(frame_image,&shadow);
+  shadow.red=QuantumScale*matte.red*ShadowModulate;
+  shadow.green=QuantumScale*matte.green*ShadowModulate;
+  shadow.blue=QuantumScale*matte.blue*ShadowModulate;
+  shadow.alpha=matte.alpha;
+  GetPixelInfo(frame_image,&trough);
+  trough.red=QuantumScale*matte.red*TroughModulate;
+  trough.green=QuantumScale*matte.green*TroughModulate;
+  trough.blue=QuantumScale*matte.blue*TroughModulate;
+  trough.alpha=matte.alpha;
+  if (image->colorspace == CMYKColorspace)
+    {
+      ConvertRGBToCMYK(&interior);
+      ConvertRGBToCMYK(&matte);
+      ConvertRGBToCMYK(&border);
+      ConvertRGBToCMYK(&accentuate);
+      ConvertRGBToCMYK(&highlight);
+      ConvertRGBToCMYK(&shadow);
+      ConvertRGBToCMYK(&trough);
+    }
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  frame_view=AcquireCacheView(frame_image);
+  height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
+    frame_info->inner_bevel);
+  if (height != 0)
+    {
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      /*
+        Draw top of ornamental border.
+      */
+      q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
+        height,exception);
+      if (q != (Quantum *) NULL)
+        {
+          /*
+            Draw top of ornamental border.
+          */
+          for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
+          {
+            for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
+            {
+              if (x < y)
+                SetPixelPixelInfo(frame_image,&highlight,q);
+              else
+                SetPixelPixelInfo(frame_image,&accentuate,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for ( ; x < (ssize_t) frame_image->columns; x++)
+            {
+              SetPixelPixelInfo(frame_image,&shadow,q);
+              q+=GetPixelChannels(frame_image);
+            }
+          }
+          for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
+          {
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&highlight,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            width=frame_image->columns-2*frame_info->outer_bevel;
+            for (x=0; x < (ssize_t) width; x++)
+            {
+              SetPixelPixelInfo(frame_image,&matte,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&shadow,q);
+              q+=GetPixelChannels(frame_image);
+            }
+          }
+          for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
+          {
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&highlight,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
+            {
+              SetPixelPixelInfo(frame_image,&matte,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            width=image->columns+((size_t) frame_info->inner_bevel << 1)-
+              y;
+            for (x=0; x < (ssize_t) width; x++)
+            {
+              if (x < y)
+                SetPixelPixelInfo(frame_image,&shadow,q);
+              else
+                SetPixelPixelInfo(frame_image,&trough,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
+            {
+              SetPixelPixelInfo(frame_image,&highlight,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            width=frame_info->width-frame_info->x-image->columns-bevel_width;
+            for (x=0; x < (ssize_t) width; x++)
+            {
+              SetPixelPixelInfo(frame_image,&matte,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&shadow,q);
+              q+=GetPixelChannels(frame_image);
+            }
+          }
+          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
+        }
+    }
+  /*
+    Draw sides of ornamental border.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    /*
+      Initialize scanline with matte color.
+    */
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
+      frame_image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+    {
+      SetPixelPixelInfo(frame_image,&highlight,q);
+      q+=GetPixelChannels(frame_image);
+    }
+    for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
+    {
+      SetPixelPixelInfo(frame_image,&matte,q);
+      q+=GetPixelChannels(frame_image);
+    }
+    for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
+    {
+      SetPixelPixelInfo(frame_image,&shadow,q);
+      q+=GetPixelChannels(frame_image);
+    }
+    /*
+      Set frame interior to interior color.
+    */
+    if ((image->compose != CopyCompositeOp) &&
+        ((image->compose != OverCompositeOp) || (image->matte != MagickFalse)))
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        SetPixelPixelInfo(frame_image,&interior,q);
+        q+=GetPixelChannels(frame_image);
+      }
+    else
+      {
+        register const Quantum
+          *p;
+
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(frame_image,GetPixelRed(image,p),q);
+          SetPixelGreen(frame_image,GetPixelGreen(image,p),q);
+          SetPixelBlue(frame_image,GetPixelBlue(image,p),q);
+          if (image->colorspace == CMYKColorspace)
+            SetPixelBlack(frame_image,GetPixelBlack(image,p),q);
+          SetPixelAlpha(frame_image,GetPixelAlpha(image,p),q);
+          p+=GetPixelChannels(image);
+          q+=GetPixelChannels(frame_image);
+        }
+      }
+    for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
+    {
+      SetPixelPixelInfo(frame_image,&highlight,q);
+      q+=GetPixelChannels(frame_image);
+    }
+    width=frame_info->width-frame_info->x-image->columns-bevel_width;
+    for (x=0; x < (ssize_t) width; x++)
+    {
+      SetPixelPixelInfo(frame_image,&matte,q);
+      q+=GetPixelChannels(frame_image);
+    }
+    for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+    {
+      SetPixelPixelInfo(frame_image,&shadow,q);
+      q+=GetPixelChannels(frame_image);
+    }
+    if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp critical (MagickCore_FrameImage)
+#endif
+        proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  height=(size_t) (frame_info->inner_bevel+frame_info->height-
+    frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
+  if (height != 0)
+    {
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      /*
+        Draw bottom of ornamental border.
+      */
+      q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
+        height),frame_image->columns,height,exception);
+      if (q != (Quantum *) NULL)
+        {
+          /*
+            Draw bottom of ornamental border.
+          */
+          for (y=frame_info->inner_bevel-1; y >= 0; y--)
+          {
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&highlight,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
+            {
+              SetPixelPixelInfo(frame_image,&matte,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < y; x++)
+            {
+              SetPixelPixelInfo(frame_image,&shadow,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
+            {
+              if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
+                SetPixelPixelInfo(frame_image,&highlight,q);
+              else
+                SetPixelPixelInfo(frame_image,&accentuate,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            width=frame_info->width-frame_info->x-image->columns-bevel_width;
+            for (x=0; x < (ssize_t) width; x++)
+            {
+              SetPixelPixelInfo(frame_image,&matte,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&shadow,q);
+              q+=GetPixelChannels(frame_image);
+            }
+          }
+          height=frame_info->height-frame_info->y-image->rows-bevel_width;
+          for (y=0; y < (ssize_t) height; y++)
+          {
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&highlight,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            width=frame_image->columns-2*frame_info->outer_bevel;
+            for (x=0; x < (ssize_t) width; x++)
+            {
+              SetPixelPixelInfo(frame_image,&matte,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
+            {
+              SetPixelPixelInfo(frame_image,&shadow,q);
+              q+=GetPixelChannels(frame_image);
+            }
+          }
+          for (y=frame_info->outer_bevel-1; y >= 0; y--)
+          {
+            for (x=0; x < y; x++)
+            {
+              SetPixelPixelInfo(frame_image,&highlight,q);
+              q+=GetPixelChannels(frame_image);
+            }
+            for ( ; x < (ssize_t) frame_image->columns; x++)
+            {
+              if (x >= (ssize_t) (frame_image->columns-y))
+                SetPixelPixelInfo(frame_image,&shadow,q);
+              else
+                SetPixelPixelInfo(frame_image,&trough,q);
+              q+=GetPixelChannels(frame_image);
+            }
+          }
+          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
+        }
+    }
+  frame_view=DestroyCacheView(frame_view);
+  image_view=DestroyCacheView(image_view);
+  if ((image->compose != CopyCompositeOp) &&
+      ((image->compose != OverCompositeOp) || (image->matte != MagickFalse)))
+    {
+      x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
+        frame_info->inner_bevel);
+      y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
+        frame_info->inner_bevel);
+      (void) CompositeImage(frame_image,image->compose,image,x,y);
+    }
+  return(frame_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R a i s e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RaiseImage() creates a simulated three-dimensional button-like effect
+%  by lightening and darkening the edges of the image.  Members width and
+%  height of raise_info define the width of the vertical and horizontal
+%  edge of the effect.
+%
+%  The format of the RaiseImage method is:
+%
+%      MagickBooleanType RaiseImage(const Image *image,
+%        const RectangleInfo *raise_info,const MagickBooleanType raise)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o raise_info: Define the width and height of the raise area.
+%
+%    o raise: A value other than zero creates a 3-D raise effect,
+%      otherwise it has a lowered effect.
+%
+*/
+MagickExport MagickBooleanType RaiseImage(Image *image,
+  const RectangleInfo *raise_info,const MagickBooleanType raise)
+{
+#define AccentuateFactor  ScaleCharToQuantum(135)
+#define HighlightFactor  ScaleCharToQuantum(190)
+#define ShadowFactor  ScaleCharToQuantum(190)
+#define RaiseImageTag  "Raise/Image"
+#define TroughFactor  ScaleCharToQuantum(135)
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  Quantum
+    foreground,
+    background;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(raise_info != (RectangleInfo *) NULL);
+  if ((image->columns <= (raise_info->width << 1)) ||
+      (image->rows <= (raise_info->height << 1)))
+    ThrowBinaryException(OptionError,"ImageSizeMustExceedBevelWidth",
+      image->filename);
+  foreground=(Quantum) QuantumRange;
+  background=(Quantum) 0;
+  if (raise == MagickFalse)
+    {
+      foreground=(Quantum) 0;
+      background=(Quantum) QuantumRange;
+    }
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  /*
+    Raise image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) raise_info->height; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < y; x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    for ( ; x < (ssize_t) (image->columns-y); x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*AccentuateFactor+(MagickRealType) foreground*
+        (QuantumRange-AccentuateFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*AccentuateFactor+(MagickRealType) foreground*
+        (QuantumRange-AccentuateFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*AccentuateFactor+(MagickRealType) foreground*
+        (QuantumRange-AccentuateFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    for ( ; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=(ssize_t) raise_info->height; y < (ssize_t) (image->rows-raise_info->height); y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) raise_info->width; x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    for ( ; x < (ssize_t) (image->columns-raise_info->width); x++)
+      q+=GetPixelChannels(image);
+    for ( ; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=(ssize_t) (image->rows-raise_info->height); y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) (image->rows-y); x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*HighlightFactor+(MagickRealType) foreground*
+        (QuantumRange-HighlightFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    for ( ; x < (ssize_t) (image->columns-(image->rows-y)); x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*TroughFactor+(MagickRealType) background*
+        (QuantumRange-TroughFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*TroughFactor+(MagickRealType) background*
+        (QuantumRange-TroughFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*TroughFactor+(MagickRealType) background*
+        (QuantumRange-TroughFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    for ( ; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelRed(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelRed(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      SetPixelGreen(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelGreen(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      SetPixelBlue(image,ClampToQuantum(QuantumScale*((MagickRealType)
+        GetPixelBlue(image,q)*ShadowFactor+(MagickRealType) background*
+        (QuantumRange-ShadowFactor))),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_RaiseImage)
+#endif
+        proceed=SetImageProgress(image,RaiseImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/MagickCore/decorate.h b/MagickCore/decorate.h
new file mode 100644
index 0000000..a9d5ea9
--- /dev/null
+++ b/MagickCore/decorate.h
@@ -0,0 +1,51 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image decorate methods.
+*/
+#ifndef _MAGICKCORE_DECORATE_H
+#define _MAGICKCORE_DECORATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/image.h>
+
+typedef struct _FrameInfo
+{
+  size_t
+    width,
+    height;
+
+  ssize_t
+    x,
+    y,
+    inner_bevel,
+    outer_bevel;
+} FrameInfo;
+
+extern MagickExport Image
+  *BorderImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *FrameImage(const Image *,const FrameInfo *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  RaiseImage(Image *,const RectangleInfo *,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/delegate-private.h b/MagickCore/delegate-private.h
new file mode 100644
index 0000000..2d304b7
--- /dev/null
+++ b/MagickCore/delegate-private.h
@@ -0,0 +1,66 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore delegates private methods.
+*/
+#ifndef _MAGICKCORE_DELEGATE_PRIVATE_H
+#define _MAGICKCORE_DELEGATE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_GS_DELEGATE)
+#include "ghostscript/iapi.h"
+#include "ghostscript/ierrors.h"
+#endif
+
+#ifndef gs_main_instance_DEFINED
+# define gs_main_instance_DEFINED
+typedef struct gs_main_instance_s
+  gs_main_instance;
+#endif
+
+#if !defined(MagickDLLCall)
+#  if defined(MAGICKCORE_WINDOWS_SUPPORT)
+#    define MagickDLLCall __stdcall
+#  else
+#    define MagickDLLCall
+#  endif
+#endif
+
+typedef struct _GhostInfo
+{
+  int
+    (MagickDLLCall *exit)(gs_main_instance *);
+
+  int
+    (MagickDLLCall *init_with_args)(gs_main_instance *,int,char **);
+
+  int
+    (MagickDLLCall *new_instance)(gs_main_instance **,void *);
+
+  int
+    (MagickDLLCall *run_string)(gs_main_instance *,const char *,int,int *);
+
+  void
+    (MagickDLLCall *delete_instance)(gs_main_instance *);
+} GhostInfo;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/delegate.c b/MagickCore/delegate.c
new file mode 100644
index 0000000..a0884f2
--- /dev/null
+++ b/MagickCore/delegate.c
@@ -0,0 +1,1495 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%           DDDD   EEEEE  L      EEEEE   GGGG   AAA   TTTTT  EEEEE            %
+%           D   D  E      L      E      G      A   A    T    E                %
+%           D   D  EEE    L      EEE    G  GG  AAAAA    T    EEE              %
+%           D   D  E      L      E      G   G  A   A    T    E                %
+%           DDDD   EEEEE  LLLLL  EEEEE   GGG   A   A    T    EEEEE            %
+%                                                                             %
+%                                                                             %
+%             MagickCore Methods to Read/Write/Invoke Delegates               %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               October 1998                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The Delegates methods associate a set of commands with a particular
+%  image format.  ImageMagick uses delegates for formats it does not handle
+%  directly.
+%
+%  Thanks to Bob Friesenhahn for the initial inspiration and design of the
+%  delegates methods.
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define DelegateFilename  "delegates.xml"
+
+/*
+  Declare delegate map.
+*/
+static const char
+  *DelegateMap = (const char *)
+    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+    "<delegatemap>"
+    "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
+    "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/\"/>"
+    "  <delegate decode=\"cgm\" thread-support=\"False\" command=\"&quot;ralcgm&quot; -d ps -oC &lt; &quot;%i&quot; &gt; &quot;%o&quot; 2&gt; &quot;%u&quot;\"/>"
+    "  <delegate decode=\"dng:decode\" command=\"&quot;/usr/bin/ufraw-batch&quot; --silent --wb=camera --black-point=auto --exposure=auto --create-id=also --out-type=ppm16 &quot;--output=%u.pnm&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
+    "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
+    "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
+    "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
+    "  <delegate decode=\"gplt\" command=\"&quot;echo&quot; &quot;set size 1.25,0.62     set terminal postscript portrait color solid; set output &quot;%o&quot;; load &quot;%i&quot;&quot; &gt; &quot;%u&quot;;&quot;gnuplot&quot; &quot;%u&quot;\"/>"
+    "  <delegate decode=\"hpg\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
+    "  <delegate decode=\"hpgl\" command=\"if [ -e hp2xx -o -e /usr/bin/hp2xx ]; then     hp2xx -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o   else     echo &quot;You need to install hp2xx to use HPGL files with ImageMagick.&quot;     exit 1   fi\"/>"
+    "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"
+    "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
+    "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
+    "  <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; --i &quot;%i&quot; -vcodec pam -an -f rawvideo -y &quot;%u0.pam&quot; 2;&gt; &quot;%Z&quot;\"/>"
+    "  <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2;&gt; &quot;%Z&quot;\"/>"
+    "  <delegate decode=\"pcl:color\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=ppmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
+    "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
+    "  <delegate decode=\"pcl:mono\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
+    "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
+    "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
+    "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
+    "  <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"pov\" command=\"&quot;povray&quot; &quot;+i&quot;%i&quot;&quot; -D0 +o&quot;%o&quot; +fn%q +w%w +h%h +a -q9 -kfi&quot;%s&quot; -kff&quot;%n&quot;     &quot;convert&quot; -concatenate &quot;%o*.png&quot; &quot;%o&quot;\"/>"
+    "  <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
+    "  <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
+    "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
+    "  <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pngalpha&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
+    "  <delegate decode=\"ps:bbox\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=bbox&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
+    "  <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
+    "  <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
+    "  <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
+    "  <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
+    "  <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
+    "  <delegate encode=\"show\" spawn=\"True\" command=\"&quot;/usr/local/bin/display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
+    "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
+    "  <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
+    "  <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
+    "  <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\"&quot;/usr/local/bin/display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
+    "  <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
+    "</delegatemap>";
+
+/*
+  Global declaractions.
+*/
+static LinkedListInfo
+  *delegate_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *delegate_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_delegate = MagickFalse;
+
+/*
+  Forward declaractions.
+*/
+static MagickBooleanType
+  InitializeDelegateList(ExceptionInfo *),
+  LoadDelegateLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e l e g a t e C o m p o n e n t T e r m i n u s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DelegateComponentGenesis() instantiates the delegate component.
+%
+%  The format of the DelegateComponentGenesis method is:
+%
+%      MagickBooleanType DelegateComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType DelegateComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&delegate_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e g a t e C o m p o n e n t T e r m i n u s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DelegateComponentTerminus() destroys the delegate component.
+%
+%  The format of the DelegateComponentTerminus method is:
+%
+%      DelegateComponentTerminus(void)
+%
+*/
+
+static void *DestroyDelegate(void *delegate_info)
+{
+  register DelegateInfo
+    *p;
+
+  p=(DelegateInfo *) delegate_info;
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  if (p->decode != (char *) NULL)
+    p->decode=DestroyString(p->decode);
+  if (p->encode != (char *) NULL)
+    p->encode=DestroyString(p->encode);
+  if (p->commands != (char *) NULL)
+    p->commands=DestroyString(p->commands);
+  p=(DelegateInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+
+MagickExport void DelegateComponentTerminus(void)
+{
+  if (delegate_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&delegate_semaphore);
+  LockSemaphoreInfo(delegate_semaphore);
+  if (delegate_list != (LinkedListInfo *) NULL)
+    delegate_list=DestroyLinkedList(delegate_list,DestroyDelegate);
+  instantiate_delegate=MagickFalse;
+  UnlockSemaphoreInfo(delegate_semaphore);
+  DestroySemaphoreInfo(&delegate_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t D e l e g a t e C o m m a n d                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateCommand() replaces any embedded formatting characters with the
+%  appropriate image attribute and returns the resulting command.
+%
+%  The format of the GetDelegateCommand method is:
+%
+%      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
+%        const char *decode,const char *encode,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o command: Method GetDelegateCommand returns the command associated
+%      with specified delegate tag.
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+%    o decode: Specifies the decode delegate we are searching for as a
+%      character string.
+%
+%    o encode: Specifies the encode delegate we are searching for as a
+%      character string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
+  const char *decode,const char *encode,ExceptionInfo *exception)
+{
+  char
+    *command,
+    **commands;
+
+  const DelegateInfo
+    *delegate_info;
+
+  register ssize_t
+    i;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  delegate_info=GetDelegateInfo(decode,encode,exception);
+  if (delegate_info == (const DelegateInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
+        "NoTagFound","`%s'",decode ? decode : encode);
+      return((char *) NULL);
+    }
+  commands=StringToList(delegate_info->commands);
+  if (commands == (char **) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        decode ? decode : encode);
+      return((char *) NULL);
+    }
+  command=InterpretImageProperties(image_info,image,commands[0]);
+  if (command == (char *) NULL)
+    (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
+      "MemoryAllocationFailed","`%s'",commands[0]);
+  /*
+    Relinquish resources.
+  */
+  for (i=0; commands[i] != (char *) NULL; i++)
+    commands[i]=DestroyString(commands[i]);
+  commands=(char **) RelinquishMagickMemory(commands);
+  return(command);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t D e l e g a t e C o m m a n d s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateCommands() returns the commands associated with a delegate.
+%
+%  The format of the GetDelegateCommands method is:
+%
+%      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
+%
+%  A description of each parameter follows:
+%
+%    o delegate_info:  The delegate info.
+%
+*/
+MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(delegate_info != (DelegateInfo *) NULL);
+  assert(delegate_info->signature == MagickSignature);
+  return(delegate_info->commands);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t D e l e g a t e I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateInfo() returns any delegates associated with the specified tag.
+%
+%  The format of the GetDelegateInfo method is:
+%
+%      const DelegateInfo *GetDelegateInfo(const char *decode,
+%        const char *encode,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o decode: Specifies the decode delegate we are searching for as a
+%      character string.
+%
+%    o encode: Specifies the encode delegate we are searching for as a
+%      character string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
+  const char *encode,ExceptionInfo *exception)
+{
+  register const DelegateInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((delegate_list == (LinkedListInfo *) NULL) ||
+      (instantiate_delegate == MagickFalse))
+    if (InitializeDelegateList(exception) == MagickFalse)
+      return((const DelegateInfo *) NULL);
+  if ((delegate_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(delegate_list) != MagickFalse))
+    return((const DelegateInfo *) NULL);
+  if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
+    return((const DelegateInfo *) GetValueFromLinkedList(delegate_list,0));
+  /*
+    Search for named delegate.
+  */
+  LockSemaphoreInfo(delegate_semaphore);
+  ResetLinkedListIterator(delegate_list);
+  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+  while (p != (const DelegateInfo *) NULL)
+  {
+    if (p->mode > 0)
+      {
+        if (LocaleCompare(p->decode,decode) == 0)
+          break;
+        p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+        continue;
+      }
+    if (p->mode < 0)
+      {
+        if (LocaleCompare(p->encode,encode) == 0)
+          break;
+        p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+        continue;
+      }
+    if (LocaleCompare(decode,p->decode) == 0)
+      if (LocaleCompare(encode,p->encode) == 0)
+        break;
+    if (LocaleCompare(decode,"*") == 0)
+      if (LocaleCompare(encode,p->encode) == 0)
+        break;
+    if (LocaleCompare(decode,p->decode) == 0)
+      if (LocaleCompare(encode,"*") == 0)
+        break;
+    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+  }
+  if (p != (const DelegateInfo *) NULL)
+    (void) InsertValueInLinkedList(delegate_list,0,
+      RemoveElementByValueFromLinkedList(delegate_list,p));
+  UnlockSemaphoreInfo(delegate_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t D e l e g a t e I n f o L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateInfoList() returns any delegates that match the specified pattern.
+%
+%  The delegate of the GetDelegateInfoList function is:
+%
+%      const DelegateInfo **GetDelegateInfoList(const char *pattern,
+%        size_t *number_delegates,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_delegates:  This integer returns the number of delegates in the
+%      list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int DelegateInfoCompare(const void *x,const void *y)
+{
+  const DelegateInfo
+    **p,
+    **q;
+
+  p=(const DelegateInfo **) x,
+  q=(const DelegateInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    {
+      if ((*p)->decode == (char *) NULL)
+        if (((*p)->encode != (char *) NULL) &&
+            ((*q)->encode != (char *) NULL))
+          return(strcmp((*p)->encode,(*q)->encode));
+      if (((*p)->decode != (char *) NULL) &&
+          ((*q)->decode != (char *) NULL))
+        return(strcmp((*p)->decode,(*q)->decode));
+    }
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
+  size_t *number_delegates,ExceptionInfo *exception)
+{
+  const DelegateInfo
+    **delegates;
+
+  register const DelegateInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate delegate list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_delegates != (size_t *) NULL);
+  *number_delegates=0;
+  p=GetDelegateInfo("*","*",exception);
+  if (p == (const DelegateInfo *) NULL)
+    return((const DelegateInfo **) NULL);
+  delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(delegate_list)+1UL,sizeof(*delegates));
+  if (delegates == (const DelegateInfo **) NULL)
+    return((const DelegateInfo **) NULL);
+  /*
+    Generate delegate list.
+  */
+  LockSemaphoreInfo(delegate_semaphore);
+  ResetLinkedListIterator(delegate_list);
+  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+  for (i=0; p != (const DelegateInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        ((GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse) ||
+         (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse)))
+      delegates[i++]=p;
+    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+  }
+  UnlockSemaphoreInfo(delegate_semaphore);
+  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
+  delegates[i]=(DelegateInfo *) NULL;
+  *number_delegates=(size_t) i;
+  return(delegates);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t D e l e g a t e L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateList() returns any image format delegates that match the
+%  specified  pattern.
+%
+%  The format of the GetDelegateList function is:
+%
+%      char **GetDelegateList(const char *pattern,
+%        size_t *number_delegates,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_delegates:  This integer returns the number of delegates
+%      in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int DelegateCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetDelegateList(const char *pattern,
+  size_t *number_delegates,ExceptionInfo *exception)
+{
+  char
+    **delegates;
+
+  register const DelegateInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate delegate list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_delegates != (size_t *) NULL);
+  *number_delegates=0;
+  p=GetDelegateInfo("*","*",exception);
+  if (p == (const DelegateInfo *) NULL)
+    return((char **) NULL);
+  delegates=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(delegate_list)+1UL,sizeof(*delegates));
+  if (delegates == (char **) NULL)
+    return((char **) NULL);
+  LockSemaphoreInfo(delegate_semaphore);
+  ResetLinkedListIterator(delegate_list);
+  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+  for (i=0; p != (const DelegateInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse))
+      delegates[i++]=ConstantString(p->decode);
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse))
+      delegates[i++]=ConstantString(p->encode);
+    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
+  }
+  UnlockSemaphoreInfo(delegate_semaphore);
+  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
+  delegates[i]=(char *) NULL;
+  *number_delegates=(size_t) i;
+  return(delegates);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t D e l e g a t e M o d e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateMode() returns the mode of the delegate.
+%
+%  The format of the GetDelegateMode method is:
+%
+%      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
+%
+%  A description of each parameter follows:
+%
+%    o delegate_info:  The delegate info.
+%
+*/
+MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(delegate_info != (DelegateInfo *) NULL);
+  assert(delegate_info->signature == MagickSignature);
+  return(delegate_info->mode);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t D e l e g a t e T h r e a d S u p p o r t                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
+%  threads.
+%
+%  The format of the GetDelegateThreadSupport method is:
+%
+%      MagickBooleanType GetDelegateThreadSupport(
+%        const DelegateInfo *delegate_info)
+%
+%  A description of each parameter follows:
+%
+%    o delegate_info:  The delegate info.
+%
+*/
+MagickExport MagickBooleanType GetDelegateThreadSupport(
+  const DelegateInfo *delegate_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(delegate_info != (DelegateInfo *) NULL);
+  assert(delegate_info->signature == MagickSignature);
+  return(delegate_info->thread_support);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e D e l e g a t e L i s t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeDelegateList() initializes the delegate list.
+%
+%  The format of the InitializeDelegateList method is:
+%
+%      MagickBooleanType InitializeDelegateList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeDelegateList(ExceptionInfo *exception)
+{
+  if ((delegate_list == (LinkedListInfo *) NULL) &&
+      (instantiate_delegate == MagickFalse))
+    {
+      if (delegate_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&delegate_semaphore);
+      LockSemaphoreInfo(delegate_semaphore);
+      if ((delegate_list == (LinkedListInfo *) NULL) &&
+          (instantiate_delegate == MagickFalse))
+        {
+          (void) LoadDelegateLists(DelegateFilename,exception);
+          instantiate_delegate=MagickTrue;
+        }
+      UnlockSemaphoreInfo(delegate_semaphore);
+    }
+  return(delegate_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n v o k e D e l e g a t e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InvokeDelegate replaces any embedded formatting characters with the
+%  appropriate image attribute and executes the resulting command.  MagickFalse
+%  is returned if the commands execute with success otherwise MagickTrue.
+%
+%  The format of the InvokeDelegate method is:
+%
+%      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
+%        const char *decode,const char *encode,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the imageInfo.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickBooleanType CopyDelegateFile(const char *source,
+  const char *destination)
+{
+  int
+    destination_file,
+    source_file;
+
+  MagickBooleanType
+    status;
+
+  register size_t
+    i;
+
+  size_t
+    length,
+    quantum;
+
+  ssize_t
+    count;
+
+  struct stat
+    attributes;
+
+  unsigned char
+    *buffer;
+
+  /*
+    Return if destination file already exists and is not empty.
+  */
+  assert(source != (const char *) NULL);
+  assert(destination != (char *) NULL);
+  status=GetPathAttributes(destination,&attributes);
+  if ((status != MagickFalse) && (attributes.st_size != 0))
+    return(MagickTrue);
+  /*
+    Copy source file to destination.
+  */
+  destination_file=open(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
+  if (destination_file == -1)
+    return(MagickFalse);
+  source_file=open(source,O_RDONLY | O_BINARY);
+  if (source_file == -1)
+    {
+      (void) close(destination_file);
+      return(MagickFalse);
+    }
+  quantum=(size_t) MagickMaxBufferExtent;
+  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
+    quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
+  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
+  if (buffer == (unsigned char *) NULL)
+    {
+      (void) close(source_file);
+      (void) close(destination_file);
+      return(MagickFalse);
+    }
+  length=0;
+  for (i=0; ; i+=count)
+  {
+    count=(ssize_t) read(source_file,buffer,quantum);
+    if (count <= 0)
+      break;
+    length=(size_t) count;
+    count=(ssize_t) write(destination_file,buffer,length);
+    if ((size_t) count != length)
+      break;
+  }
+  (void) close(destination_file);
+  (void) close(source_file);
+  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+  return(i != 0 ? MagickTrue : MagickFalse);
+}
+
+MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
+  Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
+{
+  char
+    *command,
+    **commands,
+    input_filename[MaxTextExtent],
+    output_filename[MaxTextExtent];
+
+  const DelegateInfo
+    *delegate_info;
+
+  MagickBooleanType
+    status,
+    temporary;
+
+  register ssize_t
+    i;
+
+  PolicyRights
+    rights;
+
+  /*
+    Get delegate.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  rights=ExecutePolicyRights;
+  if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",decode);
+      return(MagickFalse);
+    }
+  if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",encode);
+      return(MagickFalse);
+    }
+  temporary=(*image->filename == '\0') ? MagickTrue : MagickFalse;
+  if (temporary != MagickFalse)
+    if (AcquireUniqueFilename(image->filename) == MagickFalse)
+      {
+        ThrowFileException(exception,FileOpenError,
+          "UnableToCreateTemporaryFile",image->filename);
+        return(MagickFalse);
+      }
+  delegate_info=GetDelegateInfo(decode,encode,exception);
+  if (delegate_info == (DelegateInfo *) NULL)
+    {
+      if (temporary != MagickFalse)
+        (void) RelinquishUniqueFileResource(image->filename);
+      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
+        "NoTagFound","`%s'",decode ? decode : encode);
+      return(MagickFalse);
+    }
+  if (*image_info->filename == '\0')
+    {
+      if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
+        {
+          if (temporary != MagickFalse)
+            (void) RelinquishUniqueFileResource(image->filename);
+          ThrowFileException(exception,FileOpenError,
+            "UnableToCreateTemporaryFile",image_info->filename);
+          return(MagickFalse);
+        }
+      image_info->temporary=MagickTrue;
+    }
+  if ((delegate_info->mode != 0) &&
+      (((decode != (const char *) NULL) &&
+        (delegate_info->encode != (char *) NULL)) ||
+       ((encode != (const char *) NULL) &&
+        (delegate_info->decode != (char *) NULL))))
+    {
+      char
+        *magick;
+
+      ImageInfo
+        *clone_info;
+
+      register Image
+        *p;
+
+      /*
+        Delegate requires a particular image format.
+      */
+      if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
+        {
+          ThrowFileException(exception,FileOpenError,
+            "UnableToCreateTemporaryFile",image_info->unique);
+          return(MagickFalse);
+        }
+      if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
+        {
+          (void) RelinquishUniqueFileResource(image_info->zero);
+          ThrowFileException(exception,FileOpenError,
+            "UnableToCreateTemporaryFile",image_info->zero);
+          return(MagickFalse);
+        }
+      magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
+        delegate_info->encode : delegate_info->decode);
+      if (magick == (char *) NULL)
+        {
+          (void) RelinquishUniqueFileResource(image_info->unique);
+          (void) RelinquishUniqueFileResource(image_info->zero);
+          if (temporary != MagickFalse)
+            (void) RelinquishUniqueFileResource(image->filename);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
+          return(MagickFalse);
+        }
+      LocaleUpper(magick);
+      clone_info=CloneImageInfo(image_info);
+      (void) CopyMagickString((char *) clone_info->magick,magick,
+        MaxTextExtent);
+      if (LocaleCompare(magick,"NULL") != 0)
+        (void) CopyMagickString(image->magick,magick,MaxTextExtent);
+      magick=DestroyString(magick);
+      (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
+        delegate_info->decode);
+      (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
+        exception);
+      (void) CopyMagickString(clone_info->filename,image_info->filename,
+        MaxTextExtent);
+      (void) CopyMagickString(image_info->filename,image->filename,
+        MaxTextExtent);
+      for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
+      {
+        (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
+          delegate_info->decode,clone_info->filename);
+        status=WriteImage(clone_info,p);
+        if (status == MagickFalse)
+          {
+            (void) RelinquishUniqueFileResource(image_info->unique);
+            (void) RelinquishUniqueFileResource(image_info->zero);
+            if (temporary != MagickFalse)
+              (void) RelinquishUniqueFileResource(image->filename);
+            clone_info=DestroyImageInfo(clone_info);
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
+            return(MagickFalse);
+          }
+        if (clone_info->adjoin != MagickFalse)
+          break;
+      }
+      (void) RelinquishUniqueFileResource(image_info->unique);
+      (void) RelinquishUniqueFileResource(image_info->zero);
+      clone_info=DestroyImageInfo(clone_info);
+    }
+  /*
+    Invoke delegate.
+  */
+  commands=StringToList(delegate_info->commands);
+  if (commands == (char **) NULL)
+    {
+      if (temporary != MagickFalse)
+        (void) RelinquishUniqueFileResource(image->filename);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        decode ? decode : encode);
+      return(MagickFalse);
+    }
+  command=(char *) NULL;
+  status=MagickFalse;
+  (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
+  (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
+  for (i=0; commands[i] != (char *) NULL; i++)
+  {
+    status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
+    if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
+      {
+        ThrowFileException(exception,FileOpenError,
+          "UnableToCreateTemporaryFile",image_info->unique);
+        break;
+      }
+    if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
+      {
+        (void) RelinquishUniqueFileResource(image_info->unique);
+        ThrowFileException(exception,FileOpenError,
+          "UnableToCreateTemporaryFile",image_info->zero);
+        break;
+      }
+    if (LocaleCompare(decode,"SCAN") != 0)
+      {
+        status=AcquireUniqueSymbolicLink(input_filename,image->filename);
+        if (status == MagickFalse)
+          {
+            ThrowFileException(exception,FileOpenError,
+              "UnableToCreateTemporaryFile",input_filename);
+            break;
+          }
+      }
+    status=MagickFalse;
+    command=InterpretImageProperties(image_info,image,commands[i]);
+    if (command != (char *) NULL)
+      {
+        /*
+          Execute delegate.
+        */
+        status=SystemCommand(delegate_info->spawn,image_info->verbose,command,
+          exception) != 0 ? MagickTrue : MagickFalse;
+        if (delegate_info->spawn != MagickFalse)
+          (void) sleep(2);
+        command=DestroyString(command);
+      }
+    if (LocaleCompare(decode,"SCAN") != 0)
+      {
+        if (CopyDelegateFile(image->filename,input_filename) == MagickFalse)
+          (void) RelinquishUniqueFileResource(input_filename);
+      }
+    if (CopyDelegateFile(image_info->filename,output_filename) == MagickFalse)
+      (void) RelinquishUniqueFileResource(output_filename);
+    if (image_info->temporary != MagickFalse)
+      (void) RelinquishUniqueFileResource(image_info->filename);
+    (void) RelinquishUniqueFileResource(image_info->unique);
+    (void) RelinquishUniqueFileResource(image_info->zero);
+    (void) RelinquishUniqueFileResource(image_info->filename);
+    (void) RelinquishUniqueFileResource(image->filename);
+    if (status != MagickFalse)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
+          "DelegateFailed","`%s'",commands[i]);
+        break;
+      }
+    commands[i]=DestroyString(commands[i]);
+  }
+  (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
+  (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
+  /*
+    Relinquish resources.
+  */
+  for ( ; commands[i] != (char *) NULL; i++)
+    commands[i]=DestroyString(commands[i]);
+  commands=(char **) RelinquishMagickMemory(commands);
+  if (temporary != MagickFalse)
+    (void) RelinquishUniqueFileResource(image->filename);
+  return(status == MagickFalse ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t D e l e g a t e I n f o                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListDelegateInfo() lists the image formats to a file.
+%
+%  The format of the ListDelegateInfo method is:
+%
+%      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const DelegateInfo
+    **delegate_info;
+
+  char
+    **commands,
+    delegate[MaxTextExtent];
+
+  const char
+    *path;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_delegates;
+
+  ssize_t
+    j;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
+  if (delegate_info == (const DelegateInfo **) NULL)
+    return(MagickFalse);
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_delegates; i++)
+  {
+    if (delegate_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,delegate_info[i]->path) != 0))
+      {
+        if (delegate_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
+        (void) FormatLocaleFile(file,"Delegate                Command\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=delegate_info[i]->path;
+    *delegate='\0';
+    if (delegate_info[i]->encode != (char *) NULL)
+      (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
+    (void) ConcatenateMagickString(delegate,"        ",MaxTextExtent);
+    delegate[8]='\0';
+    commands=StringToList(delegate_info[i]->commands);
+    if (commands == (char **) NULL)
+      continue;
+    (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
+      delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
+      delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
+    StripString(commands[0]);
+    (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
+    for (j=1; commands[j] != (char *) NULL; j++)
+    {
+      StripString(commands[j]);
+      (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
+    }
+    for (j=0; commands[j] != (char *) NULL; j++)
+      commands[j]=DestroyString(commands[j]);
+    commands=(char **) RelinquishMagickMemory(commands);
+  }
+  (void) fflush(file);
+  delegate_info=(const DelegateInfo **)
+    RelinquishMagickMemory((void *) delegate_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d D e l e g a t e L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadDelegateList() loads the delegate configuration file which provides a
+%  mapping between delegate attributes and a delegate name.
+%
+%  The format of the LoadDelegateList method is:
+%
+%      MagickBooleanType LoadDelegateList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The delegate list in XML format.
+%
+%    o filename:  The delegate list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadDelegateList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  DelegateInfo
+    *delegate_info;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Load the delegate map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading delegate configuration file \"%s\" ...",filename);
+  if (xml == (const char *) NULL)
+    return(MagickFalse);
+  if (delegate_list == (LinkedListInfo *) NULL)
+    {
+      delegate_list=NewLinkedList(0);
+      if (delegate_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  delegate_info=(DelegateInfo *) NULL;
+  token=AcquireString(xml);
+  for (q=(const char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadDelegateList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<delegate") == 0)
+      {
+        /*
+          Delegate element.
+        */
+        delegate_info=(DelegateInfo *) AcquireMagickMemory(
+          sizeof(*delegate_info));
+        if (delegate_info == (DelegateInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
+        delegate_info->path=ConstantString(filename);
+        delegate_info->signature=MagickSignature;
+        continue;
+      }
+    if (delegate_info == (DelegateInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AppendValueToLinkedList(delegate_list,delegate_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            delegate_info->commands);
+        delegate_info=(DelegateInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'C':
+      case 'c':
+      {
+        if (LocaleCompare((char *) keyword,"command") == 0)
+          {
+            char
+              *commands;
+
+            commands=AcquireString(token);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+            if (strchr(commands,'@') != (char *) NULL)
+              {
+                char
+                  path[MaxTextExtent];
+
+                NTGhostscriptEXE(path,MaxTextExtent);
+                (void) SubstituteString((char **) &commands,"@PSDelegate@",
+                  path);
+                (void) SubstituteString((char **) &commands,"\\","/");
+              }
+#endif
+            (void) SubstituteString((char **) &commands,"&amp;","&");
+            (void) SubstituteString((char **) &commands,"&quot;","\"");
+            (void) SubstituteString((char **) &commands,"&gt;",">");
+            (void) SubstituteString((char **) &commands,"&lt;","<");
+            delegate_info->commands=commands;
+            break;
+          }
+        break;
+      }
+      case 'D':
+      case 'd':
+      {
+        if (LocaleCompare((char *) keyword,"decode") == 0)
+          {
+            delegate_info->decode=ConstantString(token);
+            delegate_info->mode=1;
+            break;
+          }
+        break;
+      }
+      case 'E':
+      case 'e':
+      {
+        if (LocaleCompare((char *) keyword,"encode") == 0)
+          {
+            delegate_info->encode=ConstantString(token);
+            delegate_info->mode=(-1);
+            break;
+          }
+        break;
+      }
+      case 'M':
+      case 'm':
+      {
+        if (LocaleCompare((char *) keyword,"mode") == 0)
+          {
+            delegate_info->mode=1;
+            if (LocaleCompare(token,"bi") == 0)
+              delegate_info->mode=0;
+            else
+              if (LocaleCompare(token,"encode") == 0)
+                delegate_info->mode=(-1);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"spawn") == 0)
+          {
+            delegate_info->spawn=IsMagickTrue(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            delegate_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      case 'T':
+      case 't':
+      {
+        if (LocaleCompare((char *) keyword,"thread-support") == 0)
+          {
+            delegate_info->thread_support=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d D e l e g a t e L i s t s                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadDelegateList() loads one or more delegate configuration file which
+%  provides a mapping between delegate attributes and a delegate name.
+%
+%  The format of the LoadDelegateLists method is:
+%
+%      MagickBooleanType LoadDelegateLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadDelegateLists(const char *filename,
+  ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadDelegateList(DelegateMap,"built-in",0,exception));
+#else
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  status=MagickFalse;
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadDelegateList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((delegate_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(delegate_list) != MagickFalse))
+    status|=LoadDelegateList(DelegateMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
diff --git a/MagickCore/delegate.h b/MagickCore/delegate.h
new file mode 100644
index 0000000..daf7f8a
--- /dev/null
+++ b/MagickCore/delegate.h
@@ -0,0 +1,73 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore delegates methods.
+*/
+#ifndef _MAGICKCORE_DELEGATE_H
+#define _MAGICKCORE_DELEGATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _DelegateInfo
+{
+  char
+    *path,
+    *decode,
+    *encode,
+    *commands;
+                                                                                
+  ssize_t
+    mode;
+                                                                                
+  MagickBooleanType
+    thread_support,
+    spawn,
+    stealth;
+                                                                                
+  size_t
+    signature;
+} DelegateInfo;
+
+extern MagickExport char
+  *GetDelegateCommand(const ImageInfo *,Image *,const char *,const char *,
+    ExceptionInfo *),
+  **GetDelegateList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetDelegateCommands(const DelegateInfo *);
+
+extern MagickExport const DelegateInfo
+  *GetDelegateInfo(const char *,const char *,ExceptionInfo *exception),
+  **GetDelegateInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport ssize_t
+  GetDelegateMode(const DelegateInfo *);
+
+extern MagickExport MagickBooleanType
+  DelegateComponentGenesis(void),
+  GetDelegateThreadSupport(const DelegateInfo *),
+  InvokeDelegate(ImageInfo *,Image *,const char *,const char *,ExceptionInfo *),
+  ListDelegateInfo(FILE *,ExceptionInfo *);
+
+extern MagickExport void
+  DelegateComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/deprecate.c b/MagickCore/deprecate.c
new file mode 100644
index 0000000..1cc7b3c
--- /dev/null
+++ b/MagickCore/deprecate.c
@@ -0,0 +1,93 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        DDDD   EEEEE  PPPP   RRRR   EEEEE   CCCC   AAA   TTTTT  EEEEE        %
+%        D   D  E      P   P  R   R  E      C      A   A    T    E            %
+%        D   D  EEE    PPPPP  RRRR   EEE    C      AAAAA    T    EEE          %
+%        D   D  E      P      R R    E      C      A   A    T    E            %
+%        DDDD   EEEEE  P      R  R   EEEEE   CCCC  A   A    T    EEEEE        %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Deprecated Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                October 2002                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colormap-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/draw-private.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/identify.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/morphology.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+
+#if !defined(MAGICKCORE_EXCLUDE_DEPRECATED)
+
+#endif
diff --git a/MagickCore/deprecate.h b/MagickCore/deprecate.h
new file mode 100644
index 0000000..15a1006
--- /dev/null
+++ b/MagickCore/deprecate.h
@@ -0,0 +1,33 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore deprecated methods.
+*/
+#ifndef _MAGICKCORE_DEPRECATE_H
+#define _MAGICKCORE_DEPRECATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if !defined(MAGICKCORE_EXCLUDE_DEPRECATED)
+
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/display-private.h b/MagickCore/display-private.h
new file mode 100644
index 0000000..86b3348
--- /dev/null
+++ b/MagickCore/display-private.h
@@ -0,0 +1,39 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore methods to interactively display and edit an image.
+*/
+#ifndef _MAGICKCORE_DISPLAY_PRIVATE_H
+#define _MAGICKCORE_DISPLAY_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+#include "MagickCore/xwindow-private.h"
+
+extern MagickExport Image
+  *XDisplayImage(Display *,XResourceInfo *,char **,int,Image **,size_t *);
+
+extern MagickExport MagickBooleanType XDisplayBackgroundImage(Display *,
+  XResourceInfo *,Image *);
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/display.c b/MagickCore/display.c
new file mode 100644
index 0000000..4291e8e
--- /dev/null
+++ b/MagickCore/display.c
@@ -0,0 +1,16095 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               DDDD   IIIII  SSSSS  PPPP   L       AAA   Y   Y               %
+%               D   D    I    SS     P   P  L      A   A   Y Y                %
+%               D   D    I     SSS   PPPP   L      AAAAA    Y                 %
+%               D   D    I       SS  P      L      A   A    Y                 %
+%               DDDD   IIIII  SSSSS  P      LLLLL  A   A    Y                 %
+%                                                                             %
+%                                                                             %
+%        MagickCore Methods to Interactively Display and Edit an Image        %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                                July 1992                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/display.h"
+#include "MagickCore/display-private.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/option.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/PreRvIcccm.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#include "MagickCore/widget.h"
+#include "MagickCore/xwindow-private.h"
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+/*
+  Define declarations.
+*/
+#define MaxColors  MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
+
+/*
+  Constant declarations.
+*/
+static const unsigned char
+  HighlightBitmap[8] =
+  {
+    0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
+  },
+  OpaqueBitmap[8] =
+  {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+  },
+  ShadowBitmap[8] =
+  {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+static const char
+  *PageSizes[] =
+  {
+    "Letter",
+    "Tabloid",
+    "Ledger",
+    "Legal",
+    "Statement",
+    "Executive",
+    "A3",
+    "A4",
+    "A5",
+    "B4",
+    "B5",
+    "Folio",
+    "Quarto",
+    "10x14",
+    (char *) NULL
+  };
+
+/*
+  Help widget declarations.
+*/
+static const char
+  *ImageAnnotateHelp[] =
+  {
+    "In annotate mode, the Command widget has these options:",
+    "",
+    "    Font Name",
+    "      fixed",
+    "      variable",
+    "      5x8",
+    "      6x10",
+    "      7x13bold",
+    "      8x13bold",
+    "      9x15bold",
+    "      10x20",
+    "      12x24",
+    "      Browser...",
+    "    Font Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      transparent",
+    "      Browser...",
+    "    Font Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      transparent",
+    "      Browser...",
+    "    Rotate Text",
+    "      -90",
+    "      -45",
+    "      -30",
+    "      0",
+    "      30",
+    "      45",
+    "      90",
+    "      180",
+    "      Dialog...",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a font name from the Font Name sub-menu.  Additional",
+    "font names can be specified with the font browser.  You can",
+    "change the menu names by setting the X resources font1",
+    "through font9.",
+    "",
+    "Choose a font color from the Font Color sub-menu.",
+    "Additional font colors can be specified with the color",
+    "browser.  You can change the menu colors by setting the X",
+    "resources pen1 through pen9.",
+    "",
+    "If you select the color browser and press Grab, you can",
+    "choose the font color by moving the pointer to the desired",
+    "color on the screen and press any button.",
+    "",
+    "If you choose to rotate the text, choose Rotate Text from the",
+    "menu and select an angle.  Typically you will only want to",
+    "rotate one line of text at a time.  Depending on the angle you",
+    "choose, subsequent lines may end up overwriting each other.",
+    "",
+    "Choosing a font and its color is optional.  The default font",
+    "is fixed and the default color is black.  However, you must",
+    "choose a location to begin entering text and press button 1.",
+    "An underscore character will appear at the location of the",
+    "pointer.  The cursor changes to a pencil to indicate you are",
+    "in text mode.  To exit immediately, press Dismiss.",
+    "",
+    "In text mode, any key presses will display the character at",
+    "the location of the underscore and advance the underscore",
+    "cursor.  Enter your text and once completed press Apply to",
+    "finish your image annotation.  To correct errors press BACK",
+    "SPACE.  To delete an entire line of text, press DELETE.  Any",
+    "text that exceeds the boundaries of the image window is",
+    "automagically continued onto the next line.",
+    "",
+    "The actual color you request for the font is saved in the",
+    "image.  However, the color that appears in your image window",
+    "may be different.  For example, on a monochrome screen the",
+    "text will appear black or white even if you choose the color",
+    "red as the font color.  However, the image saved to a file",
+    "with -write is written with red lettering.  To assure the",
+    "correct color text in the final image, any PseudoClass image",
+    "is promoted to DirectClass (see miff(5)).  To force a",
+    "PseudoClass image to remain PseudoClass, use -colors.",
+    (char *) NULL,
+  },
+  *ImageChopHelp[] =
+  {
+    "In chop mode, the Command widget has these options:",
+    "",
+    "    Direction",
+    "      horizontal",
+    "      vertical",
+    "    Help",
+    "    Dismiss",
+    "",
+    "If the you choose the horizontal direction (this the",
+    "default), the area of the image between the two horizontal",
+    "endpoints of the chop line is removed.  Otherwise, the area",
+    "of the image between the two vertical endpoints of the chop",
+    "line is removed.",
+    "",
+    "Select a location within the image window to begin your chop,",
+    "press and hold any button.  Next, move the pointer to",
+    "another location in the image.  As you move a line will",
+    "connect the initial location and the pointer.  When you",
+    "release the button, the area within the image to chop is",
+    "determined by which direction you choose from the Command",
+    "widget.",
+    "",
+    "To cancel the image chopping, move the pointer back to the",
+    "starting point of the line and release the button.",
+    (char *) NULL,
+  },
+  *ImageColorEditHelp[] =
+  {
+    "In color edit mode, the Command widget has these options:",
+    "",
+    "    Method",
+    "      point",
+    "      replace",
+    "      floodfill",
+    "      filltoborder",
+    "      reset",
+    "    Pixel Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      Browser...",
+    "    Border Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      Browser...",
+    "    Fuzz",
+    "      0%",
+    "      2%",
+    "      5%",
+    "      10%",
+    "      15%",
+    "      Dialog...",
+    "    Undo",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a color editing method from the Method sub-menu",
+    "of the Command widget.  The point method recolors any pixel",
+    "selected with the pointer until the button is released.  The",
+    "replace method recolors any pixel that matches the color of",
+    "the pixel you select with a button press.  Floodfill recolors",
+    "any pixel that matches the color of the pixel you select with",
+    "a button press and is a neighbor.  Whereas filltoborder recolors",
+    "any neighbor pixel that is not the border color.  Finally reset",
+    "changes the entire image to the designated color.",
+    "",
+    "Next, choose a pixel color from the Pixel Color sub-menu.",
+    "Additional pixel colors can be specified with the color",
+    "browser.  You can change the menu colors by setting the X",
+    "resources pen1 through pen9.",
+    "",
+    "Now press button 1 to select a pixel within the image window",
+    "to change its color.  Additional pixels may be recolored as",
+    "prescribed by the method you choose.",
+    "",
+    "If the Magnify widget is mapped, it can be helpful in positioning",
+    "your pointer within the image (refer to button 2).",
+    "",
+    "The actual color you request for the pixels is saved in the",
+    "image.  However, the color that appears in your image window",
+    "may be different.  For example, on a monochrome screen the",
+    "pixel will appear black or white even if you choose the",
+    "color red as the pixel color.  However, the image saved to a",
+    "file with -write is written with red pixels.  To assure the",
+    "correct color text in the final image, any PseudoClass image",
+    "is promoted to DirectClass (see miff(5)).  To force a",
+    "PseudoClass image to remain PseudoClass, use -colors.",
+    (char *) NULL,
+  },
+  *ImageCompositeHelp[] =
+  {
+    "First a widget window is displayed requesting you to enter an",
+    "image name. Press Composite, Grab or type a file name.",
+    "Press Cancel if you choose not to create a composite image.",
+    "When you choose Grab, move the pointer to the desired window",
+    "and press any button.",
+    "",
+    "If the Composite image does not have any matte information,",
+    "you are informed and the file browser is displayed again.",
+    "Enter the name of a mask image.  The image is typically",
+    "grayscale and the same size as the composite image.  If the",
+    "image is not grayscale, it is converted to grayscale and the",
+    "resulting intensities are used as matte information.",
+    "",
+    "A small window appears showing the location of the cursor in",
+    "the image window. You are now in composite mode.  To exit",
+    "immediately, press Dismiss.  In composite mode, the Command",
+    "widget has these options:",
+    "",
+    "    Operators",
+    "      Over",
+    "      In",
+    "      Out",
+    "      Atop",
+    "      Xor",
+    "      Plus",
+    "      Minus",
+    "      Add",
+    "      Subtract",
+    "      Difference",
+    "      Multiply",
+    "      Bumpmap",
+    "      Copy",
+    "      CopyRed",
+    "      CopyGreen",
+    "      CopyBlue",
+    "      CopyOpacity",
+    "      Clear",
+    "    Dissolve",
+    "    Displace",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a composite operation from the Operators sub-menu of",
+    "the Command widget.  How each operator behaves is described",
+    "below.  Image window is the image currently displayed on",
+    "your X server and image is the image obtained with the File",
+    "Browser widget.",
+    "",
+    "Over     The result is the union of the two image shapes,",
+    "         with image obscuring image window in the region of",
+    "         overlap.",
+    "",
+    "In       The result is simply image cut by the shape of",
+    "         image window.  None of the image data of image",
+    "         window is in the result.",
+    "",
+    "Out      The resulting image is image with the shape of",
+    "         image window cut out.",
+    "",
+    "Atop     The result is the same shape as image image window,",
+    "         with image obscuring image window where the image",
+    "         shapes overlap.  Note this differs from over",
+    "         because the portion of image outside image window's",
+    "         shape does not appear in the result.",
+    "",
+    "Xor      The result is the image data from both image and",
+    "         image window that is outside the overlap region.",
+    "         The overlap region is blank.",
+    "",
+    "Plus     The result is just the sum of the image data.",
+    "         Output values are cropped to QuantumRange (no overflow).",
+    "",
+    "Minus    The result of image - image window, with underflow",
+    "         cropped to zero.",
+    "",
+    "Add      The result of image + image window, with overflow",
+    "         wrapping around (mod 256).",
+    "",
+    "Subtract The result of image - image window, with underflow",
+    "         wrapping around (mod 256).  The add and subtract",
+    "         operators can be used to perform reversible",
+    "         transformations.",
+    "",
+    "Difference",
+    "         The result of abs(image - image window).  This",
+    "         useful for comparing two very similar images.",
+    "",
+    "Multiply",
+    "         The result of image * image window.  This",
+    "         useful for the creation of drop-shadows.",
+    "",
+    "Bumpmap  The result of surface normals from image * image",
+    "         window.",
+    "",
+    "Copy     The resulting image is image window replaced with",
+    "         image.  Here the matte information is ignored.",
+    "",
+    "CopyRed  The red layer of the image window is replace with",
+    "         the red layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "CopyGreen",
+    "         The green layer of the image window is replace with",
+    "         the green layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "CopyBlue The blue layer of the image window is replace with",
+    "         the blue layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "CopyOpacity",
+    "         The matte layer of the image window is replace with",
+    "         the matte layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "The image compositor requires a matte, or alpha channel in",
+    "the image for some operations.  This extra channel usually",
+    "defines a mask which represents a sort of a cookie-cutter",
+    "for the image.  This the case when matte is opaque (full",
+    "coverage) for pixels inside the shape, zero outside, and",
+    "between 0 and QuantumRange on the boundary.  If image does not",
+    "have a matte channel, it is initialized with 0 for any pixel",
+    "matching in color to pixel location (0,0), otherwise QuantumRange.",
+    "",
+    "If you choose Dissolve, the composite operator becomes Over.  The",
+    "image matte channel percent transparency is initialized to factor.",
+    "The image window is initialized to (100-factor). Where factor is the",
+    "value you specify in the Dialog widget.",
+    "",
+    "Displace shifts the image pixels as defined by a displacement",
+    "map.  With this option, image is used as a displacement map.",
+    "Black, within the displacement map, is a maximum positive",
+    "displacement.  White is a maximum negative displacement and",
+    "middle gray is neutral.  The displacement is scaled to determine",
+    "the pixel shift.  By default, the displacement applies in both the",
+    "horizontal and vertical directions.  However, if you specify a mask,",
+    "image is the horizontal X displacement and mask the vertical Y",
+    "displacement.",
+    "",
+    "Note that matte information for image window is not retained",
+    "for colormapped X server visuals (e.g. StaticColor,",
+    "StaticColor, GrayScale, PseudoColor).  Correct compositing",
+    "behavior may require a TrueColor or DirectColor visual or a",
+    "Standard Colormap.",
+    "",
+    "Choosing a composite operator is optional.  The default",
+    "operator is replace.  However, you must choose a location to",
+    "composite your image and press button 1.  Press and hold the",
+    "button before releasing and an outline of the image will",
+    "appear to help you identify your location.",
+    "",
+    "The actual colors of the composite image is saved.  However,",
+    "the color that appears in image window may be different.",
+    "For example, on a monochrome screen image window will appear",
+    "black or white even though your composited image may have",
+    "many colors.  If the image is saved to a file it is written",
+    "with the correct colors.  To assure the correct colors are",
+    "saved in the final image, any PseudoClass image is promoted",
+    "to DirectClass (see miff(5)).  To force a PseudoClass image",
+    "to remain PseudoClass, use -colors.",
+    (char *) NULL,
+  },
+  *ImageCutHelp[] =
+  {
+    "In cut mode, the Command widget has these options:",
+    "",
+    "    Help",
+    "    Dismiss",
+    "",
+    "To define a cut region, press button 1 and drag.  The",
+    "cut region is defined by a highlighted rectangle that",
+    "expands or contracts as it follows the pointer.  Once you",
+    "are satisfied with the cut region, release the button.",
+    "You are now in rectify mode.  In rectify mode, the Command",
+    "widget has these options:",
+    "",
+    "    Cut",
+    "    Help",
+    "    Dismiss",
+    "",
+    "You can make adjustments by moving the pointer to one of the",
+    "cut rectangle corners, pressing a button, and dragging.",
+    "Finally, press Cut to commit your copy region.  To",
+    "exit without cutting the image, press Dismiss.",
+    (char *) NULL,
+  },
+  *ImageCopyHelp[] =
+  {
+    "In copy mode, the Command widget has these options:",
+    "",
+    "    Help",
+    "    Dismiss",
+    "",
+    "To define a copy region, press button 1 and drag.  The",
+    "copy region is defined by a highlighted rectangle that",
+    "expands or contracts as it follows the pointer.  Once you",
+    "are satisfied with the copy region, release the button.",
+    "You are now in rectify mode.  In rectify mode, the Command",
+    "widget has these options:",
+    "",
+    "    Copy",
+    "    Help",
+    "    Dismiss",
+    "",
+    "You can make adjustments by moving the pointer to one of the",
+    "copy rectangle corners, pressing a button, and dragging.",
+    "Finally, press Copy to commit your copy region.  To",
+    "exit without copying the image, press Dismiss.",
+    (char *) NULL,
+  },
+  *ImageCropHelp[] =
+  {
+    "In crop mode, the Command widget has these options:",
+    "",
+    "    Help",
+    "    Dismiss",
+    "",
+    "To define a cropping region, press button 1 and drag.  The",
+    "cropping region is defined by a highlighted rectangle that",
+    "expands or contracts as it follows the pointer.  Once you",
+    "are satisfied with the cropping region, release the button.",
+    "You are now in rectify mode.  In rectify mode, the Command",
+    "widget has these options:",
+    "",
+    "    Crop",
+    "    Help",
+    "    Dismiss",
+    "",
+    "You can make adjustments by moving the pointer to one of the",
+    "cropping rectangle corners, pressing a button, and dragging.",
+    "Finally, press Crop to commit your cropping region.  To",
+    "exit without cropping the image, press Dismiss.",
+    (char *) NULL,
+  },
+  *ImageDrawHelp[] =
+  {
+    "The cursor changes to a crosshair to indicate you are in",
+    "draw mode.  To exit immediately, press Dismiss.  In draw mode,",
+    "the Command widget has these options:",
+    "",
+    "    Element",
+    "      point",
+    "      line",
+    "      rectangle",
+    "      fill rectangle",
+    "      circle",
+    "      fill circle",
+    "      ellipse",
+    "      fill ellipse",
+    "      polygon",
+    "      fill polygon",
+    "    Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      transparent",
+    "      Browser...",
+    "    Stipple",
+    "      Brick",
+    "      Diagonal",
+    "      Scales",
+    "      Vertical",
+    "      Wavy",
+    "      Translucent",
+    "      Opaque",
+    "      Open...",
+    "    Width",
+    "      1",
+    "      2",
+    "      4",
+    "      8",
+    "      16",
+    "      Dialog...",
+    "    Undo",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a drawing primitive from the Element sub-menu.",
+    "",
+    "Choose a color from the Color sub-menu.  Additional",
+    "colors can be specified with the color browser.",
+    "",
+    "If you choose the color browser and press Grab, you can",
+    "select the color by moving the pointer to the desired",
+    "color on the screen and press any button.  The transparent",
+    "color updates the image matte channel and is useful for",
+    "image compositing.",
+    "",
+    "Choose a stipple, if appropriate, from the Stipple sub-menu.",
+    "Additional stipples can be specified with the file browser.",
+    "Stipples obtained from the file browser must be on disk in the",
+    "X11 bitmap format.",
+    "",
+    "Choose a width, if appropriate, from the Width sub-menu.  To",
+    "choose a specific width select the Dialog widget.",
+    "",
+    "Choose a point in the Image window and press button 1 and",
+    "hold.  Next, move the pointer to another location in the",
+    "image.  As you move, a line connects the initial location and",
+    "the pointer.  When you release the button, the image is",
+    "updated with the primitive you just drew.  For polygons, the",
+    "image is updated when you press and release the button without",
+    "moving the pointer.",
+    "",
+    "To cancel image drawing, move the pointer back to the",
+    "starting point of the line and release the button.",
+    (char *) NULL,
+  },
+  *DisplayHelp[] =
+  {
+    "BUTTONS",
+    "  The effects of each button press is described below.  Three",
+    "  buttons are required.  If you have a two button mouse,",
+    "  button 1 and 3 are returned.  Press ALT and button 3 to",
+    "  simulate button 2.",
+    "",
+    "  1    Press this button to map or unmap the Command widget.",
+    "",
+    "  2    Press and drag to define a region of the image to",
+    "       magnify.",
+    "",
+    "  3    Press and drag to choose from a select set of commands.",
+    "       This button behaves differently if the image being",
+    "       displayed is a visual image directory.  Here, choose a",
+    "       particular tile of the directory and press this button and",
+    "       drag to select a command from a pop-up menu.  Choose from",
+    "       these menu items:",
+    "",
+    "           Open",
+    "           Next",
+    "           Former",
+    "           Delete",
+    "           Update",
+    "",
+    "       If you choose Open, the image represented by the tile is",
+    "       displayed.  To return to the visual image directory, choose",
+    "       Next from the Command widget.  Next and Former moves to the",
+    "       next or former image respectively.  Choose Delete to delete",
+    "       a particular image tile.  Finally, choose Update to",
+    "       synchronize all the image tiles with their respective",
+    "       images.",
+    "",
+    "COMMAND WIDGET",
+    "  The Command widget lists a number of sub-menus and commands.",
+    "  They are",
+    "",
+    "      File",
+    "        Open...",
+    "        Next",
+    "        Former",
+    "        Select...",
+    "        Save...",
+    "        Print...",
+    "        Delete...",
+    "        New...",
+    "        Visual Directory...",
+    "        Quit",
+    "      Edit",
+    "        Undo",
+    "        Redo",
+    "        Cut",
+    "        Copy",
+    "        Paste",
+    "      View",
+    "        Half Size",
+    "        Original Size",
+    "        Double Size",
+    "        Resize...",
+    "        Apply",
+    "        Refresh",
+    "        Restore",
+    "      Transform",
+    "        Crop",
+    "        Chop",
+    "        Flop",
+    "        Flip",
+    "        Rotate Right",
+    "        Rotate Left",
+    "        Rotate...",
+    "        Shear...",
+    "        Roll...",
+    "        Trim Edges",
+    "      Enhance",
+    "        Brightness...",
+    "        Saturation...",
+    "        Hue...",
+    "        Gamma...",
+    "        Sharpen...",
+    "        Dull",
+    "        Contrast Stretch...",
+    "        Sigmoidal Contrast...",
+    "        Normalize",
+    "        Equalize",
+    "        Negate",
+    "        Grayscale",
+    "        Map...",
+    "        Quantize...",
+    "      Effects",
+    "        Despeckle",
+    "        Emboss",
+    "        Reduce Noise",
+    "        Add Noise",
+    "        Sharpen...",
+    "        Blur...",
+    "        Threshold...",
+    "        Edge Detect...",
+    "        Spread...",
+    "        Shade...",
+    "        Painting...",
+    "        Segment...",
+    "      F/X",
+    "        Solarize...",
+    "        Sepia Tone...",
+    "        Swirl...",
+    "        Implode...",
+    "        Vignette...",
+    "        Wave...",
+    "        Oil Painting...",
+    "        Charcoal Drawing...",
+    "      Image Edit",
+    "        Annotate...",
+    "        Draw...",
+    "        Color...",
+    "        Matte...",
+    "        Composite...",
+    "        Add Border...",
+    "        Add Frame...",
+    "        Comment...",
+    "        Launch...",
+    "        Region of Interest...",
+    "      Miscellany",
+    "        Image Info",
+    "        Zoom Image",
+    "        Show Preview...",
+    "        Show Histogram",
+    "        Show Matte",
+    "        Background...",
+    "        Slide Show",
+    "        Preferences...",
+    "      Help",
+    "        Overview",
+    "        Browse Documentation",
+    "        About Display",
+    "",
+    "  Menu items with a indented triangle have a sub-menu.  They",
+    "  are represented above as the indented items.  To access a",
+    "  sub-menu item, move the pointer to the appropriate menu and",
+    "  press a button and drag.  When you find the desired sub-menu",
+    "  item, release the button and the command is executed.  Move",
+    "  the pointer away from the sub-menu if you decide not to",
+    "  execute a particular command.",
+    "",
+    "KEYBOARD ACCELERATORS",
+    "  Accelerators are one or two key presses that effect a",
+    "  particular command.  The keyboard accelerators that",
+    "  display(1) understands is:",
+    "",
+    "  Ctl+O     Press to open an image from a file.",
+    "",
+    "  space     Press to display the next image.",
+    "",
+    "            If the image is a multi-paged document such as a Postscript",
+    "            document, you can skip ahead several pages by preceding",
+    "            this command with a number.  For example to display the",
+    "            third page beyond the current page, press 3<space>.",
+    "",
+    "  backspace Press to display the former image.",
+    "",
+    "            If the image is a multi-paged document such as a Postscript",
+    "            document, you can skip behind several pages by preceding",
+    "            this command with a number.  For example to display the",
+    "            third page preceding the current page, press 3<backspace>.",
+    "",
+    "  Ctl+S     Press to write the image to a file.",
+    "",
+    "  Ctl+P     Press to print the image to a Postscript printer.",
+    "",
+    "  Ctl+D     Press to delete an image file.",
+    "",
+    "  Ctl+N     Press to create a blank canvas.",
+    "",
+    "  Ctl+Q     Press to discard all images and exit program.",
+    "",
+    "  Ctl+Z     Press to undo last image transformation.",
+    "",
+    "  Ctl+R     Press to redo last image transformation.",
+    "",
+    "  Ctl+X     Press to cut a region of the image.",
+    "",
+    "  Ctl+C     Press to copy a region of the image.",
+    "",
+    "  Ctl+V     Press to paste a region to the image.",
+    "",
+    "  <         Press to half the image size.",
+    "",
+    "  -         Press to return to the original image size.",
+    "",
+    "  >         Press to double the image size.",
+    "",
+    "  %         Press to resize the image to a width and height you",
+    "            specify.",
+    "",
+    "Cmd-A       Press to make any image transformations permanent."
+    "",
+    "            By default, any image size transformations are applied",
+    "            to the original image to create the image displayed on",
+    "            the X server.  However, the transformations are not",
+    "            permanent (i.e. the original image does not change",
+    "            size only the X image does).  For example, if you",
+    "            press > the X image will appear to double in size,",
+    "            but the original image will in fact remain the same size.",
+    "            To force the original image to double in size, press >",
+    "            followed by Cmd-A.",
+    "",
+    "  @         Press to refresh the image window.",
+    "",
+    "  C         Press to cut out a rectangular region of the image.",
+    "",
+    "  [         Press to chop the image.",
+    "",
+    "  H         Press to flop image in the horizontal direction.",
+    "",
+    "  V         Press to flip image in the vertical direction.",
+    "",
+    "  /         Press to rotate the image 90 degrees clockwise.",
+    "",
+    " \\         Press to rotate the image 90 degrees counter-clockwise.",
+    "",
+    "  *         Press to rotate the image the number of degrees you",
+    "            specify.",
+    "",
+    "  S         Press to shear the image the number of degrees you",
+    "            specify.",
+    "",
+    "  R         Press to roll the image.",
+    "",
+    "  T         Press to trim the image edges.",
+    "",
+    "  Shft-H    Press to vary the image hue.",
+    "",
+    "  Shft-S    Press to vary the color saturation.",
+    "",
+    "  Shft-L    Press to vary the color brightness.",
+    "",
+    "  Shft-G    Press to gamma correct the image.",
+    "",
+    "  Shft-C    Press to sharpen the image contrast.",
+    "",
+    "  Shft-Z    Press to dull the image contrast.",
+    "",
+    "  =         Press to perform histogram equalization on the image.",
+    "",
+    "  Shft-N    Press to perform histogram normalization on the image.",
+    "",
+    "  Shft-~    Press to negate the colors of the image.",
+    "",
+    "  .         Press to convert the image colors to gray.",
+    "",
+    "  Shft-#    Press to set the maximum number of unique colors in the",
+    "            image.",
+    "",
+    "  F2        Press to reduce the speckles in an image.",
+    "",
+    "  F3        Press to eliminate peak noise from an image.",
+    "",
+    "  F4        Press to add noise to an image.",
+    "",
+    "  F5        Press to sharpen an image.",
+    "",
+    "  F6        Press to delete an image file.",
+    "",
+    "  F7        Press to threshold the image.",
+    "",
+    "  F8        Press to detect edges within an image.",
+    "",
+    "  F9        Press to emboss an image.",
+    "",
+    "  F10       Press to displace pixels by a random amount.",
+    "",
+    "  F11       Press to negate all pixels above the threshold level.",
+    "",
+    "  F12       Press to shade the image using a distant light source.",
+    "",
+    "  F13       Press to lighten or darken image edges to create a 3-D effect.",
+    "",
+    "  F14       Press to segment the image by color.",
+    "",
+    "  Meta-S    Press to swirl image pixels about the center.",
+    "",
+    "  Meta-I    Press to implode image pixels about the center.",
+    "",
+    "  Meta-W    Press to alter an image along a sine wave.",
+    "",
+    "  Meta-P    Press to simulate an oil painting.",
+    "",
+    "  Meta-C    Press to simulate a charcoal drawing.",
+    "",
+    "  Alt-A     Press to annotate the image with text.",
+    "",
+    "  Alt-D     Press to draw on an image.",
+    "",
+    "  Alt-P     Press to edit an image pixel color.",
+    "",
+    "  Alt-M     Press to edit the image matte information.",
+    "",
+    "  Alt-V     Press to composite the image with another.",
+    "",
+    "  Alt-B     Press to add a border to the image.",
+    "",
+    "  Alt-F     Press to add an ornamental border to the image.",
+    "",
+    "  Alt-Shft-!",
+    "            Press to add an image comment.",
+    "",
+    "  Ctl-A     Press to apply image processing techniques to a region",
+    "            of interest.",
+    "",
+    "  Shft-?    Press to display information about the image.",
+    "",
+    "  Shft-+    Press to map the zoom image window.",
+    "",
+    "  Shft-P    Press to preview an image enhancement, effect, or f/x.",
+    "",
+    "  F1        Press to display helpful information about display(1).",
+    "",
+    "  Find      Press to browse documentation about ImageMagick.",
+    "",
+    "  1-9       Press to change the level of magnification.",
+    "",
+    "  Use the arrow keys to move the image one pixel up, down,",
+    "  left, or right within the magnify window.  Be sure to first",
+    "  map the magnify window by pressing button 2.",
+    "",
+    "  Press ALT and one of the arrow keys to trim off one pixel",
+    "  from any side of the image.",
+    (char *) NULL,
+  },
+  *ImageMatteEditHelp[] =
+  {
+    "Matte information within an image is useful for some",
+    "operations such as image compositing (See IMAGE",
+    "COMPOSITING).  This extra channel usually defines a mask",
+    "which represents a sort of a cookie-cutter for the image.",
+    "This the case when matte is opaque (full coverage) for",
+    "pixels inside the shape, zero outside, and between 0 and",
+    "QuantumRange on the boundary.",
+    "",
+    "A small window appears showing the location of the cursor in",
+    "the image window. You are now in matte edit mode.  To exit",
+    "immediately, press Dismiss.  In matte edit mode, the Command",
+    "widget has these options:",
+    "",
+    "    Method",
+    "      point",
+    "      replace",
+    "      floodfill",
+    "      filltoborder",
+    "      reset",
+    "    Border Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      Browser...",
+    "    Fuzz",
+    "      0%",
+    "      2%",
+    "      5%",
+    "      10%",
+    "      15%",
+    "      Dialog...",
+    "    Matte",
+    "      Opaque",
+    "      Transparent",
+    "      Dialog...",
+    "    Undo",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a matte editing method from the Method sub-menu of",
+    "the Command widget.  The point method changes the matte value",
+    "of any pixel selected with the pointer until the button is",
+    "is released.  The replace method changes the matte value of",
+    "any pixel that matches the color of the pixel you select with",
+    "a button press.  Floodfill changes the matte value of any pixel",
+    "that matches the color of the pixel you select with a button",
+    "press and is a neighbor.  Whereas filltoborder changes the matte",
+    "value any neighbor pixel that is not the border color.  Finally",
+    "reset changes the entire image to the designated matte value.",
+    "",
+    "Choose Matte Value and pick Opaque or Transarent.  For other values",
+    "select the Dialog entry.  Here a dialog appears requesting a matte",
+    "value.  The value you select is assigned as the opacity value of the",
+    "selected pixel or pixels.",
+    "",
+    "Now, press any button to select a pixel within the image",
+    "window to change its matte value.",
+    "",
+    "If the Magnify widget is mapped, it can be helpful in positioning",
+    "your pointer within the image (refer to button 2).",
+    "",
+    "Matte information is only valid in a DirectClass image.",
+    "Therefore, any PseudoClass image is promoted to DirectClass",
+    "(see miff(5)).  Note that matte information for PseudoClass",
+    "is not retained for colormapped X server visuals (e.g.",
+    "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
+    "immediately save your image to a file (refer to Write).",
+    "Correct matte editing behavior may require a TrueColor or",
+    "DirectColor visual or a Standard Colormap.",
+    (char *) NULL,
+  },
+  *ImagePanHelp[] =
+  {
+    "When an image exceeds the width or height of the X server",
+    "screen, display maps a small panning icon.  The rectangle",
+    "within the panning icon shows the area that is currently",
+    "displayed in the image window.  To pan about the image,",
+    "press any button and drag the pointer within the panning",
+    "icon.  The pan rectangle moves with the pointer and the",
+    "image window is updated to reflect the location of the",
+    "rectangle within the panning icon.  When you have selected",
+    "the area of the image you wish to view, release the button.",
+    "",
+    "Use the arrow keys to pan the image one pixel up, down,",
+    "left, or right within the image window.",
+    "",
+    "The panning icon is withdrawn if the image becomes smaller",
+    "than the dimensions of the X server screen.",
+    (char *) NULL,
+  },
+  *ImagePasteHelp[] =
+  {
+    "A small window appears showing the location of the cursor in",
+    "the image window. You are now in paste mode.  To exit",
+    "immediately, press Dismiss.  In paste mode, the Command",
+    "widget has these options:",
+    "",
+    "    Operators",
+    "      over",
+    "      in",
+    "      out",
+    "      atop",
+    "      xor",
+    "      plus",
+    "      minus",
+    "      add",
+    "      subtract",
+    "      difference",
+    "      replace",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a composite operation from the Operators sub-menu of",
+    "the Command widget.  How each operator behaves is described",
+    "below.  Image window is the image currently displayed on",
+    "your X server and image is the image obtained with the File",
+    "Browser widget.",
+    "",
+    "Over     The result is the union of the two image shapes,",
+    "         with image obscuring image window in the region of",
+    "         overlap.",
+    "",
+    "In       The result is simply image cut by the shape of",
+    "         image window.  None of the image data of image",
+    "         window is in the result.",
+    "",
+    "Out      The resulting image is image with the shape of",
+    "         image window cut out.",
+    "",
+    "Atop     The result is the same shape as image image window,",
+    "         with image obscuring image window where the image",
+    "         shapes overlap.  Note this differs from over",
+    "         because the portion of image outside image window's",
+    "         shape does not appear in the result.",
+    "",
+    "Xor      The result is the image data from both image and",
+    "         image window that is outside the overlap region.",
+    "         The overlap region is blank.",
+    "",
+    "Plus     The result is just the sum of the image data.",
+    "         Output values are cropped to QuantumRange (no overflow).",
+    "         This operation is independent of the matte",
+    "         channels.",
+    "",
+    "Minus    The result of image - image window, with underflow",
+    "         cropped to zero.",
+    "",
+    "Add      The result of image + image window, with overflow",
+    "         wrapping around (mod 256).",
+    "",
+    "Subtract The result of image - image window, with underflow",
+    "         wrapping around (mod 256).  The add and subtract",
+    "         operators can be used to perform reversible",
+    "         transformations.",
+    "",
+    "Difference",
+    "         The result of abs(image - image window).  This",
+    "         useful for comparing two very similar images.",
+    "",
+    "Copy     The resulting image is image window replaced with",
+    "         image.  Here the matte information is ignored.",
+    "",
+    "CopyRed  The red layer of the image window is replace with",
+    "         the red layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "CopyGreen",
+    "         The green layer of the image window is replace with",
+    "         the green layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "CopyBlue The blue layer of the image window is replace with",
+    "         the blue layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "CopyOpacity",
+    "         The matte layer of the image window is replace with",
+    "         the matte layer of the image.  The other layers are",
+    "         untouched.",
+    "",
+    "The image compositor requires a matte, or alpha channel in",
+    "the image for some operations.  This extra channel usually",
+    "defines a mask which represents a sort of a cookie-cutter",
+    "for the image.  This the case when matte is opaque (full",
+    "coverage) for pixels inside the shape, zero outside, and",
+    "between 0 and QuantumRange on the boundary.  If image does not",
+    "have a matte channel, it is initialized with 0 for any pixel",
+    "matching in color to pixel location (0,0), otherwise QuantumRange.",
+    "",
+    "Note that matte information for image window is not retained",
+    "for colormapped X server visuals (e.g. StaticColor,",
+    "StaticColor, GrayScale, PseudoColor).  Correct compositing",
+    "behavior may require a TrueColor or DirectColor visual or a",
+    "Standard Colormap.",
+    "",
+    "Choosing a composite operator is optional.  The default",
+    "operator is replace.  However, you must choose a location to",
+    "paste your image and press button 1.  Press and hold the",
+    "button before releasing and an outline of the image will",
+    "appear to help you identify your location.",
+    "",
+    "The actual colors of the pasted image is saved.  However,",
+    "the color that appears in image window may be different.",
+    "For example, on a monochrome screen image window will appear",
+    "black or white even though your pasted image may have",
+    "many colors.  If the image is saved to a file it is written",
+    "with the correct colors.  To assure the correct colors are",
+    "saved in the final image, any PseudoClass image is promoted",
+    "to DirectClass (see miff(5)).  To force a PseudoClass image",
+    "to remain PseudoClass, use -colors.",
+    (char *) NULL,
+  },
+  *ImageROIHelp[] =
+  {
+    "In region of interest mode, the Command widget has these",
+    "options:",
+    "",
+    "    Help",
+    "    Dismiss",
+    "",
+    "To define a region of interest, press button 1 and drag.",
+    "The region of interest is defined by a highlighted rectangle",
+    "that expands or contracts as it follows the pointer.  Once",
+    "you are satisfied with the region of interest, release the",
+    "button.  You are now in apply mode.  In apply mode the",
+    "Command widget has these options:",
+    "",
+    "      File",
+    "        Save...",
+    "        Print...",
+    "      Edit",
+    "        Undo",
+    "        Redo",
+    "      Transform",
+    "        Flop",
+    "        Flip",
+    "        Rotate Right",
+    "        Rotate Left",
+    "      Enhance",
+    "        Hue...",
+    "        Saturation...",
+    "        Brightness...",
+    "        Gamma...",
+    "        Spiff",
+    "        Dull",
+    "        Contrast Stretch",
+    "        Sigmoidal Contrast...",
+    "        Normalize",
+    "        Equalize",
+    "        Negate",
+    "        Grayscale",
+    "        Map...",
+    "        Quantize...",
+    "      Effects",
+    "        Despeckle",
+    "        Emboss",
+    "        Reduce Noise",
+    "        Sharpen...",
+    "        Blur...",
+    "        Threshold...",
+    "        Edge Detect...",
+    "        Spread...",
+    "        Shade...",
+    "        Raise...",
+    "        Segment...",
+    "      F/X",
+    "        Solarize...",
+    "        Sepia Tone...",
+    "        Swirl...",
+    "        Implode...",
+    "        Vignette...",
+    "        Wave...",
+    "        Oil Painting...",
+    "        Charcoal Drawing...",
+    "      Miscellany",
+    "        Image Info",
+    "        Zoom Image",
+    "        Show Preview...",
+    "        Show Histogram",
+    "        Show Matte",
+    "      Help",
+    "      Dismiss",
+    "",
+    "You can make adjustments to the region of interest by moving",
+    "the pointer to one of the rectangle corners, pressing a",
+    "button, and dragging.  Finally, choose an image processing",
+    "technique from the Command widget.  You can choose more than",
+    "one image processing technique to apply to an area.",
+    "Alternatively, you can move the region of interest before",
+    "applying another image processing technique.  To exit, press",
+    "Dismiss.",
+    (char *) NULL,
+  },
+  *ImageRotateHelp[] =
+  {
+    "In rotate mode, the Command widget has these options:",
+    "",
+    "    Pixel Color",
+    "      black",
+    "      blue",
+    "      cyan",
+    "      green",
+    "      gray",
+    "      red",
+    "      magenta",
+    "      yellow",
+    "      white",
+    "      Browser...",
+    "    Direction",
+    "      horizontal",
+    "      vertical",
+    "    Help",
+    "    Dismiss",
+    "",
+    "Choose a background color from the Pixel Color sub-menu.",
+    "Additional background colors can be specified with the color",
+    "browser.  You can change the menu colors by setting the X",
+    "resources pen1 through pen9.",
+    "",
+    "If you choose the color browser and press Grab, you can",
+    "select the background color by moving the pointer to the",
+    "desired color on the screen and press any button.",
+    "",
+    "Choose a point in the image window and press this button and",
+    "hold.  Next, move the pointer to another location in the",
+    "image.  As you move a line connects the initial location and",
+    "the pointer.  When you release the button, the degree of",
+    "image rotation is determined by the slope of the line you",
+    "just drew.  The slope is relative to the direction you",
+    "choose from the Direction sub-menu of the Command widget.",
+    "",
+    "To cancel the image rotation, move the pointer back to the",
+    "starting point of the line and release the button.",
+    (char *) NULL,
+  };
+
+/*
+  Enumeration declarations.
+*/
+typedef enum
+{
+  CopyMode,
+  CropMode,
+  CutMode
+} ClipboardMode;
+
+typedef enum
+{
+  OpenCommand,
+  NextCommand,
+  FormerCommand,
+  SelectCommand,
+  SaveCommand,
+  PrintCommand,
+  DeleteCommand,
+  NewCommand,
+  VisualDirectoryCommand,
+  QuitCommand,
+  UndoCommand,
+  RedoCommand,
+  CutCommand,
+  CopyCommand,
+  PasteCommand,
+  HalfSizeCommand,
+  OriginalSizeCommand,
+  DoubleSizeCommand,
+  ResizeCommand,
+  ApplyCommand,
+  RefreshCommand,
+  RestoreCommand,
+  CropCommand,
+  ChopCommand,
+  FlopCommand,
+  FlipCommand,
+  RotateRightCommand,
+  RotateLeftCommand,
+  RotateCommand,
+  ShearCommand,
+  RollCommand,
+  TrimCommand,
+  HueCommand,
+  SaturationCommand,
+  BrightnessCommand,
+  GammaCommand,
+  SpiffCommand,
+  DullCommand,
+  ContrastStretchCommand,
+  SigmoidalContrastCommand,
+  NormalizeCommand,
+  EqualizeCommand,
+  NegateCommand,
+  GrayscaleCommand,
+  MapCommand,
+  QuantizeCommand,
+  DespeckleCommand,
+  EmbossCommand,
+  ReduceNoiseCommand,
+  AddNoiseCommand,
+  SharpenCommand,
+  BlurCommand,
+  ThresholdCommand,
+  EdgeDetectCommand,
+  SpreadCommand,
+  ShadeCommand,
+  RaiseCommand,
+  SegmentCommand,
+  SolarizeCommand,
+  SepiaToneCommand,
+  SwirlCommand,
+  ImplodeCommand,
+  VignetteCommand,
+  WaveCommand,
+  OilPaintCommand,
+  CharcoalDrawCommand,
+  AnnotateCommand,
+  DrawCommand,
+  ColorCommand,
+  MatteCommand,
+  CompositeCommand,
+  AddBorderCommand,
+  AddFrameCommand,
+  CommentCommand,
+  LaunchCommand,
+  RegionofInterestCommand,
+  ROIHelpCommand,
+  ROIDismissCommand,
+  InfoCommand,
+  ZoomCommand,
+  ShowPreviewCommand,
+  ShowHistogramCommand,
+  ShowMatteCommand,
+  BackgroundCommand,
+  SlideShowCommand,
+  PreferencesCommand,
+  HelpCommand,
+  BrowseDocumentationCommand,
+  VersionCommand,
+  SaveToUndoBufferCommand,
+  FreeBuffersCommand,
+  NullCommand
+} CommandType;
+
+typedef enum
+{
+  AnnotateNameCommand,
+  AnnotateFontColorCommand,
+  AnnotateBackgroundColorCommand,
+  AnnotateRotateCommand,
+  AnnotateHelpCommand,
+  AnnotateDismissCommand,
+  TextHelpCommand,
+  TextApplyCommand,
+  ChopDirectionCommand,
+  ChopHelpCommand,
+  ChopDismissCommand,
+  HorizontalChopCommand,
+  VerticalChopCommand,
+  ColorEditMethodCommand,
+  ColorEditColorCommand,
+  ColorEditBorderCommand,
+  ColorEditFuzzCommand,
+  ColorEditUndoCommand,
+  ColorEditHelpCommand,
+  ColorEditDismissCommand,
+  CompositeOperatorsCommand,
+  CompositeDissolveCommand,
+  CompositeDisplaceCommand,
+  CompositeHelpCommand,
+  CompositeDismissCommand,
+  CropHelpCommand,
+  CropDismissCommand,
+  RectifyCopyCommand,
+  RectifyHelpCommand,
+  RectifyDismissCommand,
+  DrawElementCommand,
+  DrawColorCommand,
+  DrawStippleCommand,
+  DrawWidthCommand,
+  DrawUndoCommand,
+  DrawHelpCommand,
+  DrawDismissCommand,
+  MatteEditMethod,
+  MatteEditBorderCommand,
+  MatteEditFuzzCommand,
+  MatteEditValueCommand,
+  MatteEditUndoCommand,
+  MatteEditHelpCommand,
+  MatteEditDismissCommand,
+  PasteOperatorsCommand,
+  PasteHelpCommand,
+  PasteDismissCommand,
+  RotateColorCommand,
+  RotateDirectionCommand,
+  RotateCropCommand,
+  RotateSharpenCommand,
+  RotateHelpCommand,
+  RotateDismissCommand,
+  HorizontalRotateCommand,
+  VerticalRotateCommand,
+  TileLoadCommand,
+  TileNextCommand,
+  TileFormerCommand,
+  TileDeleteCommand,
+  TileUpdateCommand
+} ModeType;
+
+/*
+  Stipples.
+*/
+#define BricksWidth  20
+#define BricksHeight  20
+#define DiagonalWidth  16
+#define DiagonalHeight  16
+#define HighlightWidth  8
+#define HighlightHeight  8
+#define OpaqueWidth  8
+#define OpaqueHeight  8
+#define ScalesWidth  16
+#define ScalesHeight  16
+#define ShadowWidth  8
+#define ShadowHeight  8
+#define VerticalWidth  16
+#define VerticalHeight  16
+#define WavyWidth  16
+#define WavyHeight  16
+
+/*
+  Constant declaration.
+*/
+static const int
+  RoiDelta = 8;
+
+static const unsigned char
+  BricksBitmap[] =
+  {
+    0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
+    0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
+    0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
+    0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
+    0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
+  },
+  DiagonalBitmap[] =
+  {
+    0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
+    0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
+    0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
+  },
+  ScalesBitmap[] =
+  {
+    0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
+    0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
+    0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
+  },
+  VerticalBitmap[] =
+  {
+    0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+    0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+    0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+  },
+  WavyBitmap[] =
+  {
+    0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
+    0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
+    0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
+  };
+
+/*
+  Function prototypes.
+*/
+static CommandType
+  XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
+    const MagickStatusType,KeySym,Image **);
+
+static Image
+  *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
+    Image **),
+  *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
+  *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
+  *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
+
+static MagickBooleanType
+  XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
+  XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
+  XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
+  XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
+  XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
+  XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
+  XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
+  XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
+  XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
+
+static void
+  XDrawPanRectangle(Display *,XWindows *),
+  XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
+  XMagnifyImage(Display *,XWindows *,XEvent *),
+  XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
+  XPanImage(Display *,XWindows *,XEvent *),
+  XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
+    const KeySym),
+  XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
+  XScreenEvent(Display *,XWindows *,XEvent *),
+  XTranslateImage(Display *,XWindows *,Image *,const KeySym);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D i s p l a y I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DisplayImages() displays an image sequence to any X window screen.  It
+%  returns a value other than 0 if successful.  Check the exception member
+%  of image to determine the reason for any failure.
+%
+%  The format of the DisplayImages method is:
+%
+%      MagickBooleanType DisplayImages(const ImageInfo *image_info,
+%        Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
+  Image *images)
+{
+  char
+    *argv[1];
+
+  Display
+    *display;
+
+  Image
+    *image;
+
+  register ssize_t
+    i;
+
+  size_t
+    state;
+
+  XrmDatabase
+    resource_database;
+
+  XResourceInfo
+    resource_info;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  display=XOpenDisplay(image_info->server_name);
+  if (display == (Display *) NULL)
+    {
+      (void) ThrowMagickException(&images->exception,GetMagickModule(),
+        XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
+        image_info->server_name));
+      return(MagickFalse);
+    }
+  if (images->exception.severity != UndefinedException)
+    CatchException(&images->exception);
+  (void) XSetErrorHandler(XError);
+  resource_database=XGetResourceDatabase(display,GetClientName());
+  (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
+  XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
+  if (image_info->page != (char *) NULL)
+    resource_info.image_geometry=AcquireString(image_info->page);
+  resource_info.immutable=MagickTrue;
+  argv[0]=AcquireString(GetClientName());
+  state=DefaultState;
+  for (i=0; (state & ExitState) == 0; i++)
+  {
+    if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
+      break;
+    image=GetImageFromList(images,i % GetImageListLength(images));
+    (void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
+  }
+  argv[0]=DestroyString(argv[0]);
+  (void) XCloseDisplay(display);
+  XDestroyResourceInfo(&resource_info);
+  if (images->exception.severity != UndefinedException)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o t e D i s p l a y C o m m a n d                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoteDisplayCommand() encourages a remote display program to display the
+%  specified image filename.
+%
+%  The format of the RemoteDisplayCommand method is:
+%
+%      MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
+%        const char *window,const char *filename,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o window: Specifies the name or id of an X window.
+%
+%    o filename: the name of the image filename to display.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
+  const char *window,const char *filename,ExceptionInfo *exception)
+{
+  Display
+    *display;
+
+  MagickStatusType
+    status;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(filename != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  display=XOpenDisplay(image_info->server_name);
+  if (display == (Display *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
+        "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
+      return(MagickFalse);
+    }
+  (void) XSetErrorHandler(XError);
+  status=XRemoteCommand(display,window,filename);
+  (void) XCloseDisplay(display);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X A n n o t a t e E d i t I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XAnnotateEditImage() annotates the image with text.
+%
+%  The format of the XAnnotateEditImage method is:
+%
+%      MagickBooleanType XAnnotateEditImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+*/
+
+static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickBooleanType XAnnotateEditImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  static const char
+    *AnnotateMenu[] =
+    {
+      "Font Name",
+      "Font Color",
+      "Box Color",
+      "Rotate Text",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    },
+    *TextMenu[] =
+    {
+      "Help",
+      "Apply",
+      (char *) NULL
+    };
+
+  static const ModeType
+    AnnotateCommands[] =
+    {
+      AnnotateNameCommand,
+      AnnotateFontColorCommand,
+      AnnotateBackgroundColorCommand,
+      AnnotateRotateCommand,
+      AnnotateHelpCommand,
+      AnnotateDismissCommand
+    },
+    TextCommands[] =
+    {
+      TextHelpCommand,
+      TextApplyCommand
+    };
+
+  static MagickBooleanType
+    transparent_box = MagickTrue,
+    transparent_pen = MagickFalse;
+
+  static MagickRealType
+    degrees = 0.0;
+
+  static unsigned int
+    box_id = MaxNumberPens-2,
+    font_id = 0,
+    pen_id = 0;
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  const char
+    *ColorMenu[MaxNumberPens+1];
+
+  Cursor
+    cursor;
+
+  GC
+    annotate_context;
+
+  int
+    id,
+    pen_number,
+    status,
+    x,
+    y;
+
+  KeySym
+    key_symbol;
+
+  register char
+    *p;
+
+  register ssize_t
+    i;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XAnnotateInfo
+    *annotate_info,
+    *previous_info;
+
+  XColor
+    color;
+
+  XFontStruct
+    *font_info;
+
+  XEvent
+    event,
+    text_event;
+
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Annotate");
+  windows->command.data=4;
+  (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  cursor=XCreateFontCursor(display,XC_left_side);
+  (void) XCheckDefineCursor(display,windows->image.id,cursor);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
+          x+windows->image.x,y+windows->image.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,AnnotateMenu,&event);
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        if (id < 0)
+          continue;
+        switch (AnnotateCommands[id])
+        {
+          case AnnotateNameCommand:
+          {
+            const char
+              *FontMenu[MaxNumberFonts];
+
+            int
+              font_number;
+
+            /*
+              Initialize menu selections.
+            */
+            for (i=0; i < MaxNumberFonts; i++)
+              FontMenu[i]=resource_info->font_name[i];
+            FontMenu[MaxNumberFonts-2]="Browser...";
+            FontMenu[MaxNumberFonts-1]=(const char *) NULL;
+            /*
+              Select a font name from the pop-up menu.
+            */
+            font_number=XMenuWidget(display,windows,AnnotateMenu[id],
+              (const char **) FontMenu,command);
+            if (font_number < 0)
+              break;
+            if (font_number == (MaxNumberFonts-2))
+              {
+                static char
+                  font_name[MaxTextExtent] = "fixed";
+
+                /*
+                  Select a font name from a browser.
+                */
+                resource_info->font_name[font_number]=font_name;
+                XFontBrowserWidget(display,windows,"Select",font_name);
+                if (*font_name == '\0')
+                  break;
+              }
+            /*
+              Initialize font info.
+            */
+            font_info=XLoadQueryFont(display,resource_info->font_name[
+              font_number]);
+            if (font_info == (XFontStruct *) NULL)
+              {
+                XNoticeWidget(display,windows,"Unable to load font:",
+                  resource_info->font_name[font_number]);
+                break;
+              }
+            font_id=(unsigned int) font_number;
+            (void) XFreeFont(display,font_info);
+            break;
+          }
+          case AnnotateFontColorCommand:
+          {
+            /*
+              Initialize menu selections.
+            */
+            for (i=0; i < (int) (MaxNumberPens-2); i++)
+              ColorMenu[i]=resource_info->pen_colors[i];
+            ColorMenu[MaxNumberPens-2]="transparent";
+            ColorMenu[MaxNumberPens-1]="Browser...";
+            ColorMenu[MaxNumberPens]=(const char *) NULL;
+            /*
+              Select a pen color from the pop-up menu.
+            */
+            pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
+              (const char **) ColorMenu,command);
+            if (pen_number < 0)
+              break;
+            transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
+              MagickFalse;
+            if (transparent_pen != MagickFalse)
+              break;
+            if (pen_number == (MaxNumberPens-1))
+              {
+                static char
+                  color_name[MaxTextExtent] = "gray";
+
+                /*
+                  Select a pen color from a dialog.
+                */
+                resource_info->pen_colors[pen_number]=color_name;
+                XColorBrowserWidget(display,windows,"Select",color_name);
+                if (*color_name == '\0')
+                  break;
+              }
+            /*
+              Set pen color.
+            */
+            (void) XParseColor(display,windows->map_info->colormap,
+              resource_info->pen_colors[pen_number],&color);
+            XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
+              (unsigned int) MaxColors,&color);
+            windows->pixel_info->pen_colors[pen_number]=color;
+            pen_id=(unsigned int) pen_number;
+            break;
+          }
+          case AnnotateBackgroundColorCommand:
+          {
+            /*
+              Initialize menu selections.
+            */
+            for (i=0; i < (int) (MaxNumberPens-2); i++)
+              ColorMenu[i]=resource_info->pen_colors[i];
+            ColorMenu[MaxNumberPens-2]="transparent";
+            ColorMenu[MaxNumberPens-1]="Browser...";
+            ColorMenu[MaxNumberPens]=(const char *) NULL;
+            /*
+              Select a pen color from the pop-up menu.
+            */
+            pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
+              (const char **) ColorMenu,command);
+            if (pen_number < 0)
+              break;
+            transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
+              MagickFalse;
+            if (transparent_box != MagickFalse)
+              break;
+            if (pen_number == (MaxNumberPens-1))
+              {
+                static char
+                  color_name[MaxTextExtent] = "gray";
+
+                /*
+                  Select a pen color from a dialog.
+                */
+                resource_info->pen_colors[pen_number]=color_name;
+                XColorBrowserWidget(display,windows,"Select",color_name);
+                if (*color_name == '\0')
+                  break;
+              }
+            /*
+              Set pen color.
+            */
+            (void) XParseColor(display,windows->map_info->colormap,
+              resource_info->pen_colors[pen_number],&color);
+            XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
+              (unsigned int) MaxColors,&color);
+            windows->pixel_info->pen_colors[pen_number]=color;
+            box_id=(unsigned int) pen_number;
+            break;
+          }
+          case AnnotateRotateCommand:
+          {
+            int
+              entry;
+
+            static char
+              angle[MaxTextExtent] = "30.0";
+
+            static const char
+              *RotateMenu[] =
+              {
+                "-90",
+                "-45",
+                "-30",
+                "0",
+                "30",
+                "45",
+                "90",
+                "180",
+                "Dialog...",
+                (char *) NULL,
+              };
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
+              command);
+            if (entry < 0)
+              break;
+            if (entry != 8)
+              {
+                degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL);
+                break;
+              }
+            (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
+              angle);
+            if (*angle == '\0')
+              break;
+            degrees=InterpretLocaleValue(angle,(char **) NULL);
+            break;
+          }
+          case AnnotateHelpCommand:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Annotation",ImageAnnotateHelp);
+            break;
+          }
+          case AnnotateDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        /*
+          Change to text entering mode.
+        */
+        x=event.xbutton.x;
+        y=event.xbutton.y;
+        state|=ExitState;
+        break;
+      }
+      case ButtonRelease:
+        break;
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Annotation",ImageAnnotateHelp);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  if ((state & EscapeState) != 0)
+    return(MagickTrue);
+  /*
+    Set font info and check boundary conditions.
+  */
+  font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
+  if (font_info == (XFontStruct *) NULL)
+    {
+      XNoticeWidget(display,windows,"Unable to load font:",
+        resource_info->font_name[font_id]);
+      font_info=windows->font_info;
+    }
+  if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
+    x=(int) windows->image.width-font_info->max_bounds.width;
+  if (y < (int) (font_info->ascent+font_info->descent))
+    y=(int) font_info->ascent+font_info->descent;
+  if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
+      ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
+    return(MagickFalse);
+  /*
+    Initialize annotate structure.
+  */
+  annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
+  if (annotate_info == (XAnnotateInfo *) NULL)
+    return(MagickFalse);
+  XGetAnnotateInfo(annotate_info);
+  annotate_info->x=x;
+  annotate_info->y=y;
+  if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
+    annotate_info->stencil=OpaqueStencil;
+  else
+    if (transparent_box == MagickFalse)
+      annotate_info->stencil=BackgroundStencil;
+    else
+      annotate_info->stencil=ForegroundStencil;
+  annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
+  annotate_info->degrees=degrees;
+  annotate_info->font_info=font_info;
+  annotate_info->text=(char *) AcquireQuantumMemory((size_t)
+    windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
+    sizeof(*annotate_info->text));
+  if (annotate_info->text == (char *) NULL)
+    return(MagickFalse);
+  /*
+    Create cursor and set graphic context.
+  */
+  cursor=XCreateFontCursor(display,XC_pencil);
+  (void) XCheckDefineCursor(display,windows->image.id,cursor);
+  annotate_context=windows->image.annotate_context;
+  (void) XSetFont(display,annotate_context,font_info->fid);
+  (void) XSetBackground(display,annotate_context,
+    windows->pixel_info->pen_colors[box_id].pixel);
+  (void) XSetForeground(display,annotate_context,
+    windows->pixel_info->pen_colors[pen_id].pixel);
+  /*
+    Begin annotating the image with text.
+  */
+  (void) CloneString(&windows->command.name,"Text");
+  windows->command.data=0;
+  (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
+  state=DefaultState;
+  (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
+  text_event.xexpose.width=(int) font_info->max_bounds.width;
+  text_event.xexpose.height=font_info->max_bounds.ascent+
+    font_info->max_bounds.descent;
+  p=annotate_info->text;
+  do
+  {
+    /*
+      Display text cursor.
+    */
+    *p='\0';
+    (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        (void) XSetBackground(display,annotate_context,
+          windows->pixel_info->background_color.pixel);
+        (void) XSetForeground(display,annotate_context,
+          windows->pixel_info->foreground_color.pixel);
+        id=XCommandWidget(display,windows,AnnotateMenu,&event);
+        (void) XSetBackground(display,annotate_context,
+          windows->pixel_info->pen_colors[box_id].pixel);
+        (void) XSetForeground(display,annotate_context,
+          windows->pixel_info->pen_colors[pen_id].pixel);
+        if (id < 0)
+          continue;
+        switch (TextCommands[id])
+        {
+          case TextHelpCommand:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Annotation",ImageAnnotateHelp);
+            (void) XCheckDefineCursor(display,windows->image.id,cursor);
+            break;
+          }
+          case TextApplyCommand:
+          {
+            /*
+              Finished annotating.
+            */
+            annotate_info->width=(unsigned int) XTextWidth(font_info,
+              annotate_info->text,(int) strlen(annotate_info->text));
+            XRefreshWindow(display,&windows->image,&text_event);
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    /*
+      Erase text cursor.
+    */
+    text_event.xexpose.x=x;
+    text_event.xexpose.y=y-font_info->max_bounds.ascent;
+    (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
+      (unsigned int) text_event.xexpose.width,(unsigned int)
+      text_event.xexpose.height,MagickFalse);
+    XRefreshWindow(display,&windows->image,&text_event);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.window != windows->image.id)
+          break;
+        if (event.xbutton.button == Button2)
+          {
+            /*
+              Request primary selection.
+            */
+            (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
+              windows->image.id,CurrentTime);
+            break;
+          }
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.count == 0)
+          {
+            XAnnotateInfo
+              *text_info;
+
+            /*
+              Refresh Image window.
+            */
+            XRefreshWindow(display,&windows->image,(XEvent *) NULL);
+            text_info=annotate_info;
+            while (text_info != (XAnnotateInfo *) NULL)
+            {
+              if (annotate_info->stencil == ForegroundStencil)
+                (void) XDrawString(display,windows->image.id,annotate_context,
+                  text_info->x,text_info->y,text_info->text,
+                  (int) strlen(text_info->text));
+              else
+                (void) XDrawImageString(display,windows->image.id,
+                  annotate_context,text_info->x,text_info->y,text_info->text,
+                  (int) strlen(text_info->text));
+              text_info=text_info->previous;
+            }
+            (void) XDrawString(display,windows->image.id,annotate_context,
+              x,y,"_",1);
+          }
+        break;
+      }
+      case KeyPress:
+      {
+        int
+          length;
+
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (((event.xkey.state & ControlMask) != 0) ||
+            ((event.xkey.state & Mod1Mask) != 0))
+          state|=ModifierState;
+        if ((state & ModifierState) != 0)
+          switch ((int) key_symbol)
+          {
+            case XK_u:
+            case XK_U:
+            {
+              key_symbol=DeleteCommand;
+              break;
+            }
+            default:
+              break;
+          }
+        switch ((int) key_symbol)
+        {
+          case XK_BackSpace:
+          {
+            /*
+              Erase one character.
+            */
+            if (p == annotate_info->text)
+              {
+                if (annotate_info->previous == (XAnnotateInfo *) NULL)
+                  break;
+                else
+                  {
+                    /*
+                      Go to end of the previous line of text.
+                    */
+                    annotate_info=annotate_info->previous;
+                    p=annotate_info->text;
+                    x=annotate_info->x+annotate_info->width;
+                    y=annotate_info->y;
+                    if (annotate_info->width != 0)
+                      p+=strlen(annotate_info->text);
+                    break;
+                  }
+              }
+            p--;
+            x-=XTextWidth(font_info,p,1);
+            text_event.xexpose.x=x;
+            text_event.xexpose.y=y-font_info->max_bounds.ascent;
+            XRefreshWindow(display,&windows->image,&text_event);
+            break;
+          }
+          case XK_bracketleft:
+          {
+            key_symbol=XK_Escape;
+            break;
+          }
+          case DeleteCommand:
+          {
+            /*
+              Erase the entire line of text.
+            */
+            while (p != annotate_info->text)
+            {
+              p--;
+              x-=XTextWidth(font_info,p,1);
+              text_event.xexpose.x=x;
+              XRefreshWindow(display,&windows->image,&text_event);
+            }
+            break;
+          }
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Finished annotating.
+            */
+            annotate_info->width=(unsigned int) XTextWidth(font_info,
+              annotate_info->text,(int) strlen(annotate_info->text));
+            XRefreshWindow(display,&windows->image,&text_event);
+            state|=ExitState;
+            break;
+          }
+          default:
+          {
+            /*
+              Draw a single character on the Image window.
+            */
+            if ((state & ModifierState) != 0)
+              break;
+            if (*command == '\0')
+              break;
+            *p=(*command);
+            if (annotate_info->stencil == ForegroundStencil)
+              (void) XDrawString(display,windows->image.id,annotate_context,
+                x,y,p,1);
+            else
+              (void) XDrawImageString(display,windows->image.id,
+                annotate_context,x,y,p,1);
+            x+=XTextWidth(font_info,p,1);
+            p++;
+            if ((x+font_info->max_bounds.width) < (int) windows->image.width)
+              break;
+          }
+          case XK_Return:
+          case XK_KP_Enter:
+          {
+            /*
+              Advance to the next line of text.
+            */
+            *p='\0';
+            annotate_info->width=(unsigned int) XTextWidth(font_info,
+              annotate_info->text,(int) strlen(annotate_info->text));
+            if (annotate_info->next != (XAnnotateInfo *) NULL)
+              {
+                /*
+                  Line of text already exists.
+                */
+                annotate_info=annotate_info->next;
+                x=annotate_info->x;
+                y=annotate_info->y;
+                p=annotate_info->text;
+                break;
+              }
+            annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
+              sizeof(*annotate_info->next));
+            if (annotate_info->next == (XAnnotateInfo *) NULL)
+              return(MagickFalse);
+            *annotate_info->next=(*annotate_info);
+            annotate_info->next->previous=annotate_info;
+            annotate_info=annotate_info->next;
+            annotate_info->text=(char *) AcquireQuantumMemory((size_t)
+              windows->image.width/MagickMax((ssize_t)
+              font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
+            if (annotate_info->text == (char *) NULL)
+              return(MagickFalse);
+            annotate_info->y+=annotate_info->height;
+            if (annotate_info->y > (int) windows->image.height)
+              annotate_info->y=(int) annotate_info->height;
+            annotate_info->next=(XAnnotateInfo *) NULL;
+            x=annotate_info->x;
+            y=annotate_info->y;
+            p=annotate_info->text;
+            break;
+          }
+        }
+        break;
+      }
+      case KeyRelease:
+      {
+        /*
+          Respond to a user key release.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        state&=(~ModifierState);
+        break;
+      }
+      case SelectionNotify:
+      {
+        Atom
+          type;
+
+        int
+          format;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        /*
+          Obtain response from primary selection.
+        */
+        if (event.xselection.property == (Atom) None)
+          break;
+        status=XGetWindowProperty(display,event.xselection.requestor,
+          event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
+          &type,&format,&length,&after,&data);
+        if ((status != Success) || (type != XA_STRING) || (format == 32) ||
+            (length == 0))
+          break;
+        /*
+          Annotate Image window with primary selection.
+        */
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          if ((char) data[i] != '\n')
+            {
+              /*
+                Draw a single character on the Image window.
+              */
+              *p=(char) data[i];
+              (void) XDrawString(display,windows->image.id,annotate_context,
+                x,y,p,1);
+              x+=XTextWidth(font_info,p,1);
+              p++;
+              if ((x+font_info->max_bounds.width) < (int) windows->image.width)
+                continue;
+            }
+          /*
+            Advance to the next line of text.
+          */
+          *p='\0';
+          annotate_info->width=(unsigned int) XTextWidth(font_info,
+            annotate_info->text,(int) strlen(annotate_info->text));
+          if (annotate_info->next != (XAnnotateInfo *) NULL)
+            {
+              /*
+                Line of text already exists.
+              */
+              annotate_info=annotate_info->next;
+              x=annotate_info->x;
+              y=annotate_info->y;
+              p=annotate_info->text;
+              continue;
+            }
+          annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
+            sizeof(*annotate_info->next));
+          if (annotate_info->next == (XAnnotateInfo *) NULL)
+            return(MagickFalse);
+          *annotate_info->next=(*annotate_info);
+          annotate_info->next->previous=annotate_info;
+          annotate_info=annotate_info->next;
+          annotate_info->text=(char *) AcquireQuantumMemory((size_t)
+            windows->image.width/MagickMax((ssize_t)
+            font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
+          if (annotate_info->text == (char *) NULL)
+            return(MagickFalse);
+          annotate_info->y+=annotate_info->height;
+          if (annotate_info->y > (int) windows->image.height)
+            annotate_info->y=(int) annotate_info->height;
+          annotate_info->next=(XAnnotateInfo *) NULL;
+          x=annotate_info->x;
+          y=annotate_info->y;
+          p=annotate_info->text;
+        }
+        (void) XFree((void *) data);
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  (void) XFreeCursor(display,cursor);
+  /*
+    Annotation is relative to image configuration.
+  */
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  /*
+    Initialize annotated image.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  while (annotate_info != (XAnnotateInfo *) NULL)
+  {
+    if (annotate_info->width == 0)
+      {
+        /*
+          No text on this line--  go to the next line of text.
+        */
+        previous_info=annotate_info->previous;
+        annotate_info->text=(char *)
+          RelinquishMagickMemory(annotate_info->text);
+        annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
+        annotate_info=previous_info;
+        continue;
+      }
+    /*
+      Determine pixel index for box and pen color.
+    */
+    windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
+    if (windows->pixel_info->colors != 0)
+      for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
+        if (windows->pixel_info->pixels[i] ==
+            windows->pixel_info->pen_colors[box_id].pixel)
+          {
+            windows->pixel_info->box_index=(unsigned short) i;
+            break;
+          }
+    windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
+    if (windows->pixel_info->colors != 0)
+      for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
+        if (windows->pixel_info->pixels[i] ==
+            windows->pixel_info->pen_colors[pen_id].pixel)
+          {
+            windows->pixel_info->pen_index=(unsigned short) i;
+            break;
+          }
+    /*
+      Define the annotate geometry string.
+    */
+    annotate_info->x=(int)
+      width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
+    annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
+      windows->image.y)/windows->image.ximage->height;
+    (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
+      "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
+      height*annotate_info->height/windows->image.ximage->height,
+      annotate_info->x+x,annotate_info->y+y);
+    /*
+      Annotate image with text.
+    */
+    status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
+    if (status == 0)
+      return(MagickFalse);
+    /*
+      Free up memory.
+    */
+    previous_info=annotate_info->previous;
+    annotate_info->text=DestroyString(annotate_info->text);
+    annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
+    annotate_info=previous_info;
+  }
+  (void) XSetForeground(display,annotate_context,
+    windows->pixel_info->foreground_color.pixel);
+  (void) XSetBackground(display,annotate_context,
+    windows->pixel_info->background_color.pixel);
+  (void) XSetFont(display,annotate_context,windows->font_info->fid);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XFreeFont(display,font_info);
+  /*
+    Update image configuration.
+  */
+  XConfigureImageColormap(display,resource_info,windows,image);
+  (void) XConfigureImage(display,resource_info,windows,image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X B a c k g r o u n d I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XBackgroundImage() displays the image in the background of a window.
+%
+%  The format of the XBackgroundImage method is:
+%
+%      MagickBooleanType XBackgroundImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XBackgroundImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image **image)
+{
+#define BackgroundImageTag  "Background/Image"
+
+  int
+    status;
+
+  static char
+    window_id[MaxTextExtent] = "root";
+
+  XResourceInfo
+    background_resources;
+
+  /*
+    Put image in background.
+  */
+  status=XDialogWidget(display,windows,"Background",
+    "Enter window id (id 0x00 selects window with pointer):",window_id);
+  if (*window_id == '\0')
+    return(MagickFalse);
+  (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+  XInfoWidget(display,windows,BackgroundImageTag);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  background_resources=(*resource_info);
+  background_resources.window_id=window_id;
+  background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
+  status=XDisplayBackgroundImage(display,&background_resources,*image);
+  if (status != MagickFalse)
+    XClientMessage(display,windows->image.id,windows->im_protocols,
+      windows->im_retain_colors,CurrentTime);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C h o p I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XChopImage() chops the X image.
+%
+%  The format of the XChopImage method is:
+%
+%    MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
+%      XWindows *windows,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XChopImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image **image)
+{
+  static const char
+    *ChopMenu[] =
+    {
+      "Direction",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static ModeType
+    direction = HorizontalChopCommand;
+
+  static const ModeType
+    ChopCommands[] =
+    {
+      ChopDirectionCommand,
+      ChopHelpCommand,
+      ChopDismissCommand
+    },
+    DirectionCommands[] =
+    {
+      HorizontalChopCommand,
+      VerticalChopCommand
+    };
+
+  char
+    text[MaxTextExtent];
+
+  Image
+    *chop_image;
+
+  int
+    id,
+    x,
+    y;
+
+  MagickRealType
+    scale_factor;
+
+  RectangleInfo
+    chop_info;
+
+  unsigned int
+    distance,
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  XSegment
+    segment_info;
+
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Chop");
+  windows->command.data=1;
+  (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
+          x+windows->image.x,y+windows->image.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,ChopMenu,&event);
+        if (id < 0)
+          continue;
+        switch (ChopCommands[id])
+        {
+          case ChopDirectionCommand:
+          {
+            char
+              command[MaxTextExtent];
+
+            static const char
+              *Directions[] =
+              {
+                "horizontal",
+                "vertical",
+                (char *) NULL,
+              };
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
+            if (id >= 0)
+              direction=DirectionCommands[id];
+            break;
+          }
+          case ChopHelpCommand:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Chop",ImageChopHelp);
+            break;
+          }
+          case ChopDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        /*
+          User has committed to start point of chopping line.
+        */
+        segment_info.x1=(short int) event.xbutton.x;
+        segment_info.x2=(short int) event.xbutton.x;
+        segment_info.y1=(short int) event.xbutton.y;
+        segment_info.y2=(short int) event.xbutton.y;
+        state|=ExitState;
+        break;
+      }
+      case ButtonRelease:
+        break;
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        char
+          command[MaxTextExtent];
+
+        KeySym
+          key_symbol;
+
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Chop",ImageChopHelp);
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as text cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+      }
+    }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  if ((state & EscapeState) != 0)
+    return(MagickTrue);
+  /*
+    Draw line as pointer moves until the mouse button is released.
+  */
+  chop_info.width=0;
+  chop_info.height=0;
+  chop_info.x=0;
+  chop_info.y=0;
+  distance=0;
+  (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+  state=DefaultState;
+  do
+  {
+    if (distance > 9)
+      {
+        /*
+          Display info and draw chopping line.
+        */
+        if (windows->info.mapped == MagickFalse)
+          (void) XMapWindow(display,windows->info.id);
+        (void) FormatLocaleString(text,MaxTextExtent,
+          " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
+          chop_info.height,(double) chop_info.x,(double) chop_info.y);
+        XInfoWidget(display,windows,text);
+        XHighlightLine(display,windows->image.id,
+          windows->image.highlight_context,&segment_info);
+      }
+    else
+      if (windows->info.mapped != MagickFalse)
+        (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (distance > 9)
+      XHighlightLine(display,windows->image.id,
+        windows->image.highlight_context,&segment_info);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        segment_info.x2=(short int) event.xmotion.x;
+        segment_info.y2=(short int) event.xmotion.y;
+        break;
+      }
+      case ButtonRelease:
+      {
+        /*
+          User has committed to chopping line.
+        */
+        segment_info.x2=(short int) event.xbutton.x;
+        segment_info.y2=(short int) event.xbutton.y;
+        state|=ExitState;
+        break;
+      }
+      case Expose:
+        break;
+      case MotionNotify:
+      {
+        segment_info.x2=(short int) event.xmotion.x;
+        segment_info.y2=(short int) event.xmotion.y;
+      }
+      default:
+        break;
+    }
+    /*
+      Check boundary conditions.
+    */
+    if (segment_info.x2 < 0)
+      segment_info.x2=0;
+    else
+      if (segment_info.x2 > windows->image.ximage->width)
+        segment_info.x2=windows->image.ximage->width;
+    if (segment_info.y2 < 0)
+      segment_info.y2=0;
+    else
+      if (segment_info.y2 > windows->image.ximage->height)
+        segment_info.y2=windows->image.ximage->height;
+    distance=(unsigned int)
+      (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
+       ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
+    /*
+      Compute chopping geometry.
+    */
+    if (direction == HorizontalChopCommand)
+      {
+        chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
+        chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
+        chop_info.height=0;
+        chop_info.y=0;
+        if (segment_info.x1 > (int) segment_info.x2)
+          {
+            chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
+            chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
+          }
+      }
+    else
+      {
+        chop_info.width=0;
+        chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
+        chop_info.x=0;
+        chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
+        if (segment_info.y1 > segment_info.y2)
+          {
+            chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
+            chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
+          }
+      }
+  } while ((state & ExitState) == 0);
+  (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  if (distance <= 9)
+    return(MagickTrue);
+  /*
+    Image chopping is relative to image configuration.
+  */
+  (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  windows->image.window_changes.width=windows->image.ximage->width-
+    (unsigned int) chop_info.width;
+  windows->image.window_changes.height=windows->image.ximage->height-
+    (unsigned int) chop_info.height;
+  width=(unsigned int) (*image)->columns;
+  height=(unsigned int) (*image)->rows;
+  x=0;
+  y=0;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  scale_factor=(MagickRealType) width/windows->image.ximage->width;
+  chop_info.x+=x;
+  chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
+  chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
+  scale_factor=(MagickRealType) height/windows->image.ximage->height;
+  chop_info.y+=y;
+  chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
+  chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
+  /*
+    Chop image.
+  */
+  chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
+  XSetCursorState(display,windows,MagickFalse);
+  if (chop_image == (Image *) NULL)
+    return(MagickFalse);
+  *image=DestroyImage(*image);
+  *image=chop_image;
+  /*
+    Update image configuration.
+  */
+  XConfigureImageColormap(display,resource_info,windows,*image);
+  (void) XConfigureImage(display,resource_info,windows,*image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C o l o r E d i t I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XColorEditImage() allows the user to interactively change the color of one
+%  pixel for a DirectColor image or one colormap entry for a PseudoClass image.
+%
+%  The format of the XColorEditImage method is:
+%
+%      MagickBooleanType XColorEditImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+*/
+
+
+static MagickBooleanType XColorEditImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image **image)
+{
+  static const char
+    *ColorEditMenu[] =
+    {
+      "Method",
+      "Pixel Color",
+      "Border Color",
+      "Fuzz",
+      "Undo",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static const ModeType
+    ColorEditCommands[] =
+    {
+      ColorEditMethodCommand,
+      ColorEditColorCommand,
+      ColorEditBorderCommand,
+      ColorEditFuzzCommand,
+      ColorEditUndoCommand,
+      ColorEditHelpCommand,
+      ColorEditDismissCommand
+    };
+
+  static PaintMethod
+    method = PointMethod;
+
+  static unsigned int
+    pen_id = 0;
+
+  static XColor
+    border_color = { 0, 0, 0, 0, 0, 0 };
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  ExceptionInfo
+    *exception;
+
+  int
+    entry,
+    id,
+    x,
+    x_offset,
+    y,
+    y_offset;
+
+  register Quantum
+    *q;
+
+  register ssize_t
+    i;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XColor
+    color;
+
+  XEvent
+    event;
+
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Color Edit");
+  windows->command.data=4;
+  (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Make cursor.
+  */
+  cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
+    resource_info->background_color,resource_info->foreground_color);
+  (void) XCheckDefineCursor(display,windows->image.id,cursor);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
+          x+windows->image.x,y+windows->image.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,ColorEditMenu,&event);
+        if (id < 0)
+          {
+            (void) XCheckDefineCursor(display,windows->image.id,cursor);
+            continue;
+          }
+        switch (ColorEditCommands[id])
+        {
+          case ColorEditMethodCommand:
+          {
+            char
+              **methods;
+
+            /*
+              Select a method from the pop-up menu.
+            */
+            methods=(char **) GetCommandOptions(MagickMethodOptions);
+            if (methods == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,ColorEditMenu[id],
+              (const char **) methods,command);
+            if (entry >= 0)
+              method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
+                MagickFalse,methods[entry]);
+            methods=DestroyStringList(methods);
+            break;
+          }
+          case ColorEditColorCommand:
+          {
+            const char
+              *ColorMenu[MaxNumberPens];
+
+            int
+              pen_number;
+
+            /*
+              Initialize menu selections.
+            */
+            for (i=0; i < (int) (MaxNumberPens-2); i++)
+              ColorMenu[i]=resource_info->pen_colors[i];
+            ColorMenu[MaxNumberPens-2]="Browser...";
+            ColorMenu[MaxNumberPens-1]=(const char *) NULL;
+            /*
+              Select a pen color from the pop-up menu.
+            */
+            pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
+              (const char **) ColorMenu,command);
+            if (pen_number < 0)
+              break;
+            if (pen_number == (MaxNumberPens-2))
+              {
+                static char
+                  color_name[MaxTextExtent] = "gray";
+
+                /*
+                  Select a pen color from a dialog.
+                */
+                resource_info->pen_colors[pen_number]=color_name;
+                XColorBrowserWidget(display,windows,"Select",color_name);
+                if (*color_name == '\0')
+                  break;
+              }
+            /*
+              Set pen color.
+            */
+            (void) XParseColor(display,windows->map_info->colormap,
+              resource_info->pen_colors[pen_number],&color);
+            XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
+              (unsigned int) MaxColors,&color);
+            windows->pixel_info->pen_colors[pen_number]=color;
+            pen_id=(unsigned int) pen_number;
+            break;
+          }
+          case ColorEditBorderCommand:
+          {
+            const char
+              *ColorMenu[MaxNumberPens];
+
+            int
+              pen_number;
+
+            /*
+              Initialize menu selections.
+            */
+            for (i=0; i < (int) (MaxNumberPens-2); i++)
+              ColorMenu[i]=resource_info->pen_colors[i];
+            ColorMenu[MaxNumberPens-2]="Browser...";
+            ColorMenu[MaxNumberPens-1]=(const char *) NULL;
+            /*
+              Select a pen color from the pop-up menu.
+            */
+            pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
+              (const char **) ColorMenu,command);
+            if (pen_number < 0)
+              break;
+            if (pen_number == (MaxNumberPens-2))
+              {
+                static char
+                  color_name[MaxTextExtent] = "gray";
+
+                /*
+                  Select a pen color from a dialog.
+                */
+                resource_info->pen_colors[pen_number]=color_name;
+                XColorBrowserWidget(display,windows,"Select",color_name);
+                if (*color_name == '\0')
+                  break;
+              }
+            /*
+              Set border color.
+            */
+            (void) XParseColor(display,windows->map_info->colormap,
+              resource_info->pen_colors[pen_number],&border_color);
+            break;
+          }
+          case ColorEditFuzzCommand:
+          {
+            static char
+              fuzz[MaxTextExtent];
+
+            static const char
+              *FuzzMenu[] =
+              {
+                "0%",
+                "2%",
+                "5%",
+                "10%",
+                "15%",
+                "Dialog...",
+                (char *) NULL,
+              };
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
+              command);
+            if (entry < 0)
+              break;
+            if (entry != 5)
+              {
+                (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
+                  QuantumRange+1.0);
+                break;
+              }
+            (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
+            (void) XDialogWidget(display,windows,"Ok",
+              "Enter fuzz factor (0.0 - 99.9%):",fuzz);
+            if (*fuzz == '\0')
+              break;
+            (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
+            (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
+            break;
+          }
+          case ColorEditUndoCommand:
+          {
+            (void) XMagickCommand(display,resource_info,windows,UndoCommand,
+              image);
+            break;
+          }
+          case ColorEditHelpCommand:
+          default:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Annotation",ImageColorEditHelp);
+            break;
+          }
+          case ColorEditDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+        }
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if ((event.xbutton.window != windows->image.id) &&
+            (event.xbutton.window != windows->magnify.id))
+          break;
+        /*
+          exit loop.
+        */
+        x=event.xbutton.x;
+        y=event.xbutton.y;
+        (void) XMagickCommand(display,resource_info,windows,
+          SaveToUndoBufferCommand,image);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if ((event.xbutton.window != windows->image.id) &&
+            (event.xbutton.window != windows->magnify.id))
+          break;
+        /*
+          Update colormap information.
+        */
+        x=event.xbutton.x;
+        y=event.xbutton.y;
+        XConfigureImageColormap(display,resource_info,windows,*image);
+        (void) XConfigureImage(display,resource_info,windows,*image);
+        XInfoWidget(display,windows,text);
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        state&=(~UpdateConfigurationState);
+        break;
+      }
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        KeySym
+          key_symbol;
+
+        if (event.xkey.window == windows->magnify.id)
+          {
+            Window
+              window;
+
+            window=windows->magnify.id;
+            while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
+          }
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Annotation",ImageColorEditHelp);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        break;
+      }
+      default:
+        break;
+    }
+    if (event.xany.window == windows->magnify.id)
+      {
+        x=windows->magnify.x-windows->image.x;
+        y=windows->magnify.y-windows->image.y;
+      }
+    x_offset=x;
+    y_offset=y;
+    if ((state & UpdateConfigurationState) != 0)
+      {
+        CacheView
+          *image_view;
+
+        int
+          x,
+          y;
+
+        /*
+          Pixel edit is relative to image configuration.
+        */
+        (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
+          MagickTrue);
+        color=windows->pixel_info->pen_colors[pen_id];
+        XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
+        width=(unsigned int) (*image)->columns;
+        height=(unsigned int) (*image)->rows;
+        x=0;
+        y=0;
+        if (windows->image.crop_geometry != (char *) NULL)
+          (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
+            &width,&height);
+        x_offset=(int)
+          (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
+        y_offset=(int)
+          (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
+        if ((x_offset < 0) || (y_offset < 0))
+          continue;
+        if ((x_offset >= (int) (*image)->columns) ||
+            (y_offset >= (int) (*image)->rows))
+          continue;
+        exception=(&(*image)->exception);
+        image_view=AcquireCacheView(*image);
+        switch (method)
+        {
+          case PointMethod:
+          default:
+          {
+            /*
+              Update color information using point algorithm.
+            */
+            if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
+              return(MagickFalse);
+            q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
+              (ssize_t)y_offset,1,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
+            SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
+            SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
+            (void) SyncCacheViewAuthenticPixels(image_view,
+              &(*image)->exception);
+            break;
+          }
+          case ReplaceMethod:
+          {
+            PixelPacket
+              pixel,
+              target;
+
+            /*
+              Update color information using replace algorithm.
+            */
+            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
+              (ssize_t) y_offset,&target,&(*image)->exception);
+            if ((*image)->storage_class == DirectClass)
+              {
+                for (y=0; y < (int) (*image)->rows; y++)
+                {
+                  q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
+                    (*image)->columns,1,exception);
+                  if (q == (Quantum *) NULL)
+                    break;
+                  for (x=0; x < (int) (*image)->columns; x++)
+                  {
+                    GetPixelPacket(*image,q,&pixel);
+                    if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target))
+                      {
+                        SetPixelRed(*image,ScaleShortToQuantum(
+                          color.red),q);
+                        SetPixelGreen(*image,ScaleShortToQuantum(
+                          color.green),q);
+                        SetPixelBlue(*image,ScaleShortToQuantum(
+                          color.blue),q);
+                      }
+                    q+=GetPixelChannels(*image);
+                  }
+                  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+                    break;
+                }
+              }
+            else
+              {
+                for (i=0; i < (ssize_t) (*image)->colors; i++)
+                  if (IsFuzzyEquivalencePixelPacket(*image,(*image)->colormap+i,&target))
+                    {
+                      (*image)->colormap[i].red=ScaleShortToQuantum(
+                        color.red);
+                      (*image)->colormap[i].green=ScaleShortToQuantum(
+                        color.green);
+                      (*image)->colormap[i].blue=ScaleShortToQuantum(
+                        color.blue);
+                    }
+                (void) SyncImage(*image);
+              }
+            break;
+          }
+          case FloodfillMethod:
+          case FillToBorderMethod:
+          {
+            DrawInfo
+              *draw_info;
+
+            PixelInfo
+              target;
+
+            /*
+              Update color information using floodfill algorithm.
+            */
+            (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
+              (ssize_t) y_offset,&target,exception);
+            if (method == FillToBorderMethod)
+              {
+                target.red=(MagickRealType)
+                  ScaleShortToQuantum(border_color.red);
+                target.green=(MagickRealType)
+                  ScaleShortToQuantum(border_color.green);
+                target.blue=(MagickRealType)
+                  ScaleShortToQuantum(border_color.blue);
+              }
+            draw_info=CloneDrawInfo(resource_info->image_info,
+              (DrawInfo *) NULL);
+            (void) QueryColorDatabase(resource_info->pen_colors[pen_id],
+              &draw_info->fill,exception);
+            (void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
+              (ssize_t) x_offset,(ssize_t) y_offset,
+              method == FloodfillMethod ? MagickFalse : MagickTrue);
+            draw_info=DestroyDrawInfo(draw_info);
+            break;
+          }
+          case ResetMethod:
+          {
+            /*
+              Update color information using reset algorithm.
+            */
+            if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
+              return(MagickFalse);
+            for (y=0; y < (int) (*image)->rows; y++)
+            {
+              q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
+                (*image)->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (int) (*image)->columns; x++)
+              {
+                SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
+                SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
+                SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
+                q+=GetPixelChannels(*image);
+              }
+              if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+                break;
+            }
+            break;
+          }
+        }
+        image_view=DestroyCacheView(image_view);
+        state&=(~UpdateConfigurationState);
+      }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XFreeCursor(display,cursor);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C o m p o s i t e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XCompositeImage() requests an image name from the user, reads the image and
+%  composites it with the X window image at a location the user chooses with
+%  the pointer.
+%
+%  The format of the XCompositeImage method is:
+%
+%      MagickBooleanType XCompositeImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+*/
+static MagickBooleanType XCompositeImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  static char
+    displacement_geometry[MaxTextExtent] = "30x30",
+    filename[MaxTextExtent] = "\0";
+
+  static const char
+    *CompositeMenu[] =
+    {
+      "Operators",
+      "Dissolve",
+      "Displace",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static CompositeOperator
+    compose = CopyCompositeOp;
+
+  static const ModeType
+    CompositeCommands[] =
+    {
+      CompositeOperatorsCommand,
+      CompositeDissolveCommand,
+      CompositeDisplaceCommand,
+      CompositeHelpCommand,
+      CompositeDismissCommand
+    };
+
+  char
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  Image
+    *composite_image;
+
+  int
+    entry,
+    id,
+    x,
+    y;
+
+  MagickRealType
+    blend,
+    scale_factor;
+
+  RectangleInfo
+    highlight_info,
+    composite_info;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  /*
+    Request image file name from user.
+  */
+  XFileBrowserWidget(display,windows,"Composite",filename);
+  if (*filename == '\0')
+    return(MagickTrue);
+  /*
+    Read image.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  (void) CopyMagickString(resource_info->image_info->filename,filename,
+    MaxTextExtent);
+  composite_image=ReadImage(resource_info->image_info,&image->exception);
+  CatchException(&image->exception);
+  XSetCursorState(display,windows,MagickFalse);
+  if (composite_image == (Image *) NULL)
+    return(MagickFalse);
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Composite");
+  windows->command.data=1;
+  (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  composite_info.x=(ssize_t) windows->image.x+x;
+  composite_info.y=(ssize_t) windows->image.y+y;
+  composite_info.width=0;
+  composite_info.height=0;
+  cursor=XCreateFontCursor(display,XC_ul_angle);
+  (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+  blend=0.0;
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
+          (long) composite_info.x,(long) composite_info.y);
+        XInfoWidget(display,windows,text);
+      }
+    highlight_info=composite_info;
+    highlight_info.x=composite_info.x-windows->image.x;
+    highlight_info.y=composite_info.y-windows->image.y;
+    XHighlightRectangle(display,windows->image.id,
+      windows->image.highlight_context,&highlight_info);
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    XHighlightRectangle(display,windows->image.id,
+      windows->image.highlight_context,&highlight_info);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,CompositeMenu,&event);
+        if (id < 0)
+          continue;
+        switch (CompositeCommands[id])
+        {
+          case CompositeOperatorsCommand:
+          {
+            char
+              command[MaxTextExtent],
+              **operators;
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            operators=GetCommandOptions(MagickComposeOptions);
+            if (operators == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,CompositeMenu[id],
+              (const char **) operators,command);
+            if (entry >= 0)
+              compose=(CompositeOperator) ParseCommandOption(
+                MagickComposeOptions,MagickFalse,operators[entry]);
+            operators=DestroyStringList(operators);
+            break;
+          }
+          case CompositeDissolveCommand:
+          {
+            static char
+              factor[MaxTextExtent] = "20.0";
+
+            /*
+              Dissolve the two images a given percent.
+            */
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            (void) XDialogWidget(display,windows,"Dissolve",
+              "Enter the blend factor (0.0 - 99.9%):",factor);
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            if (*factor == '\0')
+              break;
+            blend=InterpretLocaleValue(factor,(char **) NULL);
+            compose=DissolveCompositeOp;
+            break;
+          }
+          case CompositeDisplaceCommand:
+          {
+            /*
+              Get horizontal and vertical scale displacement geometry.
+            */
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            (void) XDialogWidget(display,windows,"Displace",
+              "Enter the horizontal and vertical scale:",displacement_geometry);
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            if (*displacement_geometry == '\0')
+              break;
+            compose=DisplaceCompositeOp;
+            break;
+          }
+          case CompositeHelpCommand:
+          {
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Composite",ImageCompositeHelp);
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            break;
+          }
+          case CompositeDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        /*
+          Change cursor.
+        */
+        composite_info.width=composite_image->columns;
+        composite_info.height=composite_image->rows;
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+        composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        if ((composite_info.width != 0) && (composite_info.height != 0))
+          {
+            /*
+              User has selected the location of the composite image.
+            */
+            composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+            composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+            state|=ExitState;
+          }
+        break;
+      }
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        char
+          command[MaxTextExtent];
+
+        KeySym
+          key_symbol;
+
+        int
+          length;
+
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            composite_image=DestroyImage(composite_image);
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Composite",ImageCompositeHelp);
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as text cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        composite_info.x=(ssize_t) windows->image.x+x;
+        composite_info.y=(ssize_t) windows->image.y+y;
+        break;
+      }
+      default:
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
+            event.type);
+        break;
+      }
+    }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XFreeCursor(display,cursor);
+  if ((state & EscapeState) != 0)
+    return(MagickTrue);
+  /*
+    Image compositing is relative to image configuration.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  scale_factor=(MagickRealType) width/windows->image.ximage->width;
+  composite_info.x+=x;
+  composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
+  composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
+  scale_factor=(MagickRealType) height/windows->image.ximage->height;
+  composite_info.y+=y;
+  composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
+  composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
+  if ((composite_info.width != composite_image->columns) ||
+      (composite_info.height != composite_image->rows))
+    {
+      Image
+        *resize_image;
+
+      /*
+        Scale composite image.
+      */
+      resize_image=ResizeImage(composite_image,composite_info.width,
+        composite_info.height,composite_image->filter,composite_image->blur,
+        &image->exception);
+      composite_image=DestroyImage(composite_image);
+      if (resize_image == (Image *) NULL)
+        {
+          XSetCursorState(display,windows,MagickFalse);
+          return(MagickFalse);
+        }
+      composite_image=resize_image;
+    }
+  if (compose == DisplaceCompositeOp)
+    (void) SetImageArtifact(composite_image,"compose:args",
+      displacement_geometry);
+  if (blend != 0.0)
+    {
+      CacheView
+        *image_view;
+
+      ExceptionInfo
+        *exception;
+
+      int
+        y;
+
+      Quantum
+        opacity;
+
+      register int
+        x;
+
+      register Quantum
+        *q;
+
+      /*
+        Create mattes for blending.
+      */
+      (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
+      opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)-
+        ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100);
+      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+        return(MagickFalse);
+      image->matte=MagickTrue;
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+      for (y=0; y < (int) image->rows; y++)
+      {
+        q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
+          exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (int) image->columns; x++)
+        {
+          SetPixelAlpha(image,opacity,q);
+          q+=GetPixelChannels(image);
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          break;
+      }
+      image_view=DestroyCacheView(image_view);
+    }
+  /*
+    Composite image with X Image window.
+  */
+  (void) CompositeImage(image,compose,composite_image,composite_info.x,
+    composite_info.y);
+  composite_image=DestroyImage(composite_image);
+  XSetCursorState(display,windows,MagickFalse);
+  /*
+    Update image configuration.
+  */
+  XConfigureImageColormap(display,resource_info,windows,image);
+  (void) XConfigureImage(display,resource_info,windows,image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C o n f i g u r e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XConfigureImage() creates a new X image.  It also notifies the window
+%  manager of the new image size and configures the transient widows.
+%
+%  The format of the XConfigureImage method is:
+%
+%      MagickBooleanType XConfigureImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+%
+*/
+static MagickBooleanType XConfigureImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  char
+    geometry[MaxTextExtent];
+
+  MagickStatusType
+    status;
+
+  size_t
+    mask,
+    height,
+    width;
+
+  ssize_t
+    x,
+    y;
+
+  XSizeHints
+    *size_hints;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Dismiss if window dimensions are zero.
+  */
+  width=(unsigned int) windows->image.window_changes.width;
+  height=(unsigned int) windows->image.window_changes.height;
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
+      windows->image.ximage->height,(double) width,(double) height);
+  if ((width*height) == 0)
+    return(MagickTrue);
+  x=0;
+  y=0;
+  /*
+    Resize image to fit Image window dimensions.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  (void) XFlush(display);
+  if (((int) width != windows->image.ximage->width) ||
+      ((int) height != windows->image.ximage->height))
+    image->taint=MagickTrue;
+  windows->magnify.x=(int)
+    width*windows->magnify.x/windows->image.ximage->width;
+  windows->magnify.y=(int)
+    height*windows->magnify.y/windows->image.ximage->height;
+  windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
+  windows->image.y=(int)
+    (height*windows->image.y/windows->image.ximage->height);
+  status=XMakeImage(display,resource_info,&windows->image,image,
+    (unsigned int) width,(unsigned int) height);
+  if (status == MagickFalse)
+    XNoticeWidget(display,windows,"Unable to configure X image:",
+      windows->image.name);
+  /*
+    Notify window manager of the new configuration.
+  */
+  if (resource_info->image_geometry != (char *) NULL)
+    (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
+      resource_info->image_geometry);
+  else
+    (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
+      XDisplayWidth(display,windows->image.screen),
+      XDisplayHeight(display,windows->image.screen));
+  (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
+  window_changes.width=(int) width;
+  if (window_changes.width > XDisplayWidth(display,windows->image.screen))
+    window_changes.width=XDisplayWidth(display,windows->image.screen);
+  window_changes.height=(int) height;
+  if (window_changes.height > XDisplayHeight(display,windows->image.screen))
+    window_changes.height=XDisplayHeight(display,windows->image.screen);
+  mask=(size_t) (CWWidth | CWHeight);
+  if (resource_info->backdrop)
+    {
+      mask|=CWX | CWY;
+      window_changes.x=(int)
+        ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
+      window_changes.y=(int)
+        ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
+    }
+  (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
+    (unsigned int) mask,&window_changes);
+  (void) XClearWindow(display,windows->image.id);
+  XRefreshWindow(display,&windows->image,(XEvent *) NULL);
+  /*
+    Update Magnify window configuration.
+  */
+  if (windows->magnify.mapped != MagickFalse)
+    XMakeMagnifyImage(display,windows);
+  windows->pan.crop_geometry=windows->image.crop_geometry;
+  XBestIconSize(display,&windows->pan,image);
+  while (((windows->pan.width << 1) < MaxIconSize) &&
+         ((windows->pan.height << 1) < MaxIconSize))
+  {
+    windows->pan.width<<=1;
+    windows->pan.height<<=1;
+  }
+  if (windows->pan.geometry != (char *) NULL)
+    (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
+      &windows->pan.width,&windows->pan.height);
+  window_changes.width=(int) windows->pan.width;
+  window_changes.height=(int) windows->pan.height;
+  size_hints=XAllocSizeHints();
+  if (size_hints != (XSizeHints *) NULL)
+    {
+      /*
+        Set new size hints.
+      */
+      size_hints->flags=PSize | PMinSize | PMaxSize;
+      size_hints->width=window_changes.width;
+      size_hints->height=window_changes.height;
+      size_hints->min_width=size_hints->width;
+      size_hints->min_height=size_hints->height;
+      size_hints->max_width=size_hints->width;
+      size_hints->max_height=size_hints->height;
+      (void) XSetNormalHints(display,windows->pan.id,size_hints);
+      (void) XFree((void *) size_hints);
+    }
+  (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
+    (unsigned int) (CWWidth | CWHeight),&window_changes);
+  /*
+    Update icon window configuration.
+  */
+  windows->icon.crop_geometry=windows->image.crop_geometry;
+  XBestIconSize(display,&windows->icon,image);
+  window_changes.width=(int) windows->icon.width;
+  window_changes.height=(int) windows->icon.height;
+  (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
+    (unsigned int) (CWWidth | CWHeight),&window_changes);
+  XSetCursorState(display,windows,MagickFalse);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C r o p I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XCropImage() allows the user to select a region of the image and crop, copy,
+%  or cut it.  For copy or cut, the image can subsequently be composited onto
+%  the image with XPasteImage.
+%
+%  The format of the XCropImage method is:
+%
+%      MagickBooleanType XCropImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image,
+%        const ClipboardMode mode)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+%    o mode: This unsigned value specified whether the image should be
+%      cropped, copied, or cut.
+%
+*/
+static MagickBooleanType XCropImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image,
+  const ClipboardMode mode)
+{
+  static const char
+    *CropModeMenu[] =
+    {
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    },
+    *RectifyModeMenu[] =
+    {
+      "Crop",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static const ModeType
+    CropCommands[] =
+    {
+      CropHelpCommand,
+      CropDismissCommand
+    },
+    RectifyCommands[] =
+    {
+      RectifyCopyCommand,
+      RectifyHelpCommand,
+      RectifyDismissCommand
+    };
+
+  CacheView
+    *image_view;
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  ExceptionInfo
+    *exception;
+
+  int
+    id,
+    x,
+    y;
+
+  KeySym
+    key_symbol;
+
+  Image
+    *crop_image;
+
+  MagickRealType
+    scale_factor;
+
+  RectangleInfo
+    crop_info,
+    highlight_info;
+
+  register Quantum
+    *q;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  /*
+    Map Command widget.
+  */
+  switch (mode)
+  {
+    case CopyMode:
+    {
+      (void) CloneString(&windows->command.name,"Copy");
+      break;
+    }
+    case CropMode:
+    {
+      (void) CloneString(&windows->command.name,"Crop");
+      break;
+    }
+    case CutMode:
+    {
+      (void) CloneString(&windows->command.name,"Cut");
+      break;
+    }
+  }
+  RectifyModeMenu[0]=windows->command.name;
+  windows->command.data=0;
+  (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  crop_info.x=(ssize_t) windows->image.x+x;
+  crop_info.y=(ssize_t) windows->image.y+y;
+  crop_info.width=0;
+  crop_info.height=0;
+  cursor=XCreateFontCursor(display,XC_fleur);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
+          (long) crop_info.x,(long) crop_info.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,CropModeMenu,&event);
+        if (id < 0)
+          continue;
+        switch (CropCommands[id])
+        {
+          case CropHelpCommand:
+          {
+            switch (mode)
+            {
+              case CopyMode:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Copy",ImageCopyHelp);
+                break;
+              }
+              case CropMode:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Crop",ImageCropHelp);
+                break;
+              }
+              case CutMode:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Cut",ImageCutHelp);
+                break;
+              }
+            }
+            break;
+          }
+          case CropDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        /*
+          Note first corner of cropping rectangle-- exit loop.
+        */
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+        crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+        state|=ExitState;
+        break;
+      }
+      case ButtonRelease:
+        break;
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            switch (mode)
+            {
+              case CopyMode:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Copy",ImageCopyHelp);
+                break;
+              }
+              case CropMode:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Crop",ImageCropHelp);
+                break;
+              }
+              case CutMode:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Cut",ImageCutHelp);
+                break;
+              }
+            }
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        if (event.xmotion.window != windows->image.id)
+          break;
+        /*
+          Map and unmap Info widget as text cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        crop_info.x=(ssize_t) windows->image.x+x;
+        crop_info.y=(ssize_t) windows->image.y+y;
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  if ((state & EscapeState) != 0)
+    {
+      /*
+        User want to exit without cropping.
+      */
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      (void) XFreeCursor(display,cursor);
+      return(MagickTrue);
+    }
+  (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+  do
+  {
+    /*
+      Size rectangle as pointer moves until the mouse button is released.
+    */
+    x=(int) crop_info.x;
+    y=(int) crop_info.y;
+    crop_info.width=0;
+    crop_info.height=0;
+    state=DefaultState;
+    do
+    {
+      highlight_info=crop_info;
+      highlight_info.x=crop_info.x-windows->image.x;
+      highlight_info.y=crop_info.y-windows->image.y;
+      if ((highlight_info.width > 3) && (highlight_info.height > 3))
+        {
+          /*
+            Display info and draw cropping rectangle.
+          */
+          if (windows->info.mapped == MagickFalse)
+            (void) XMapWindow(display,windows->info.id);
+          (void) FormatLocaleString(text,MaxTextExtent,
+            " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
+            crop_info.height,(double) crop_info.x,(double) crop_info.y);
+          XInfoWidget(display,windows,text);
+          XHighlightRectangle(display,windows->image.id,
+            windows->image.highlight_context,&highlight_info);
+        }
+      else
+        if (windows->info.mapped != MagickFalse)
+          (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      /*
+        Wait for next event.
+      */
+      XScreenEvent(display,windows,&event);
+      if ((highlight_info.width > 3) && (highlight_info.height > 3))
+        XHighlightRectangle(display,windows->image.id,
+          windows->image.highlight_context,&highlight_info);
+      switch (event.type)
+      {
+        case ButtonPress:
+        {
+          crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+          crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+          break;
+        }
+        case ButtonRelease:
+        {
+          /*
+            User has committed to cropping rectangle.
+          */
+          crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+          crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+          XSetCursorState(display,windows,MagickFalse);
+          state|=ExitState;
+          windows->command.data=0;
+          (void) XCommandWidget(display,windows,RectifyModeMenu,
+            (XEvent *) NULL);
+          break;
+        }
+        case Expose:
+          break;
+        case MotionNotify:
+        {
+          crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
+          crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
+        }
+        default:
+          break;
+      }
+      if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
+          ((state & ExitState) != 0))
+        {
+          /*
+            Check boundary conditions.
+          */
+          if (crop_info.x < 0)
+            crop_info.x=0;
+          else
+            if (crop_info.x > (ssize_t) windows->image.ximage->width)
+              crop_info.x=(ssize_t) windows->image.ximage->width;
+          if ((int) crop_info.x < x)
+            crop_info.width=(unsigned int) (x-crop_info.x);
+          else
+            {
+              crop_info.width=(unsigned int) (crop_info.x-x);
+              crop_info.x=(ssize_t) x;
+            }
+          if (crop_info.y < 0)
+            crop_info.y=0;
+          else
+            if (crop_info.y > (ssize_t) windows->image.ximage->height)
+              crop_info.y=(ssize_t) windows->image.ximage->height;
+          if ((int) crop_info.y < y)
+            crop_info.height=(unsigned int) (y-crop_info.y);
+          else
+            {
+              crop_info.height=(unsigned int) (crop_info.y-y);
+              crop_info.y=(ssize_t) y;
+            }
+        }
+    } while ((state & ExitState) == 0);
+    /*
+      Wait for user to grab a corner of the rectangle or press return.
+    */
+    state=DefaultState;
+    (void) XMapWindow(display,windows->info.id);
+    do
+    {
+      if (windows->info.mapped != MagickFalse)
+        {
+          /*
+            Display pointer position.
+          */
+          (void) FormatLocaleString(text,MaxTextExtent,
+            " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
+            crop_info.height,(double) crop_info.x,(double) crop_info.y);
+          XInfoWidget(display,windows,text);
+        }
+      highlight_info=crop_info;
+      highlight_info.x=crop_info.x-windows->image.x;
+      highlight_info.y=crop_info.y-windows->image.y;
+      if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
+        {
+          state|=EscapeState;
+          state|=ExitState;
+          break;
+        }
+      XHighlightRectangle(display,windows->image.id,
+        windows->image.highlight_context,&highlight_info);
+      XScreenEvent(display,windows,&event);
+      if (event.xany.window == windows->command.id)
+        {
+          /*
+            Select a command from the Command widget.
+          */
+          (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+          id=XCommandWidget(display,windows,RectifyModeMenu,&event);
+          (void) XSetFunction(display,windows->image.highlight_context,
+            GXinvert);
+          XHighlightRectangle(display,windows->image.id,
+            windows->image.highlight_context,&highlight_info);
+          if (id >= 0)
+            switch (RectifyCommands[id])
+            {
+              case RectifyCopyCommand:
+              {
+                state|=ExitState;
+                break;
+              }
+              case RectifyHelpCommand:
+              {
+                (void) XSetFunction(display,windows->image.highlight_context,
+                  GXcopy);
+                switch (mode)
+                {
+                  case CopyMode:
+                  {
+                    XTextViewWidget(display,resource_info,windows,MagickFalse,
+                      "Help Viewer - Image Copy",ImageCopyHelp);
+                    break;
+                  }
+                  case CropMode:
+                  {
+                    XTextViewWidget(display,resource_info,windows,MagickFalse,
+                      "Help Viewer - Image Crop",ImageCropHelp);
+                    break;
+                  }
+                  case CutMode:
+                  {
+                    XTextViewWidget(display,resource_info,windows,MagickFalse,
+                      "Help Viewer - Image Cut",ImageCutHelp);
+                    break;
+                  }
+                }
+                (void) XSetFunction(display,windows->image.highlight_context,
+                  GXinvert);
+                break;
+              }
+              case RectifyDismissCommand:
+              {
+                /*
+                  Prematurely exit.
+                */
+                state|=EscapeState;
+                state|=ExitState;
+                break;
+              }
+              default:
+                break;
+            }
+          continue;
+        }
+      XHighlightRectangle(display,windows->image.id,
+        windows->image.highlight_context,&highlight_info);
+      switch (event.type)
+      {
+        case ButtonPress:
+        {
+          if (event.xbutton.button != Button1)
+            break;
+          if (event.xbutton.window != windows->image.id)
+            break;
+          x=windows->image.x+event.xbutton.x;
+          y=windows->image.y+event.xbutton.y;
+          if ((x < (int) (crop_info.x+RoiDelta)) &&
+              (x > (int) (crop_info.x-RoiDelta)) &&
+              (y < (int) (crop_info.y+RoiDelta)) &&
+              (y > (int) (crop_info.y-RoiDelta)))
+            {
+              crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
+              crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
+              state|=UpdateConfigurationState;
+              break;
+            }
+          if ((x < (int) (crop_info.x+RoiDelta)) &&
+              (x > (int) (crop_info.x-RoiDelta)) &&
+              (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
+              (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
+            {
+              crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
+              state|=UpdateConfigurationState;
+              break;
+            }
+          if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
+              (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
+              (y < (int) (crop_info.y+RoiDelta)) &&
+              (y > (int) (crop_info.y-RoiDelta)))
+            {
+              crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
+              state|=UpdateConfigurationState;
+              break;
+            }
+          if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
+              (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
+              (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
+              (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
+            {
+              state|=UpdateConfigurationState;
+              break;
+            }
+        }
+        case ButtonRelease:
+        {
+          if (event.xbutton.window == windows->pan.id)
+            if ((highlight_info.x != crop_info.x-windows->image.x) ||
+                (highlight_info.y != crop_info.y-windows->image.y))
+              XHighlightRectangle(display,windows->image.id,
+                windows->image.highlight_context,&highlight_info);
+          (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
+            event.xbutton.time);
+          break;
+        }
+        case Expose:
+        {
+          if (event.xexpose.window == windows->image.id)
+            if (event.xexpose.count == 0)
+              {
+                event.xexpose.x=(int) highlight_info.x;
+                event.xexpose.y=(int) highlight_info.y;
+                event.xexpose.width=(int) highlight_info.width;
+                event.xexpose.height=(int) highlight_info.height;
+                XRefreshWindow(display,&windows->image,&event);
+              }
+          if (event.xexpose.window == windows->info.id)
+            if (event.xexpose.count == 0)
+              XInfoWidget(display,windows,text);
+          break;
+        }
+        case KeyPress:
+        {
+          if (event.xkey.window != windows->image.id)
+            break;
+          /*
+            Respond to a user key press.
+          */
+          (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+            sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+          switch ((int) key_symbol)
+          {
+            case XK_Escape:
+            case XK_F20:
+              state|=EscapeState;
+            case XK_Return:
+            {
+              state|=ExitState;
+              break;
+            }
+            case XK_Home:
+            case XK_KP_Home:
+            {
+              crop_info.x=(ssize_t) (windows->image.width/2L-
+                crop_info.width/2L);
+              crop_info.y=(ssize_t) (windows->image.height/2L-
+                crop_info.height/2L);
+              break;
+            }
+            case XK_Left:
+            case XK_KP_Left:
+            {
+              crop_info.x--;
+              break;
+            }
+            case XK_Up:
+            case XK_KP_Up:
+            case XK_Next:
+            {
+              crop_info.y--;
+              break;
+            }
+            case XK_Right:
+            case XK_KP_Right:
+            {
+              crop_info.x++;
+              break;
+            }
+            case XK_Prior:
+            case XK_Down:
+            case XK_KP_Down:
+            {
+              crop_info.y++;
+              break;
+            }
+            case XK_F1:
+            case XK_Help:
+            {
+              (void) XSetFunction(display,windows->image.highlight_context,
+                GXcopy);
+              switch (mode)
+              {
+                case CopyMode:
+                {
+                  XTextViewWidget(display,resource_info,windows,MagickFalse,
+                    "Help Viewer - Image Copy",ImageCopyHelp);
+                  break;
+                }
+                case CropMode:
+                {
+                  XTextViewWidget(display,resource_info,windows,MagickFalse,
+                    "Help Viewer - Image Cropg",ImageCropHelp);
+                  break;
+                }
+                case CutMode:
+                {
+                  XTextViewWidget(display,resource_info,windows,MagickFalse,
+                    "Help Viewer - Image Cutg",ImageCutHelp);
+                  break;
+                }
+              }
+              (void) XSetFunction(display,windows->image.highlight_context,
+                GXinvert);
+              break;
+            }
+            default:
+            {
+              (void) XBell(display,0);
+              break;
+            }
+          }
+          (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
+            event.xkey.time);
+          break;
+        }
+        case KeyRelease:
+          break;
+        case MotionNotify:
+        {
+          if (event.xmotion.window != windows->image.id)
+            break;
+          /*
+            Map and unmap Info widget as text cursor crosses its boundaries.
+          */
+          x=event.xmotion.x;
+          y=event.xmotion.y;
+          if (windows->info.mapped != MagickFalse)
+            {
+              if ((x < (int) (windows->info.x+windows->info.width)) &&
+                  (y < (int) (windows->info.y+windows->info.height)))
+                (void) XWithdrawWindow(display,windows->info.id,
+                  windows->info.screen);
+            }
+          else
+            if ((x > (int) (windows->info.x+windows->info.width)) ||
+                (y > (int) (windows->info.y+windows->info.height)))
+              (void) XMapWindow(display,windows->info.id);
+          crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
+          crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
+          break;
+        }
+        case SelectionRequest:
+        {
+          XSelectionEvent
+            notify;
+
+          XSelectionRequestEvent
+            *request;
+
+          /*
+            Set primary selection.
+          */
+          (void) FormatLocaleString(text,MaxTextExtent,
+            "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
+            crop_info.height,(double) crop_info.x,(double) crop_info.y);
+          request=(&(event.xselectionrequest));
+          (void) XChangeProperty(request->display,request->requestor,
+            request->property,request->target,8,PropModeReplace,
+            (unsigned char *) text,(int) strlen(text));
+          notify.type=SelectionNotify;
+          notify.display=request->display;
+          notify.requestor=request->requestor;
+          notify.selection=request->selection;
+          notify.target=request->target;
+          notify.time=request->time;
+          if (request->property == None)
+            notify.property=request->target;
+          else
+            notify.property=request->property;
+          (void) XSendEvent(request->display,request->requestor,False,0,
+            (XEvent *) &notify);
+        }
+        default:
+          break;
+      }
+      if ((state & UpdateConfigurationState) != 0)
+        {
+          (void) XPutBackEvent(display,&event);
+          (void) XCheckDefineCursor(display,windows->image.id,cursor);
+          break;
+        }
+    } while ((state & ExitState) == 0);
+  } while ((state & ExitState) == 0);
+  (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+  XSetCursorState(display,windows,MagickFalse);
+  if ((state & EscapeState) != 0)
+    return(MagickTrue);
+  if (mode == CropMode)
+    if (((int) crop_info.width != windows->image.ximage->width) ||
+        ((int) crop_info.height != windows->image.ximage->height))
+      {
+        /*
+          Reconfigure Image window as defined by cropping rectangle.
+        */
+        XSetCropGeometry(display,windows,&crop_info,image);
+        windows->image.window_changes.width=(int) crop_info.width;
+        windows->image.window_changes.height=(int) crop_info.height;
+        (void) XConfigureImage(display,resource_info,windows,image);
+        return(MagickTrue);
+      }
+  /*
+    Copy image before applying image transforms.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  scale_factor=(MagickRealType) width/windows->image.ximage->width;
+  crop_info.x+=x;
+  crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
+  crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
+  scale_factor=(MagickRealType) height/windows->image.ximage->height;
+  crop_info.y+=y;
+  crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
+  crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
+  crop_image=CropImage(image,&crop_info,&image->exception);
+  XSetCursorState(display,windows,MagickFalse);
+  if (crop_image == (Image *) NULL)
+    return(MagickFalse);
+  if (resource_info->copy_image != (Image *) NULL)
+    resource_info->copy_image=DestroyImage(resource_info->copy_image);
+  resource_info->copy_image=crop_image;
+  if (mode == CopyMode)
+    {
+      (void) XConfigureImage(display,resource_info,windows,image);
+      return(MagickTrue);
+    }
+  /*
+    Cut image.
+  */
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  image->matte=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (int) crop_info.height; y++)
+  {
+    q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
+      crop_info.width,1,exception);
+    if (q == (Quantum *) NULL)
+      break;
+    for (x=0; x < (int) crop_info.width; x++)
+    {
+      SetPixelAlpha(image,TransparentAlpha,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  /*
+    Update image configuration.
+  */
+  XConfigureImageColormap(display,resource_info,windows,image);
+  (void) XConfigureImage(display,resource_info,windows,image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
+%  the image.
+%
+%  The format of the XDrawEditImage method is:
+%
+%      MagickBooleanType XDrawEditImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XDrawEditImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image **image)
+{
+  static const char
+    *DrawMenu[] =
+    {
+      "Element",
+      "Color",
+      "Stipple",
+      "Width",
+      "Undo",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static ElementType
+    element = PointElement;
+
+  static const ModeType
+    DrawCommands[] =
+    {
+      DrawElementCommand,
+      DrawColorCommand,
+      DrawStippleCommand,
+      DrawWidthCommand,
+      DrawUndoCommand,
+      DrawHelpCommand,
+      DrawDismissCommand
+    };
+
+  static Pixmap
+    stipple = (Pixmap) NULL;
+
+  static unsigned int
+    pen_id = 0,
+    line_width = 1;
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  int
+    entry,
+    id,
+    number_coordinates,
+    x,
+    y;
+
+  MagickRealType
+    degrees;
+
+  MagickStatusType
+    status;
+
+  RectangleInfo
+    rectangle_info;
+
+  register int
+    i;
+
+  unsigned int
+    distance,
+    height,
+    max_coordinates,
+    width;
+
+  size_t
+    state;
+
+  Window
+    root_window;
+
+  XDrawInfo
+    draw_info;
+
+  XEvent
+    event;
+
+  XPoint
+    *coordinate_info;
+
+  XSegment
+    line_info;
+
+  /*
+    Allocate polygon info.
+  */
+  max_coordinates=2048;
+  coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
+    sizeof(*coordinate_info));
+  if (coordinate_info == (XPoint *) NULL)
+    {
+      (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
+      return(MagickFalse);
+    }
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Draw");
+  windows->command.data=4;
+  (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Wait for first button press.
+  */
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  draw_info.stencil=OpaqueStencil;
+  status=MagickTrue;
+  cursor=XCreateFontCursor(display,XC_tcross);
+  for ( ; ; )
+  {
+    XQueryPosition(display,windows->image.id,&x,&y);
+    (void) XSelectInput(display,windows->image.id,
+      windows->image.attributes.event_mask | PointerMotionMask);
+    (void) XCheckDefineCursor(display,windows->image.id,cursor);
+    state=DefaultState;
+    do
+    {
+      if (windows->info.mapped != MagickFalse)
+        {
+          /*
+            Display pointer position.
+          */
+          (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
+            x+windows->image.x,y+windows->image.y);
+          XInfoWidget(display,windows,text);
+        }
+      /*
+        Wait for next event.
+      */
+      XScreenEvent(display,windows,&event);
+      if (event.xany.window == windows->command.id)
+        {
+          /*
+            Select a command from the Command widget.
+          */
+          id=XCommandWidget(display,windows,DrawMenu,&event);
+          if (id < 0)
+            continue;
+          switch (DrawCommands[id])
+          {
+            case DrawElementCommand:
+            {
+              static const char
+                *Elements[] =
+                {
+                  "point",
+                  "line",
+                  "rectangle",
+                  "fill rectangle",
+                  "circle",
+                  "fill circle",
+                  "ellipse",
+                  "fill ellipse",
+                  "polygon",
+                  "fill polygon",
+                  (char *) NULL,
+                };
+
+              /*
+                Select a command from the pop-up menu.
+              */
+              element=(ElementType) (XMenuWidget(display,windows,
+                DrawMenu[id],Elements,command)+1);
+              break;
+            }
+            case DrawColorCommand:
+            {
+              const char
+                *ColorMenu[MaxNumberPens+1];
+
+              int
+                pen_number;
+
+              MagickBooleanType
+                transparent;
+
+              XColor
+                color;
+
+              /*
+                Initialize menu selections.
+              */
+              for (i=0; i < (int) (MaxNumberPens-2); i++)
+                ColorMenu[i]=resource_info->pen_colors[i];
+              ColorMenu[MaxNumberPens-2]="transparent";
+              ColorMenu[MaxNumberPens-1]="Browser...";
+              ColorMenu[MaxNumberPens]=(char *) NULL;
+              /*
+                Select a pen color from the pop-up menu.
+              */
+              pen_number=XMenuWidget(display,windows,DrawMenu[id],
+                (const char **) ColorMenu,command);
+              if (pen_number < 0)
+                break;
+              transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
+                MagickFalse;
+              if (transparent != MagickFalse)
+                {
+                  draw_info.stencil=TransparentStencil;
+                  break;
+                }
+              if (pen_number == (MaxNumberPens-1))
+                {
+                  static char
+                    color_name[MaxTextExtent] = "gray";
+
+                  /*
+                    Select a pen color from a dialog.
+                  */
+                  resource_info->pen_colors[pen_number]=color_name;
+                  XColorBrowserWidget(display,windows,"Select",color_name);
+                  if (*color_name == '\0')
+                    break;
+                }
+              /*
+                Set pen color.
+              */
+              (void) XParseColor(display,windows->map_info->colormap,
+                resource_info->pen_colors[pen_number],&color);
+              XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
+                (unsigned int) MaxColors,&color);
+              windows->pixel_info->pen_colors[pen_number]=color;
+              pen_id=(unsigned int) pen_number;
+              draw_info.stencil=OpaqueStencil;
+              break;
+            }
+            case DrawStippleCommand:
+            {
+              Image
+                *stipple_image;
+
+              ImageInfo
+                *image_info;
+
+              int
+                status;
+
+              static char
+                filename[MaxTextExtent] = "\0";
+
+              static const char
+                *StipplesMenu[] =
+                {
+                  "Brick",
+                  "Diagonal",
+                  "Scales",
+                  "Vertical",
+                  "Wavy",
+                  "Translucent",
+                  "Opaque",
+                  (char *) NULL,
+                  (char *) NULL,
+                };
+
+              /*
+                Select a command from the pop-up menu.
+              */
+              StipplesMenu[7]="Open...";
+              entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
+                command);
+              if (entry < 0)
+                break;
+              if (stipple != (Pixmap) NULL)
+                (void) XFreePixmap(display,stipple);
+              stipple=(Pixmap) NULL;
+              if (entry != 7)
+                {
+                  switch (entry)
+                  {
+                    case 0:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) BricksBitmap,BricksWidth,BricksHeight);
+                      break;
+                    }
+                    case 1:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
+                      break;
+                    }
+                    case 2:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
+                      break;
+                    }
+                    case 3:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
+                      break;
+                    }
+                    case 4:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) WavyBitmap,WavyWidth,WavyHeight);
+                      break;
+                    }
+                    case 5:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) HighlightBitmap,HighlightWidth,
+                        HighlightHeight);
+                      break;
+                    }
+                    case 6:
+                    default:
+                    {
+                      stipple=XCreateBitmapFromData(display,root_window,
+                        (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
+                      break;
+                    }
+                  }
+                  break;
+                }
+              XFileBrowserWidget(display,windows,"Stipple",filename);
+              if (*filename == '\0')
+                break;
+              /*
+                Read image.
+              */
+              XSetCursorState(display,windows,MagickTrue);
+              XCheckRefreshWindows(display,windows);
+              image_info=AcquireImageInfo();
+              (void) CopyMagickString(image_info->filename,filename,
+                MaxTextExtent);
+              stipple_image=ReadImage(image_info,&(*image)->exception);
+              CatchException(&(*image)->exception);
+              XSetCursorState(display,windows,MagickFalse);
+              if (stipple_image == (Image *) NULL)
+                break;
+              (void) AcquireUniqueFileResource(filename);
+              (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
+                "xbm:%s",filename);
+              (void) WriteImage(image_info,stipple_image);
+              stipple_image=DestroyImage(stipple_image);
+              image_info=DestroyImageInfo(image_info);
+              status=XReadBitmapFile(display,root_window,filename,&width,
+                &height,&stipple,&x,&y);
+              (void) RelinquishUniqueFileResource(filename);
+              if ((status != BitmapSuccess) != 0)
+                XNoticeWidget(display,windows,"Unable to read X bitmap image:",
+                  filename);
+              break;
+            }
+            case DrawWidthCommand:
+            {
+              static char
+                width[MaxTextExtent] = "0";
+
+              static const char
+                *WidthsMenu[] =
+                {
+                  "1",
+                  "2",
+                  "4",
+                  "8",
+                  "16",
+                  "Dialog...",
+                  (char *) NULL,
+                };
+
+              /*
+                Select a command from the pop-up menu.
+              */
+              entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
+                command);
+              if (entry < 0)
+                break;
+              if (entry != 5)
+                {
+                  line_width=(unsigned int) StringToUnsignedLong(
+                    WidthsMenu[entry]);
+                  break;
+                }
+              (void) XDialogWidget(display,windows,"Ok","Enter line width:",
+                width);
+              if (*width == '\0')
+                break;
+              line_width=(unsigned int) StringToUnsignedLong(width);
+              break;
+            }
+            case DrawUndoCommand:
+            {
+              (void) XMagickCommand(display,resource_info,windows,UndoCommand,
+                image);
+              break;
+            }
+            case DrawHelpCommand:
+            {
+              XTextViewWidget(display,resource_info,windows,MagickFalse,
+                "Help Viewer - Image Rotation",ImageDrawHelp);
+              (void) XCheckDefineCursor(display,windows->image.id,cursor);
+              break;
+            }
+            case DrawDismissCommand:
+            {
+              /*
+                Prematurely exit.
+              */
+              state|=EscapeState;
+              state|=ExitState;
+              break;
+            }
+            default:
+              break;
+          }
+          (void) XCheckDefineCursor(display,windows->image.id,cursor);
+          continue;
+        }
+      switch (event.type)
+      {
+        case ButtonPress:
+        {
+          if (event.xbutton.button != Button1)
+            break;
+          if (event.xbutton.window != windows->image.id)
+            break;
+          /*
+            exit loop.
+          */
+          x=event.xbutton.x;
+          y=event.xbutton.y;
+          state|=ExitState;
+          break;
+        }
+        case ButtonRelease:
+          break;
+        case Expose:
+          break;
+        case KeyPress:
+        {
+          KeySym
+            key_symbol;
+
+          if (event.xkey.window != windows->image.id)
+            break;
+          /*
+            Respond to a user key press.
+          */
+          (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+            sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+          switch ((int) key_symbol)
+          {
+            case XK_Escape:
+            case XK_F20:
+            {
+              /*
+                Prematurely exit.
+              */
+              state|=EscapeState;
+              state|=ExitState;
+              break;
+            }
+            case XK_F1:
+            case XK_Help:
+            {
+              XTextViewWidget(display,resource_info,windows,MagickFalse,
+                "Help Viewer - Image Rotation",ImageDrawHelp);
+              break;
+            }
+            default:
+            {
+              (void) XBell(display,0);
+              break;
+            }
+          }
+          break;
+        }
+        case MotionNotify:
+        {
+          /*
+            Map and unmap Info widget as text cursor crosses its boundaries.
+          */
+          x=event.xmotion.x;
+          y=event.xmotion.y;
+          if (windows->info.mapped != MagickFalse)
+            {
+              if ((x < (int) (windows->info.x+windows->info.width)) &&
+                  (y < (int) (windows->info.y+windows->info.height)))
+                (void) XWithdrawWindow(display,windows->info.id,
+                  windows->info.screen);
+            }
+          else
+            if ((x > (int) (windows->info.x+windows->info.width)) ||
+                (y > (int) (windows->info.y+windows->info.height)))
+              (void) XMapWindow(display,windows->info.id);
+          break;
+        }
+      }
+    } while ((state & ExitState) == 0);
+    (void) XSelectInput(display,windows->image.id,
+      windows->image.attributes.event_mask);
+    (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+    if ((state & EscapeState) != 0)
+      break;
+    /*
+      Draw element as pointer moves until the button is released.
+    */
+    distance=0;
+    degrees=0.0;
+    line_info.x1=x;
+    line_info.y1=y;
+    line_info.x2=x;
+    line_info.y2=y;
+    rectangle_info.x=(ssize_t) x;
+    rectangle_info.y=(ssize_t) y;
+    rectangle_info.width=0;
+    rectangle_info.height=0;
+    number_coordinates=1;
+    coordinate_info->x=x;
+    coordinate_info->y=y;
+    (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+    state=DefaultState;
+    do
+    {
+      switch (element)
+      {
+        case PointElement:
+        default:
+        {
+          if (number_coordinates > 1)
+            {
+              (void) XDrawLines(display,windows->image.id,
+                windows->image.highlight_context,coordinate_info,
+                number_coordinates,CoordModeOrigin);
+              (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
+                coordinate_info[number_coordinates-1].x,
+                coordinate_info[number_coordinates-1].y);
+              XInfoWidget(display,windows,text);
+            }
+          break;
+        }
+        case LineElement:
+        {
+          if (distance > 9)
+            {
+              /*
+                Display angle of the line.
+              */
+              degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
+                line_info.y1),(double) (line_info.x2-line_info.x1)));
+              (void) FormatLocaleString(text,MaxTextExtent," %g",
+                (double) degrees);
+              XInfoWidget(display,windows,text);
+              XHighlightLine(display,windows->image.id,
+                windows->image.highlight_context,&line_info);
+            }
+          else
+            if (windows->info.mapped != MagickFalse)
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          break;
+        }
+        case RectangleElement:
+        case FillRectangleElement:
+        {
+          if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
+            {
+              /*
+                Display info and draw drawing rectangle.
+              */
+              (void) FormatLocaleString(text,MaxTextExtent,
+                " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
+                (double) rectangle_info.height,(double) rectangle_info.x,
+                (double) rectangle_info.y);
+              XInfoWidget(display,windows,text);
+              XHighlightRectangle(display,windows->image.id,
+                windows->image.highlight_context,&rectangle_info);
+            }
+          else
+            if (windows->info.mapped != MagickFalse)
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          break;
+        }
+        case CircleElement:
+        case FillCircleElement:
+        case EllipseElement:
+        case FillEllipseElement:
+        {
+          if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
+            {
+              /*
+                Display info and draw drawing rectangle.
+              */
+              (void) FormatLocaleString(text,MaxTextExtent,
+                " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
+                (double) rectangle_info.height,(double) rectangle_info.x,
+                (double) rectangle_info.y);
+              XInfoWidget(display,windows,text);
+              XHighlightEllipse(display,windows->image.id,
+                windows->image.highlight_context,&rectangle_info);
+            }
+          else
+            if (windows->info.mapped != MagickFalse)
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          break;
+        }
+        case PolygonElement:
+        case FillPolygonElement:
+        {
+          if (number_coordinates > 1)
+            (void) XDrawLines(display,windows->image.id,
+              windows->image.highlight_context,coordinate_info,
+              number_coordinates,CoordModeOrigin);
+          if (distance > 9)
+            {
+              /*
+                Display angle of the line.
+              */
+              degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
+                line_info.y1),(double) (line_info.x2-line_info.x1)));
+              (void) FormatLocaleString(text,MaxTextExtent," %g",
+                (double) degrees);
+              XInfoWidget(display,windows,text);
+              XHighlightLine(display,windows->image.id,
+                windows->image.highlight_context,&line_info);
+            }
+          else
+            if (windows->info.mapped != MagickFalse)
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          break;
+        }
+      }
+      /*
+        Wait for next event.
+      */
+      XScreenEvent(display,windows,&event);
+      switch (element)
+      {
+        case PointElement:
+        default:
+        {
+          if (number_coordinates > 1)
+            (void) XDrawLines(display,windows->image.id,
+              windows->image.highlight_context,coordinate_info,
+              number_coordinates,CoordModeOrigin);
+          break;
+        }
+        case LineElement:
+        {
+          if (distance > 9)
+            XHighlightLine(display,windows->image.id,
+              windows->image.highlight_context,&line_info);
+          break;
+        }
+        case RectangleElement:
+        case FillRectangleElement:
+        {
+          if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
+            XHighlightRectangle(display,windows->image.id,
+              windows->image.highlight_context,&rectangle_info);
+          break;
+        }
+        case CircleElement:
+        case FillCircleElement:
+        case EllipseElement:
+        case FillEllipseElement:
+        {
+          if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
+            XHighlightEllipse(display,windows->image.id,
+              windows->image.highlight_context,&rectangle_info);
+          break;
+        }
+        case PolygonElement:
+        case FillPolygonElement:
+        {
+          if (number_coordinates > 1)
+            (void) XDrawLines(display,windows->image.id,
+              windows->image.highlight_context,coordinate_info,
+              number_coordinates,CoordModeOrigin);
+          if (distance > 9)
+            XHighlightLine(display,windows->image.id,
+              windows->image.highlight_context,&line_info);
+          break;
+        }
+      }
+      switch (event.type)
+      {
+        case ButtonPress:
+          break;
+        case ButtonRelease:
+        {
+          /*
+            User has committed to element.
+          */
+          line_info.x2=event.xbutton.x;
+          line_info.y2=event.xbutton.y;
+          rectangle_info.x=(ssize_t) event.xbutton.x;
+          rectangle_info.y=(ssize_t) event.xbutton.y;
+          coordinate_info[number_coordinates].x=event.xbutton.x;
+          coordinate_info[number_coordinates].y=event.xbutton.y;
+          if (((element != PolygonElement) &&
+               (element != FillPolygonElement)) || (distance <= 9))
+            {
+              state|=ExitState;
+              break;
+            }
+          number_coordinates++;
+          if (number_coordinates < (int) max_coordinates)
+            {
+              line_info.x1=event.xbutton.x;
+              line_info.y1=event.xbutton.y;
+              break;
+            }
+          max_coordinates<<=1;
+          coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
+            max_coordinates,sizeof(*coordinate_info));
+          if (coordinate_info == (XPoint *) NULL)
+            (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
+              ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
+          break;
+        }
+        case Expose:
+          break;
+        case MotionNotify:
+        {
+          if (event.xmotion.window != windows->image.id)
+            break;
+          if (element != PointElement)
+            {
+              line_info.x2=event.xmotion.x;
+              line_info.y2=event.xmotion.y;
+              rectangle_info.x=(ssize_t) event.xmotion.x;
+              rectangle_info.y=(ssize_t) event.xmotion.y;
+              break;
+            }
+          coordinate_info[number_coordinates].x=event.xbutton.x;
+          coordinate_info[number_coordinates].y=event.xbutton.y;
+          number_coordinates++;
+          if (number_coordinates < (int) max_coordinates)
+            break;
+          max_coordinates<<=1;
+          coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
+            max_coordinates,sizeof(*coordinate_info));
+          if (coordinate_info == (XPoint *) NULL)
+            (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
+              ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
+          break;
+        }
+        default:
+          break;
+      }
+      /*
+        Check boundary conditions.
+      */
+      if (line_info.x2 < 0)
+        line_info.x2=0;
+      else
+        if (line_info.x2 > (int) windows->image.width)
+          line_info.x2=(short) windows->image.width;
+      if (line_info.y2 < 0)
+        line_info.y2=0;
+      else
+        if (line_info.y2 > (int) windows->image.height)
+          line_info.y2=(short) windows->image.height;
+      distance=(unsigned int)
+        (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
+         ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
+      if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
+          ((state & ExitState) != 0))
+        {
+          if (rectangle_info.x < 0)
+            rectangle_info.x=0;
+          else
+            if (rectangle_info.x > (ssize_t) windows->image.width)
+              rectangle_info.x=(ssize_t) windows->image.width;
+          if ((int) rectangle_info.x < x)
+            rectangle_info.width=(unsigned int) (x-rectangle_info.x);
+          else
+            {
+              rectangle_info.width=(unsigned int) (rectangle_info.x-x);
+              rectangle_info.x=(ssize_t) x;
+            }
+          if (rectangle_info.y < 0)
+            rectangle_info.y=0;
+          else
+            if (rectangle_info.y > (ssize_t) windows->image.height)
+              rectangle_info.y=(ssize_t) windows->image.height;
+          if ((int) rectangle_info.y < y)
+            rectangle_info.height=(unsigned int) (y-rectangle_info.y);
+          else
+            {
+              rectangle_info.height=(unsigned int) (rectangle_info.y-y);
+              rectangle_info.y=(ssize_t) y;
+            }
+        }
+    } while ((state & ExitState) == 0);
+    (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+    if ((element == PointElement) || (element == PolygonElement) ||
+        (element == FillPolygonElement))
+      {
+        /*
+          Determine polygon bounding box.
+        */
+        rectangle_info.x=(ssize_t) coordinate_info->x;
+        rectangle_info.y=(ssize_t) coordinate_info->y;
+        x=coordinate_info->x;
+        y=coordinate_info->y;
+        for (i=1; i < number_coordinates; i++)
+        {
+          if (coordinate_info[i].x > x)
+            x=coordinate_info[i].x;
+          if (coordinate_info[i].y > y)
+            y=coordinate_info[i].y;
+          if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
+            rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
+          if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
+            rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
+        }
+        rectangle_info.width=(size_t) (x-rectangle_info.x);
+        rectangle_info.height=(size_t) (y-rectangle_info.y);
+        for (i=0; i < number_coordinates; i++)
+        {
+          coordinate_info[i].x-=rectangle_info.x;
+          coordinate_info[i].y-=rectangle_info.y;
+        }
+      }
+    else
+      if (distance <= 9)
+        continue;
+      else
+        if ((element == RectangleElement) ||
+            (element == CircleElement) || (element == EllipseElement))
+          {
+            rectangle_info.width--;
+            rectangle_info.height--;
+          }
+    /*
+      Drawing is relative to image configuration.
+    */
+    draw_info.x=(int) rectangle_info.x;
+    draw_info.y=(int) rectangle_info.y;
+    (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
+      image);
+    width=(unsigned int) (*image)->columns;
+    height=(unsigned int) (*image)->rows;
+    x=0;
+    y=0;
+    if (windows->image.crop_geometry != (char *) NULL)
+      (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+    draw_info.x+=windows->image.x-(line_width/2);
+    if (draw_info.x < 0)
+      draw_info.x=0;
+    draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
+    draw_info.y+=windows->image.y-(line_width/2);
+    if (draw_info.y < 0)
+      draw_info.y=0;
+    draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
+    draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
+    if (draw_info.width > (unsigned int) (*image)->columns)
+      draw_info.width=(unsigned int) (*image)->columns;
+    draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
+    if (draw_info.height > (unsigned int) (*image)->rows)
+      draw_info.height=(unsigned int) (*image)->rows;
+    (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
+      width*draw_info.width/windows->image.ximage->width,
+      height*draw_info.height/windows->image.ximage->height,
+      draw_info.x+x,draw_info.y+y);
+    /*
+      Initialize drawing attributes.
+    */
+    draw_info.degrees=0.0;
+    draw_info.element=element;
+    draw_info.stipple=stipple;
+    draw_info.line_width=line_width;
+    draw_info.line_info=line_info;
+    if (line_info.x1 > (int) (line_width/2))
+      draw_info.line_info.x1=(short) line_width/2;
+    if (line_info.y1 > (int) (line_width/2))
+      draw_info.line_info.y1=(short) line_width/2;
+    draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
+    draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
+    if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
+      {
+        draw_info.line_info.x2=(-draw_info.line_info.x2);
+        draw_info.line_info.y2=(-draw_info.line_info.y2);
+      }
+    if (draw_info.line_info.x2 < 0)
+      {
+        draw_info.line_info.x2=(-draw_info.line_info.x2);
+        Swap(draw_info.line_info.x1,draw_info.line_info.x2);
+      }
+    if (draw_info.line_info.y2 < 0)
+      {
+        draw_info.line_info.y2=(-draw_info.line_info.y2);
+        Swap(draw_info.line_info.y1,draw_info.line_info.y2);
+      }
+    draw_info.rectangle_info=rectangle_info;
+    if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
+      draw_info.rectangle_info.x=(ssize_t) line_width/2;
+    if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
+      draw_info.rectangle_info.y=(ssize_t) line_width/2;
+    draw_info.number_coordinates=(unsigned int) number_coordinates;
+    draw_info.coordinate_info=coordinate_info;
+    windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
+    /*
+      Draw element on image.
+    */
+    XSetCursorState(display,windows,MagickTrue);
+    XCheckRefreshWindows(display,windows);
+    status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
+    XSetCursorState(display,windows,MagickFalse);
+    /*
+      Update image colormap and return to image drawing.
+    */
+    XConfigureImageColormap(display,resource_info,windows,*image);
+    (void) XConfigureImage(display,resource_info,windows,*image);
+  }
+  XSetCursorState(display,windows,MagickFalse);
+  coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w P a n R e c t a n g l e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawPanRectangle() draws a rectangle in the pan window.  The pan window
+%  displays a zoom image and the rectangle shows which portion of the image is
+%  displayed in the Image window.
+%
+%  The format of the XDrawPanRectangle method is:
+%
+%      XDrawPanRectangle(Display *display,XWindows *windows)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+*/
+static void XDrawPanRectangle(Display *display,XWindows *windows)
+{
+  MagickRealType
+    scale_factor;
+
+  RectangleInfo
+    highlight_info;
+
+  /*
+    Determine dimensions of the panning rectangle.
+  */
+  scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
+  highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
+  highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
+  scale_factor=(MagickRealType)
+    windows->pan.height/windows->image.ximage->height;
+  highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
+  highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
+  /*
+    Display the panning rectangle.
+  */
+  (void) XClearWindow(display,windows->pan.id);
+  XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
+    &highlight_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X I m a g e C a c h e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XImageCache() handles the creation, manipulation, and destruction of the
+%  image cache (undo and redo buffers).
+%
+%  The format of the XImageCache method is:
+%
+%      void XImageCache(Display *display,XResourceInfo *resource_info,
+%        XWindows *windows,const CommandType command,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o command: Specifies a command to perform.
+%
+%    o image: the image;  XImageCache may transform the image and return a new
+%      image pointer.
+%
+*/
+static void XImageCache(Display *display,XResourceInfo *resource_info,
+  XWindows *windows,const CommandType command,Image **image)
+{
+  Image
+    *cache_image;
+
+  static Image
+    *redo_image = (Image *) NULL,
+    *undo_image = (Image *) NULL;
+
+  switch (command)
+  {
+    case FreeBuffersCommand:
+    {
+      /*
+        Free memory from the undo and redo cache.
+      */
+      while (undo_image != (Image *) NULL)
+      {
+        cache_image=undo_image;
+        undo_image=GetPreviousImageInList(undo_image);
+        cache_image->list=DestroyImage(cache_image->list);
+        cache_image=DestroyImage(cache_image);
+      }
+      undo_image=NewImageList();
+      if (redo_image != (Image *) NULL)
+        redo_image=DestroyImage(redo_image);
+      redo_image=NewImageList();
+      return;
+    }
+    case UndoCommand:
+    {
+      char
+        image_geometry[MaxTextExtent];
+
+      /*
+        Undo the last image transformation.
+      */
+      if (undo_image == (Image *) NULL)
+        {
+          (void) XBell(display,0);
+          return;
+        }
+      cache_image=undo_image;
+      undo_image=GetPreviousImageInList(undo_image);
+      windows->image.window_changes.width=(int) cache_image->columns;
+      windows->image.window_changes.height=(int) cache_image->rows;
+      (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
+        windows->image.ximage->width,windows->image.ximage->height);
+      (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
+      if (windows->image.crop_geometry != (char *) NULL)
+        windows->image.crop_geometry=(char *)
+          RelinquishMagickMemory(windows->image.crop_geometry);
+      windows->image.crop_geometry=cache_image->geometry;
+      if (redo_image != (Image *) NULL)
+        redo_image=DestroyImage(redo_image);
+      redo_image=(*image);
+      *image=cache_image->list;
+      cache_image=DestroyImage(cache_image);
+      if (windows->image.orphan != MagickFalse)
+        return;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      return;
+    }
+    case CutCommand:
+    case PasteCommand:
+    case ApplyCommand:
+    case HalfSizeCommand:
+    case OriginalSizeCommand:
+    case DoubleSizeCommand:
+    case ResizeCommand:
+    case TrimCommand:
+    case CropCommand:
+    case ChopCommand:
+    case FlipCommand:
+    case FlopCommand:
+    case RotateRightCommand:
+    case RotateLeftCommand:
+    case RotateCommand:
+    case ShearCommand:
+    case RollCommand:
+    case NegateCommand:
+    case ContrastStretchCommand:
+    case SigmoidalContrastCommand:
+    case NormalizeCommand:
+    case EqualizeCommand:
+    case HueCommand:
+    case SaturationCommand:
+    case BrightnessCommand:
+    case GammaCommand:
+    case SpiffCommand:
+    case DullCommand:
+    case GrayscaleCommand:
+    case MapCommand:
+    case QuantizeCommand:
+    case DespeckleCommand:
+    case EmbossCommand:
+    case ReduceNoiseCommand:
+    case AddNoiseCommand:
+    case SharpenCommand:
+    case BlurCommand:
+    case ThresholdCommand:
+    case EdgeDetectCommand:
+    case SpreadCommand:
+    case ShadeCommand:
+    case RaiseCommand:
+    case SegmentCommand:
+    case SolarizeCommand:
+    case SepiaToneCommand:
+    case SwirlCommand:
+    case ImplodeCommand:
+    case VignetteCommand:
+    case WaveCommand:
+    case OilPaintCommand:
+    case CharcoalDrawCommand:
+    case AnnotateCommand:
+    case AddBorderCommand:
+    case AddFrameCommand:
+    case CompositeCommand:
+    case CommentCommand:
+    case LaunchCommand:
+    case RegionofInterestCommand:
+    case SaveToUndoBufferCommand:
+    case RedoCommand:
+    {
+      Image
+        *previous_image;
+
+      ssize_t
+        bytes;
+
+      bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
+      if (undo_image != (Image *) NULL)
+        {
+          /*
+            Ensure the undo cache has enough memory available.
+          */
+          previous_image=undo_image;
+          while (previous_image != (Image *) NULL)
+          {
+            bytes+=previous_image->list->columns*previous_image->list->rows*
+              sizeof(PixelPacket);
+            if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
+              {
+                previous_image=GetPreviousImageInList(previous_image);
+                continue;
+              }
+            bytes-=previous_image->list->columns*previous_image->list->rows*
+              sizeof(PixelPacket);
+            if (previous_image == undo_image)
+              undo_image=NewImageList();
+            else
+              previous_image->next->previous=NewImageList();
+            break;
+          }
+          while (previous_image != (Image *) NULL)
+          {
+            /*
+              Delete any excess memory from undo cache.
+            */
+            cache_image=previous_image;
+            previous_image=GetPreviousImageInList(previous_image);
+            cache_image->list=DestroyImage(cache_image->list);
+            cache_image=DestroyImage(cache_image);
+          }
+        }
+      if (bytes > (ssize_t) (resource_info->undo_cache << 20))
+        break;
+      /*
+        Save image before transformations are applied.
+      */
+      cache_image=AcquireImage((ImageInfo *) NULL);
+      if (cache_image == (Image *) NULL)
+        break;
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (cache_image->list == (Image *) NULL)
+        {
+          cache_image=DestroyImage(cache_image);
+          break;
+        }
+      cache_image->columns=(size_t) windows->image.ximage->width;
+      cache_image->rows=(size_t) windows->image.ximage->height;
+      cache_image->geometry=windows->image.crop_geometry;
+      if (windows->image.crop_geometry != (char *) NULL)
+        {
+          cache_image->geometry=AcquireString((char *) NULL);
+          (void) CopyMagickString(cache_image->geometry,
+            windows->image.crop_geometry,MaxTextExtent);
+        }
+      if (undo_image == (Image *) NULL)
+        {
+          undo_image=cache_image;
+          break;
+        }
+      undo_image->next=cache_image;
+      undo_image->next->previous=undo_image;
+      undo_image=undo_image->next;
+      break;
+    }
+    default:
+      break;
+  }
+  if (command == RedoCommand)
+    {
+      /*
+        Redo the last image transformation.
+      */
+      if (redo_image == (Image *) NULL)
+        {
+          (void) XBell(display,0);
+          return;
+        }
+      windows->image.window_changes.width=(int) redo_image->columns;
+      windows->image.window_changes.height=(int) redo_image->rows;
+      if (windows->image.crop_geometry != (char *) NULL)
+        windows->image.crop_geometry=(char *)
+          RelinquishMagickMemory(windows->image.crop_geometry);
+      windows->image.crop_geometry=redo_image->geometry;
+      *image=DestroyImage(*image);
+      *image=redo_image;
+      redo_image=NewImageList();
+      if (windows->image.orphan != MagickFalse)
+        return;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      return;
+    }
+  if (command != InfoCommand)
+    return;
+  /*
+    Display image info.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
+  XSetCursorState(display,windows,MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X I m a g e W i n d o w C o m m a n d                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XImageWindowCommand() makes a transform to the image or Image window as
+%  specified by a user menu button or keyboard command.
+%
+%  The format of the XMagickCommand method is:
+%
+%      CommandType XImageWindowCommand(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,
+%        const MagickStatusType state,KeySym key_symbol,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o nexus:  Method XImageWindowCommand returns an image when the
+%      user chooses 'Open Image' from the command menu.  Otherwise a null
+%      image is returned.
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o state: key mask.
+%
+%    o key_symbol: Specifies a command to perform.
+%
+%    o image: the image;  XImageWIndowCommand
+%      may transform the image and return a new image pointer.
+%
+*/
+static CommandType XImageWindowCommand(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
+  KeySym key_symbol,Image **image)
+{
+  static char
+    delta[MaxTextExtent] = "";
+
+  static const char
+    Digits[] = "01234567890";
+
+  static KeySym
+    last_symbol = XK_0;
+
+  if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
+    {
+      if (((last_symbol < XK_0) || (last_symbol > XK_9)))
+        {
+          *delta='\0';
+          resource_info->quantum=1;
+        }
+      last_symbol=key_symbol;
+      delta[strlen(delta)+1]='\0';
+      delta[strlen(delta)]=Digits[key_symbol-XK_0];
+      resource_info->quantum=StringToLong(delta);
+      return(NullCommand);
+    }
+  last_symbol=key_symbol;
+  if (resource_info->immutable)
+    {
+      /*
+        Virtual image window has a restricted command set.
+      */
+      switch (key_symbol)
+      {
+        case XK_question:
+          return(InfoCommand);
+        case XK_p:
+        case XK_Print:
+          return(PrintCommand);
+        case XK_space:
+          return(NextCommand);
+        case XK_q:
+        case XK_Escape:
+          return(QuitCommand);
+        default:
+          break;
+      }
+      return(NullCommand);
+    }
+  switch ((int) key_symbol)
+  {
+    case XK_o:
+    {
+      if ((state & ControlMask) == 0)
+        break;
+      return(OpenCommand);
+    }
+    case XK_space:
+      return(NextCommand);
+    case XK_BackSpace:
+      return(FormerCommand);
+    case XK_s:
+    {
+      if ((state & Mod1Mask) != 0)
+        return(SwirlCommand);
+      if ((state & ControlMask) == 0)
+        return(ShearCommand);
+      return(SaveCommand);
+    }
+    case XK_p:
+    case XK_Print:
+    {
+      if ((state & Mod1Mask) != 0)
+        return(OilPaintCommand);
+      if ((state & Mod4Mask) != 0)
+        return(ColorCommand);
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(PrintCommand);
+    }
+    case XK_d:
+    {
+      if ((state & Mod4Mask) != 0)
+        return(DrawCommand);
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(DeleteCommand);
+    }
+    case XK_Select:
+    {
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(SelectCommand);
+    }
+    case XK_n:
+    {
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(NewCommand);
+    }
+    case XK_q:
+    case XK_Escape:
+      return(QuitCommand);
+    case XK_z:
+    case XK_Undo:
+    {
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(UndoCommand);
+    }
+    case XK_r:
+    case XK_Redo:
+    {
+      if ((state & ControlMask) == 0)
+        return(RollCommand);
+      return(RedoCommand);
+    }
+    case XK_x:
+    {
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(CutCommand);
+    }
+    case XK_c:
+    {
+      if ((state & Mod1Mask) != 0)
+        return(CharcoalDrawCommand);
+      if ((state & ControlMask) == 0)
+        return(CropCommand);
+      return(CopyCommand);
+    }
+    case XK_v:
+    case XK_Insert:
+    {
+      if ((state & Mod4Mask) != 0)
+        return(CompositeCommand);
+      if ((state & ControlMask) == 0)
+        return(FlipCommand);
+      return(PasteCommand);
+    }
+    case XK_less:
+      return(HalfSizeCommand);
+    case XK_minus:
+      return(OriginalSizeCommand);
+    case XK_greater:
+      return(DoubleSizeCommand);
+    case XK_percent:
+      return(ResizeCommand);
+    case XK_at:
+      return(RefreshCommand);
+    case XK_bracketleft:
+      return(ChopCommand);
+    case XK_h:
+      return(FlopCommand);
+    case XK_slash:
+      return(RotateRightCommand);
+    case XK_backslash:
+      return(RotateLeftCommand);
+    case XK_asterisk:
+      return(RotateCommand);
+    case XK_t:
+      return(TrimCommand);
+    case XK_H:
+      return(HueCommand);
+    case XK_S:
+      return(SaturationCommand);
+    case XK_L:
+      return(BrightnessCommand);
+    case XK_G:
+      return(GammaCommand);
+    case XK_C:
+      return(SpiffCommand);
+    case XK_Z:
+      return(DullCommand);
+    case XK_N:
+      return(NormalizeCommand);
+    case XK_equal:
+      return(EqualizeCommand);
+    case XK_asciitilde:
+      return(NegateCommand);
+    case XK_period:
+      return(GrayscaleCommand);
+    case XK_numbersign:
+      return(QuantizeCommand);
+    case XK_F2:
+      return(DespeckleCommand);
+    case XK_F3:
+      return(EmbossCommand);
+    case XK_F4:
+      return(ReduceNoiseCommand);
+    case XK_F5:
+      return(AddNoiseCommand);
+    case XK_F6:
+      return(SharpenCommand);
+    case XK_F7:
+      return(BlurCommand);
+    case XK_F8:
+      return(ThresholdCommand);
+    case XK_F9:
+      return(EdgeDetectCommand);
+    case XK_F10:
+      return(SpreadCommand);
+    case XK_F11:
+      return(ShadeCommand);
+    case XK_F12:
+      return(RaiseCommand);
+    case XK_F13:
+      return(SegmentCommand);
+    case XK_i:
+    {
+      if ((state & Mod1Mask) == 0)
+        return(NullCommand);
+      return(ImplodeCommand);
+    }
+    case XK_w:
+    {
+      if ((state & Mod1Mask) == 0)
+        return(NullCommand);
+      return(WaveCommand);
+    }
+    case XK_m:
+    {
+      if ((state & Mod4Mask) == 0)
+        return(NullCommand);
+      return(MatteCommand);
+    }
+    case XK_b:
+    {
+      if ((state & Mod4Mask) == 0)
+        return(NullCommand);
+      return(AddBorderCommand);
+    }
+    case XK_f:
+    {
+      if ((state & Mod4Mask) == 0)
+        return(NullCommand);
+      return(AddFrameCommand);
+    }
+    case XK_exclam:
+    {
+      if ((state & Mod4Mask) == 0)
+        return(NullCommand);
+      return(CommentCommand);
+    }
+    case XK_a:
+    {
+      if ((state & Mod1Mask) != 0)
+        return(ApplyCommand);
+      if ((state & Mod4Mask) != 0)
+        return(AnnotateCommand);
+      if ((state & ControlMask) == 0)
+        return(NullCommand);
+      return(RegionofInterestCommand);
+    }
+    case XK_question:
+      return(InfoCommand);
+    case XK_plus:
+      return(ZoomCommand);
+    case XK_P:
+    {
+      if ((state & ShiftMask) == 0)
+        return(NullCommand);
+      return(ShowPreviewCommand);
+    }
+    case XK_Execute:
+      return(LaunchCommand);
+    case XK_F1:
+      return(HelpCommand);
+    case XK_Find:
+      return(BrowseDocumentationCommand);
+    case XK_Menu:
+    {
+      (void) XMapRaised(display,windows->command.id);
+      return(NullCommand);
+    }
+    case XK_Next:
+    case XK_Prior:
+    case XK_Home:
+    case XK_KP_Home:
+    {
+      XTranslateImage(display,windows,*image,key_symbol);
+      return(NullCommand);
+    }
+    case XK_Up:
+    case XK_KP_Up:
+    case XK_Down:
+    case XK_KP_Down:
+    case XK_Left:
+    case XK_KP_Left:
+    case XK_Right:
+    case XK_KP_Right:
+    {
+      if ((state & Mod1Mask) != 0)
+        {
+          RectangleInfo
+            crop_info;
+
+          /*
+            Trim one pixel from edge of image.
+          */
+          crop_info.x=0;
+          crop_info.y=0;
+          crop_info.width=(size_t) windows->image.ximage->width;
+          crop_info.height=(size_t) windows->image.ximage->height;
+          if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
+            {
+              if (resource_info->quantum >= (int) crop_info.height)
+                resource_info->quantum=(int) crop_info.height-1;
+              crop_info.height-=resource_info->quantum;
+            }
+          if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
+            {
+              if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
+                resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
+              crop_info.y+=resource_info->quantum;
+              crop_info.height-=resource_info->quantum;
+            }
+          if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
+            {
+              if (resource_info->quantum >= (int) crop_info.width)
+                resource_info->quantum=(int) crop_info.width-1;
+              crop_info.width-=resource_info->quantum;
+            }
+          if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
+            {
+              if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
+                resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
+              crop_info.x+=resource_info->quantum;
+              crop_info.width-=resource_info->quantum;
+            }
+          if ((int) (windows->image.x+windows->image.width) >
+              (int) crop_info.width)
+            windows->image.x=(int) (crop_info.width-windows->image.width);
+          if ((int) (windows->image.y+windows->image.height) >
+              (int) crop_info.height)
+            windows->image.y=(int) (crop_info.height-windows->image.height);
+          XSetCropGeometry(display,windows,&crop_info,*image);
+          windows->image.window_changes.width=(int) crop_info.width;
+          windows->image.window_changes.height=(int) crop_info.height;
+          (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
+          (void) XConfigureImage(display,resource_info,windows,*image);
+          return(NullCommand);
+        }
+      XTranslateImage(display,windows,*image,key_symbol);
+      return(NullCommand);
+    }
+    default:
+      return(NullCommand);
+  }
+  return(NullCommand);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a g i c k C o m m a n d                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMagickCommand() makes a transform to the image or Image window as
+%  specified by a user menu button or keyboard command.
+%
+%  The format of the XMagickCommand method is:
+%
+%      Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
+%        XWindows *windows,const CommandType command,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o nexus:  Method XMagickCommand returns an image when the
+%      user chooses 'Load Image' from the command menu.  Otherwise a null
+%      image is returned.
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o command: Specifies a command to perform.
+%
+%    o image: the image;  XMagickCommand
+%      may transform the image and return a new image pointer.
+%
+*/
+static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
+  XWindows *windows,const CommandType command,Image **image)
+{
+  char
+    filename[MaxTextExtent],
+    geometry[MaxTextExtent],
+    modulate_factors[MaxTextExtent];
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *nexus;
+
+  ImageInfo
+    *image_info;
+
+  int
+    x,
+    y;
+
+  MagickStatusType
+    flags,
+    status;
+
+  QuantizeInfo
+    quantize_info;
+
+  RectangleInfo
+    page_geometry;
+
+  register int
+    i;
+
+  static char
+    color[MaxTextExtent] = "gray";
+
+  unsigned int
+    height,
+    width;
+
+  /*
+    Process user command.
+  */
+  XCheckRefreshWindows(display,windows);
+  XImageCache(display,resource_info,windows,command,image);
+  nexus=NewImageList();
+  windows->image.window_changes.width=windows->image.ximage->width;
+  windows->image.window_changes.height=windows->image.ximage->height;
+  image_info=CloneImageInfo(resource_info->image_info);
+  SetGeometryInfo(&geometry_info);
+  GetQuantizeInfo(&quantize_info);
+  switch (command)
+  {
+    case OpenCommand:
+    {
+      /*
+        Load image.
+      */
+      nexus=XOpenImage(display,resource_info,windows,MagickFalse);
+      break;
+    }
+    case NextCommand:
+    {
+      /*
+        Display next image.
+      */
+      for (i=0; i < resource_info->quantum; i++)
+        XClientMessage(display,windows->image.id,windows->im_protocols,
+          windows->im_next_image,CurrentTime);
+      break;
+    }
+    case FormerCommand:
+    {
+      /*
+        Display former image.
+      */
+      for (i=0; i < resource_info->quantum; i++)
+        XClientMessage(display,windows->image.id,windows->im_protocols,
+          windows->im_former_image,CurrentTime);
+      break;
+    }
+    case SelectCommand:
+    {
+      int
+        status;
+
+      /*
+        Select image.
+      */
+      status=chdir(resource_info->home_directory);
+      if (status == -1)
+        (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
+          FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
+      nexus=XOpenImage(display,resource_info,windows,MagickTrue);
+      break;
+    }
+    case SaveCommand:
+    {
+      /*
+        Save image.
+      */
+      status=XSaveImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to write X image:",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case PrintCommand:
+    {
+      /*
+        Print image.
+      */
+      status=XPrintImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to print X image:",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case DeleteCommand:
+    {
+      static char
+        filename[MaxTextExtent] = "\0";
+
+      /*
+        Delete image file.
+      */
+      XFileBrowserWidget(display,windows,"Delete",filename);
+      if (*filename == '\0')
+        break;
+      status=remove(filename) != 0 ? MagickTrue : MagickFalse;
+      if (status != MagickFalse)
+        XNoticeWidget(display,windows,"Unable to delete image file:",filename);
+      break;
+    }
+    case NewCommand:
+    {
+      int
+        status;
+
+      static char
+        color[MaxTextExtent] = "gray",
+        geometry[MaxTextExtent] = "640x480";
+
+      static const char
+        *format = "gradient";
+
+      /*
+        Query user for canvas geometry.
+      */
+      status=XDialogWidget(display,windows,"New","Enter image geometry:",
+        geometry);
+      if (*geometry == '\0')
+        break;
+      if (status == 0)
+        format="xc";
+      XColorBrowserWidget(display,windows,"Select",color);
+      if (*color == '\0')
+        break;
+      /*
+        Create canvas.
+      */
+      (void) FormatLocaleString(image_info->filename,MaxTextExtent,
+        "%s:%s",format,color);
+      (void) CloneString(&image_info->size,geometry);
+      nexus=ReadImage(image_info,&(*image)->exception);
+      CatchException(&(*image)->exception);
+      XClientMessage(display,windows->image.id,windows->im_protocols,
+        windows->im_next_image,CurrentTime);
+      break;
+    }
+    case VisualDirectoryCommand:
+    {
+      /*
+        Visual Image directory.
+      */
+      nexus=XVisualDirectoryImage(display,resource_info,windows);
+      break;
+    }
+    case QuitCommand:
+    {
+      /*
+        exit program.
+      */
+      if (resource_info->confirm_exit == MagickFalse)
+        XClientMessage(display,windows->image.id,windows->im_protocols,
+          windows->im_exit,CurrentTime);
+      else
+        {
+          int
+            status;
+
+          /*
+            Confirm program exit.
+          */
+          status=XConfirmWidget(display,windows,"Do you really want to exit",
+            resource_info->client_name);
+          if (status > 0)
+            XClientMessage(display,windows->image.id,windows->im_protocols,
+              windows->im_exit,CurrentTime);
+        }
+      break;
+    }
+    case CutCommand:
+    {
+      /*
+        Cut image.
+      */
+      (void) XCropImage(display,resource_info,windows,*image,CutMode);
+      break;
+    }
+    case CopyCommand:
+    {
+      /*
+        Copy image.
+      */
+      (void) XCropImage(display,resource_info,windows,*image,CopyMode);
+      break;
+    }
+    case PasteCommand:
+    {
+      /*
+        Paste image.
+      */
+      status=XPasteImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to paste X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case HalfSizeCommand:
+    {
+      /*
+        Half image size.
+      */
+      windows->image.window_changes.width=windows->image.ximage->width/2;
+      windows->image.window_changes.height=windows->image.ximage->height/2;
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case OriginalSizeCommand:
+    {
+      /*
+        Original image size.
+      */
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case DoubleSizeCommand:
+    {
+      /*
+        Double the image size.
+      */
+      windows->image.window_changes.width=windows->image.ximage->width << 1;
+      windows->image.window_changes.height=windows->image.ximage->height << 1;
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ResizeCommand:
+    {
+      int
+        status;
+
+      size_t
+        height,
+        width;
+
+      ssize_t
+        x,
+        y;
+
+      /*
+        Resize image.
+      */
+      width=(size_t) windows->image.ximage->width;
+      height=(size_t) windows->image.ximage->height;
+      x=0;
+      y=0;
+      (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
+        (double) width,(double) height);
+      status=XDialogWidget(display,windows,"Resize",
+        "Enter resize geometry (e.g. 640x480, 200%):",geometry);
+      if (*geometry == '\0')
+        break;
+      if (status == 0)
+        (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
+      (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
+      windows->image.window_changes.width=(int) width;
+      windows->image.window_changes.height=(int) height;
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ApplyCommand:
+    {
+      char
+        image_geometry[MaxTextExtent];
+
+      if ((windows->image.crop_geometry == (char *) NULL) &&
+          ((int) (*image)->columns == windows->image.ximage->width) &&
+          ((int) (*image)->rows == windows->image.ximage->height))
+        break;
+      /*
+        Apply size transforms to image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      /*
+        Crop and/or scale displayed image.
+      */
+      (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
+        windows->image.ximage->width,windows->image.ximage->height);
+      (void) TransformImage(image,windows->image.crop_geometry,image_geometry);
+      if (windows->image.crop_geometry != (char *) NULL)
+        windows->image.crop_geometry=(char *)
+          RelinquishMagickMemory(windows->image.crop_geometry);
+      windows->image.x=0;
+      windows->image.y=0;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case RefreshCommand:
+    {
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case RestoreCommand:
+    {
+      /*
+        Restore Image window to its original size.
+      */
+      if ((windows->image.width == (unsigned int) (*image)->columns) &&
+          (windows->image.height == (unsigned int) (*image)->rows) &&
+          (windows->image.crop_geometry == (char *) NULL))
+        {
+          (void) XBell(display,0);
+          break;
+        }
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      if (windows->image.crop_geometry != (char *) NULL)
+        {
+          windows->image.crop_geometry=(char *)
+            RelinquishMagickMemory(windows->image.crop_geometry);
+          windows->image.crop_geometry=(char *) NULL;
+          windows->image.x=0;
+          windows->image.y=0;
+        }
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case CropCommand:
+    {
+      /*
+        Crop image.
+      */
+      (void) XCropImage(display,resource_info,windows,*image,CropMode);
+      break;
+    }
+    case ChopCommand:
+    {
+      /*
+        Chop image.
+      */
+      status=XChopImage(display,resource_info,windows,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to cut X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case FlopCommand:
+    {
+      Image
+        *flop_image;
+
+      /*
+        Flop image scanlines.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flop_image=FlopImage(*image,&(*image)->exception);
+      if (flop_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=flop_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.crop_geometry != (char *) NULL)
+        {
+          /*
+            Flop crop geometry.
+          */
+          width=(unsigned int) (*image)->columns;
+          height=(unsigned int) (*image)->rows;
+          (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
+            &width,&height);
+          (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
+            "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
+        }
+      if (windows->image.orphan != MagickFalse)
+        break;
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case FlipCommand:
+    {
+      Image
+        *flip_image;
+
+      /*
+        Flip image scanlines.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flip_image=FlipImage(*image,&(*image)->exception);
+      if (flip_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=flip_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.crop_geometry != (char *) NULL)
+        {
+          /*
+            Flip crop geometry.
+          */
+          width=(unsigned int) (*image)->columns;
+          height=(unsigned int) (*image)->rows;
+          (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
+            &width,&height);
+          (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
+            "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
+        }
+      if (windows->image.orphan != MagickFalse)
+        break;
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case RotateRightCommand:
+    {
+      /*
+        Rotate image 90 degrees clockwise.
+      */
+      status=XRotateImage(display,resource_info,windows,90.0,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to rotate X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case RotateLeftCommand:
+    {
+      /*
+        Rotate image 90 degrees counter-clockwise.
+      */
+      status=XRotateImage(display,resource_info,windows,-90.0,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to rotate X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case RotateCommand:
+    {
+      /*
+        Rotate image.
+      */
+      status=XRotateImage(display,resource_info,windows,0.0,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to rotate X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case ShearCommand:
+    {
+      Image
+        *shear_image;
+
+      static char
+        geometry[MaxTextExtent] = "45.0x45.0";
+
+      /*
+        Query user for shear color and geometry.
+      */
+      XColorBrowserWidget(display,windows,"Select",color);
+      if (*color == '\0')
+        break;
+      (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
+        geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Shear image.
+      */
+      (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) QueryColorDatabase(color,&(*image)->background_color,
+        &(*image)->exception);
+      flags=ParseGeometry(geometry,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=geometry_info.rho;
+      shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
+        &(*image)->exception);
+      if (shear_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=shear_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case RollCommand:
+    {
+      Image
+        *roll_image;
+
+      static char
+        geometry[MaxTextExtent] = "+2+2";
+
+      /*
+        Query user for the roll geometry.
+      */
+      (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
+        geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Roll image.
+      */
+      (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) ParsePageGeometry(*image,geometry,&page_geometry,
+        &(*image)->exception);
+      roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
+        &(*image)->exception);
+      if (roll_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=roll_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case TrimCommand:
+    {
+      static char
+        fuzz[MaxTextExtent];
+
+      /*
+        Query user for the fuzz factor.
+      */
+      (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
+        (*image)->fuzz/(QuantumRange+1.0));
+      (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
+      if (*fuzz == '\0')
+        break;
+      (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0);
+      /*
+        Trim image.
+      */
+      status=XTrimImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to trim X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case HueCommand:
+    {
+      static char
+        hue_percent[MaxTextExtent] = "110";
+
+      /*
+        Query user for percent hue change.
+      */
+      (void) XDialogWidget(display,windows,"Apply",
+        "Enter percent change in image hue (0-200):",hue_percent);
+      if (*hue_percent == '\0')
+        break;
+      /*
+        Vary the image hue.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
+      (void) ConcatenateMagickString(modulate_factors,hue_percent,
+        MaxTextExtent);
+      (void) ModulateImage(*image,modulate_factors);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SaturationCommand:
+    {
+      static char
+        saturation_percent[MaxTextExtent] = "110";
+
+      /*
+        Query user for percent saturation change.
+      */
+      (void) XDialogWidget(display,windows,"Apply",
+        "Enter percent change in color saturation (0-200):",saturation_percent);
+      if (*saturation_percent == '\0')
+        break;
+      /*
+        Vary color saturation.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
+      (void) ConcatenateMagickString(modulate_factors,saturation_percent,
+        MaxTextExtent);
+      (void) ModulateImage(*image,modulate_factors);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case BrightnessCommand:
+    {
+      static char
+        brightness_percent[MaxTextExtent] = "110";
+
+      /*
+        Query user for percent brightness change.
+      */
+      (void) XDialogWidget(display,windows,"Apply",
+        "Enter percent change in color brightness (0-200):",brightness_percent);
+      if (*brightness_percent == '\0')
+        break;
+      /*
+        Vary the color brightness.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) CopyMagickString(modulate_factors,brightness_percent,
+        MaxTextExtent);
+      (void) ModulateImage(*image,modulate_factors);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case GammaCommand:
+    {
+      static char
+        factor[MaxTextExtent] = "1.6";
+
+      /*
+        Query user for gamma value.
+      */
+      (void) XDialogWidget(display,windows,"Gamma",
+        "Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
+      if (*factor == '\0')
+        break;
+      /*
+        Gamma correct image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) GammaImage(*image,factor);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SpiffCommand:
+    {
+      /*
+        Sharpen the image contrast.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) ContrastImage(*image,MagickTrue);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case DullCommand:
+    {
+      /*
+        Dull the image contrast.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) ContrastImage(*image,MagickFalse);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ContrastStretchCommand:
+    {
+      double
+        black_point,
+        white_point;
+
+      static char
+        levels[MaxTextExtent] = "1%";
+
+      /*
+        Query user for gamma value.
+      */
+      (void) XDialogWidget(display,windows,"Contrast Stretch",
+        "Enter black and white points:",levels);
+      if (*levels == '\0')
+        break;
+      /*
+        Contrast stretch image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(levels,&geometry_info);
+      black_point=geometry_info.rho;
+      white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
+      if ((flags & PercentValue) != 0)
+        {
+          black_point*=(double) (*image)->columns*(*image)->rows/100.0;
+          white_point*=(double) (*image)->columns*(*image)->rows/100.0;
+        }
+      white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
+      (void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
+        white_point);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SigmoidalContrastCommand:
+    {
+      static char
+        levels[MaxTextExtent] = "3x50%";
+
+      /*
+        Query user for gamma value.
+      */
+      (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
+        "Enter contrast and midpoint:",levels);
+      if (*levels == '\0')
+        break;
+      /*
+        Contrast stretch image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) SigmoidalContrastImage(*image,MagickTrue,levels);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case NormalizeCommand:
+    {
+      /*
+        Perform histogram normalization on the image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) NormalizeImage(*image);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case EqualizeCommand:
+    {
+      /*
+        Perform histogram equalization on the image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) EqualizeImage(*image);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case NegateCommand:
+    {
+      /*
+        Negate colors in image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) NegateImage(*image,MagickFalse);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case GrayscaleCommand:
+    {
+      /*
+        Convert image to grayscale.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) SetImageType(*image,(*image)->matte == MagickFalse ?
+        GrayscaleType : GrayscaleMatteType);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case MapCommand:
+    {
+      Image
+        *affinity_image;
+
+      static char
+        filename[MaxTextExtent] = "\0";
+
+      /*
+        Request image file name from user.
+      */
+      XFileBrowserWidget(display,windows,"Map",filename);
+      if (*filename == '\0')
+        break;
+      /*
+        Map image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+      affinity_image=ReadImage(image_info,&(*image)->exception);
+      if (affinity_image != (Image *) NULL)
+        {
+          (void) RemapImage(&quantize_info,*image,affinity_image);
+          affinity_image=DestroyImage(affinity_image);
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case QuantizeCommand:
+    {
+      int
+        status;
+
+      static char
+        colors[MaxTextExtent] = "256";
+
+      /*
+        Query user for maximum number of colors.
+      */
+      status=XDialogWidget(display,windows,"Quantize",
+        "Maximum number of colors:",colors);
+      if (*colors == '\0')
+        break;
+      /*
+        Color reduce the image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      quantize_info.number_colors=StringToUnsignedLong(colors);
+      quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
+      (void) QuantizeImage(&quantize_info,*image);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case DespeckleCommand:
+    {
+      Image
+        *despeckle_image;
+
+      /*
+        Despeckle image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      despeckle_image=DespeckleImage(*image,&(*image)->exception);
+      if (despeckle_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=despeckle_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case EmbossCommand:
+    {
+      Image
+        *emboss_image;
+
+      static char
+        radius[MaxTextExtent] = "0.0x1.0";
+
+      /*
+        Query user for emboss radius.
+      */
+      (void) XDialogWidget(display,windows,"Emboss",
+        "Enter the emboss radius and standard deviation:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        Reduce noise in the image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=1.0;
+      emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
+        &(*image)->exception);
+      if (emboss_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=emboss_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ReduceNoiseCommand:
+    {
+      Image
+        *noise_image;
+
+      static char
+        radius[MaxTextExtent] = "0";
+
+      /*
+        Query user for noise radius.
+      */
+      (void) XDialogWidget(display,windows,"Reduce Noise",
+        "Enter the noise radius:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        Reduce noise in the image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
+        geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception);
+      if (noise_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=noise_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case AddNoiseCommand:
+    {
+      char
+        **noises;
+
+      Image
+        *noise_image;
+
+      static char
+        noise_type[MaxTextExtent] = "Gaussian";
+
+      /*
+        Add noise to the image.
+      */
+      noises=GetCommandOptions(MagickNoiseOptions);
+      if (noises == (char **) NULL)
+        break;
+      XListBrowserWidget(display,windows,&windows->widget,
+        (const char **) noises,"Add Noise",
+        "Select a type of noise to add to your image:",noise_type);
+      noises=DestroyStringList(noises);
+      if (*noise_type == '\0')
+        break;
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
+        MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
+      if (noise_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=noise_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SharpenCommand:
+    {
+      Image
+        *sharp_image;
+
+      static char
+        radius[MaxTextExtent] = "0.0x1.0";
+
+      /*
+        Query user for sharpen radius.
+      */
+      (void) XDialogWidget(display,windows,"Sharpen",
+        "Enter the sharpen radius and standard deviation:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        Sharpen image scanlines.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
+        &(*image)->exception);
+      if (sharp_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=sharp_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case BlurCommand:
+    {
+      Image
+        *blur_image;
+
+      static char
+        radius[MaxTextExtent] = "0.0x1.0";
+
+      /*
+        Query user for blur radius.
+      */
+      (void) XDialogWidget(display,windows,"Blur",
+        "Enter the blur radius and standard deviation:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        Blur an image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
+        &(*image)->exception);
+      if (blur_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=blur_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ThresholdCommand:
+    {
+      double
+        threshold;
+
+      static char
+        factor[MaxTextExtent] = "128";
+
+      /*
+        Query user for threshold value.
+      */
+      (void) XDialogWidget(display,windows,"Threshold",
+        "Enter threshold value:",factor);
+      if (*factor == '\0')
+        break;
+      /*
+        Gamma correct image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      threshold=SiPrefixToDouble(factor,QuantumRange);
+      (void) BilevelImage(*image,threshold);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case EdgeDetectCommand:
+    {
+      Image
+        *edge_image;
+
+      static char
+        radius[MaxTextExtent] = "0";
+
+      /*
+        Query user for edge factor.
+      */
+      (void) XDialogWidget(display,windows,"Detect Edges",
+        "Enter the edge detect radius:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        Detect edge in image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
+      if (edge_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=edge_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SpreadCommand:
+    {
+      Image
+        *spread_image;
+
+      static char
+        amount[MaxTextExtent] = "2";
+
+      /*
+        Query user for spread amount.
+      */
+      (void) XDialogWidget(display,windows,"Spread",
+        "Enter the displacement amount:",amount);
+      if (*amount == '\0')
+        break;
+      /*
+        Displace image pixels by a random amount.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(amount,&geometry_info);
+      spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
+      if (spread_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=spread_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ShadeCommand:
+    {
+      Image
+        *shade_image;
+
+      int
+        status;
+
+      static char
+        geometry[MaxTextExtent] = "30x30";
+
+      /*
+        Query user for the shade geometry.
+      */
+      status=XDialogWidget(display,windows,"Shade",
+        "Enter the azimuth and elevation of the light source:",geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Shade image pixels.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(geometry,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=1.0;
+      shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
+        geometry_info.rho,geometry_info.sigma,&(*image)->exception);
+      if (shade_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=shade_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case RaiseCommand:
+    {
+      static char
+        bevel_width[MaxTextExtent] = "10";
+
+      /*
+        Query user for bevel width.
+      */
+      (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
+      if (*bevel_width == '\0')
+        break;
+      /*
+        Raise an image.
+      */
+      (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
+        &(*image)->exception);
+      (void) RaiseImage(*image,&page_geometry,MagickTrue);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SegmentCommand:
+    {
+      static char
+        threshold[MaxTextExtent] = "1.0x1.5";
+
+      /*
+        Query user for smoothing threshold.
+      */
+      (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
+        threshold);
+      if (*threshold == '\0')
+        break;
+      /*
+        Segment an image.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(threshold,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=1.0;
+      (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho,
+        geometry_info.sigma);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SepiaToneCommand:
+    {
+      double
+        threshold;
+
+      Image
+        *sepia_image;
+
+      static char
+        factor[MaxTextExtent] = "80%";
+
+      /*
+        Query user for sepia-tone factor.
+      */
+      (void) XDialogWidget(display,windows,"Sepia Tone",
+        "Enter the sepia tone factor (0 - 99.9%):",factor);
+      if (*factor == '\0')
+        break;
+      /*
+        Sepia tone image pixels.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      threshold=SiPrefixToDouble(factor,QuantumRange);
+      sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
+      if (sepia_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=sepia_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SolarizeCommand:
+    {
+      double
+        threshold;
+
+      static char
+        factor[MaxTextExtent] = "60%";
+
+      /*
+        Query user for solarize factor.
+      */
+      (void) XDialogWidget(display,windows,"Solarize",
+        "Enter the solarize factor (0 - 99.9%):",factor);
+      if (*factor == '\0')
+        break;
+      /*
+        Solarize image pixels.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      threshold=SiPrefixToDouble(factor,QuantumRange);
+      (void) SolarizeImage(*image,threshold);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case SwirlCommand:
+    {
+      Image
+        *swirl_image;
+
+      static char
+        degrees[MaxTextExtent] = "60";
+
+      /*
+        Query user for swirl angle.
+      */
+      (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
+        degrees);
+      if (*degrees == '\0')
+        break;
+      /*
+        Swirl image pixels about the center.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(degrees,&geometry_info);
+      swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
+      if (swirl_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=swirl_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case ImplodeCommand:
+    {
+      Image
+        *implode_image;
+
+      static char
+        factor[MaxTextExtent] = "0.3";
+
+      /*
+        Query user for implode factor.
+      */
+      (void) XDialogWidget(display,windows,"Implode",
+        "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
+      if (*factor == '\0')
+        break;
+      /*
+        Implode image pixels about the center.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(factor,&geometry_info);
+      implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
+      if (implode_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=implode_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case VignetteCommand:
+    {
+      Image
+        *vignette_image;
+
+      static char
+        geometry[MaxTextExtent] = "0x20";
+
+      /*
+        Query user for the vignette geometry.
+      */
+      (void) XDialogWidget(display,windows,"Vignette",
+        "Enter the radius, sigma, and x and y offsets:",geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Soften the edges of the image in vignette style
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(geometry,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=1.0;
+      if ((flags & XiValue) == 0)
+        geometry_info.xi=0.1*(*image)->columns;
+      if ((flags & PsiValue) == 0)
+        geometry_info.psi=0.1*(*image)->rows;
+      vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
+        (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
+        0.5),&(*image)->exception);
+      if (vignette_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=vignette_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case WaveCommand:
+    {
+      Image
+        *wave_image;
+
+      static char
+        geometry[MaxTextExtent] = "25x150";
+
+      /*
+        Query user for the wave geometry.
+      */
+      (void) XDialogWidget(display,windows,"Wave",
+        "Enter the amplitude and length of the wave:",geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Alter an image along a sine wave.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(geometry,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=1.0;
+      wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
+        &(*image)->exception);
+      if (wave_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=wave_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case OilPaintCommand:
+    {
+      Image
+        *paint_image;
+
+      static char
+        radius[MaxTextExtent] = "0";
+
+      /*
+        Query user for circular neighborhood radius.
+      */
+      (void) XDialogWidget(display,windows,"Oil Paint",
+        "Enter the mask radius:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        OilPaint image scanlines.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
+      if (paint_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=paint_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case CharcoalDrawCommand:
+    {
+      Image
+        *charcoal_image;
+
+      static char
+        radius[MaxTextExtent] = "0x1";
+
+      /*
+        Query user for charcoal radius.
+      */
+      (void) XDialogWidget(display,windows,"Charcoal Draw",
+        "Enter the charcoal radius and sigma:",radius);
+      if (*radius == '\0')
+        break;
+      /*
+        Charcoal the image.
+      */
+      (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      flags=ParseGeometry(radius,&geometry_info);
+      if ((flags & SigmaValue) == 0)
+        geometry_info.sigma=geometry_info.rho;
+      charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
+        &(*image)->exception);
+      if (charcoal_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=charcoal_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case AnnotateCommand:
+    {
+      /*
+        Annotate the image with text.
+      */
+      status=XAnnotateEditImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to annotate X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case DrawCommand:
+    {
+      /*
+        Draw image.
+      */
+      status=XDrawEditImage(display,resource_info,windows,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to draw on the X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case ColorCommand:
+    {
+      /*
+        Color edit.
+      */
+      status=XColorEditImage(display,resource_info,windows,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to pixel edit X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case MatteCommand:
+    {
+      /*
+        Matte edit.
+      */
+      status=XMatteEditImage(display,resource_info,windows,image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to matte edit X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case CompositeCommand:
+    {
+      /*
+        Composite image.
+      */
+      status=XCompositeImage(display,resource_info,windows,*image);
+      if (status == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to composite X image",
+            (*image)->filename);
+          break;
+        }
+      break;
+    }
+    case AddBorderCommand:
+    {
+      Image
+        *border_image;
+
+      static char
+        geometry[MaxTextExtent] = "6x6";
+
+      /*
+        Query user for border color and geometry.
+      */
+      XColorBrowserWidget(display,windows,"Select",color);
+      if (*color == '\0')
+        break;
+      (void) XDialogWidget(display,windows,"Add Border",
+        "Enter border geometry:",geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Add a border to the image.
+      */
+      (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) QueryColorDatabase(color,&(*image)->border_color,
+        &(*image)->exception);
+      (void) ParsePageGeometry(*image,geometry,&page_geometry,
+        &(*image)->exception);
+      border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
+      if (border_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=border_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case AddFrameCommand:
+    {
+      FrameInfo
+        frame_info;
+
+      Image
+        *frame_image;
+
+      static char
+        geometry[MaxTextExtent] = "6x6";
+
+      /*
+        Query user for frame color and geometry.
+      */
+      XColorBrowserWidget(display,windows,"Select",color);
+      if (*color == '\0')
+        break;
+      (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
+        geometry);
+      if (*geometry == '\0')
+        break;
+      /*
+        Surround image with an ornamental border.
+      */
+      (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) QueryColorDatabase(color,&(*image)->matte_color,
+        &(*image)->exception);
+      (void) ParsePageGeometry(*image,geometry,&page_geometry,
+        &(*image)->exception);
+      frame_info.width=page_geometry.width;
+      frame_info.height=page_geometry.height;
+      frame_info.outer_bevel=page_geometry.x;
+      frame_info.inner_bevel=page_geometry.y;
+      frame_info.x=(ssize_t) frame_info.width;
+      frame_info.y=(ssize_t) frame_info.height;
+      frame_info.width=(*image)->columns+2*frame_info.width;
+      frame_info.height=(*image)->rows+2*frame_info.height;
+      frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
+      if (frame_image != (Image *) NULL)
+        {
+          *image=DestroyImage(*image);
+          *image=frame_image;
+        }
+      CatchException(&(*image)->exception);
+      XSetCursorState(display,windows,MagickFalse);
+      if (windows->image.orphan != MagickFalse)
+        break;
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      XConfigureImageColormap(display,resource_info,windows,*image);
+      (void) XConfigureImage(display,resource_info,windows,*image);
+      break;
+    }
+    case CommentCommand:
+    {
+      const char
+        *value;
+
+      FILE
+        *file;
+
+      int
+        unique_file;
+
+      /*
+        Edit image comment.
+      */
+      unique_file=AcquireUniqueFileResource(image_info->filename);
+      if (unique_file == -1)
+        XNoticeWidget(display,windows,"Unable to edit image comment",
+          image_info->filename);
+      value=GetImageProperty(*image,"comment");
+      if (value == (char *) NULL)
+        unique_file=close(unique_file)-1;
+      else
+        {
+          register const char
+            *p;
+
+          file=fdopen(unique_file,"w");
+          if (file == (FILE *) NULL)
+            {
+              XNoticeWidget(display,windows,"Unable to edit image comment",
+                image_info->filename);
+              break;
+            }
+          for (p=value; *p != '\0'; p++)
+            (void) fputc((int) *p,file);
+          (void) fputc('\n',file);
+          (void) fclose(file);
+        }
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
+        &(*image)->exception);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to edit image comment",
+          (char *) NULL);
+      else
+        {
+          char
+            *comment;
+
+          comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
+          if (comment != (char *) NULL)
+            {
+              (void) SetImageProperty(*image,"comment",comment);
+              (*image)->taint=MagickTrue;
+            }
+        }
+      (void) RelinquishUniqueFileResource(image_info->filename);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case LaunchCommand:
+    {
+      /*
+        Launch program.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
+        filename);
+      status=WriteImage(image_info,*image);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to launch image editor",
+          (char *) NULL);
+      else
+        {
+          nexus=ReadImage(resource_info->image_info,&(*image)->exception);
+          CatchException(&(*image)->exception);
+          XClientMessage(display,windows->image.id,windows->im_protocols,
+            windows->im_next_image,CurrentTime);
+        }
+      (void) RelinquishUniqueFileResource(filename);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case RegionofInterestCommand:
+    {
+      /*
+        Apply an image processing technique to a region of interest.
+      */
+      (void) XROIImage(display,resource_info,windows,image);
+      break;
+    }
+    case InfoCommand:
+      break;
+    case ZoomCommand:
+    {
+      /*
+        Zoom image.
+      */
+      if (windows->magnify.mapped != MagickFalse)
+        (void) XRaiseWindow(display,windows->magnify.id);
+      else
+        {
+          /*
+            Make magnify image.
+          */
+          XSetCursorState(display,windows,MagickTrue);
+          (void) XMapRaised(display,windows->magnify.id);
+          XSetCursorState(display,windows,MagickFalse);
+        }
+      break;
+    }
+    case ShowPreviewCommand:
+    {
+      char
+        **previews;
+
+      Image
+        *preview_image;
+
+      static char
+        preview_type[MaxTextExtent] = "Gamma";
+
+      /*
+        Select preview type from menu.
+      */
+      previews=GetCommandOptions(MagickPreviewOptions);
+      if (previews == (char **) NULL)
+        break;
+      XListBrowserWidget(display,windows,&windows->widget,
+        (const char **) previews,"Preview",
+        "Select an enhancement, effect, or F/X:",preview_type);
+      previews=DestroyStringList(previews);
+      if (*preview_type == '\0')
+        break;
+      /*
+        Show image preview.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      image_info->preview_type=(PreviewType)
+        ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
+      image_info->group=(ssize_t) windows->image.id;
+      (void) DeleteImageProperty(*image,"label");
+      (void) SetImageProperty(*image,"label","Preview");
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
+        filename);
+      status=WriteImage(image_info,*image);
+      (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+      preview_image=ReadImage(image_info,&(*image)->exception);
+      (void) RelinquishUniqueFileResource(filename);
+      if (preview_image == (Image *) NULL)
+        break;
+      (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
+        filename);
+      status=WriteImage(image_info,preview_image);
+      preview_image=DestroyImage(preview_image);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to show image preview",
+          (*image)->filename);
+      XDelay(display,1500);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case ShowHistogramCommand:
+    {
+      Image
+        *histogram_image;
+
+      /*
+        Show image histogram.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      image_info->group=(ssize_t) windows->image.id;
+      (void) DeleteImageProperty(*image,"label");
+      (void) SetImageProperty(*image,"label","Histogram");
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
+        filename);
+      status=WriteImage(image_info,*image);
+      (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+      histogram_image=ReadImage(image_info,&(*image)->exception);
+      (void) RelinquishUniqueFileResource(filename);
+      if (histogram_image == (Image *) NULL)
+        break;
+      (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
+        "show:%s",filename);
+      status=WriteImage(image_info,histogram_image);
+      histogram_image=DestroyImage(histogram_image);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to show histogram",
+          (*image)->filename);
+      XDelay(display,1500);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case ShowMatteCommand:
+    {
+      Image
+        *matte_image;
+
+      if ((*image)->matte == MagickFalse)
+        {
+          XNoticeWidget(display,windows,
+            "Image does not have any matte information",(*image)->filename);
+          break;
+        }
+      /*
+        Show image matte.
+      */
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      image_info->group=(ssize_t) windows->image.id;
+      (void) DeleteImageProperty(*image,"label");
+      (void) SetImageProperty(*image,"label","Matte");
+      (void) AcquireUniqueFilename(filename);
+      (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
+        filename);
+      status=WriteImage(image_info,*image);
+      (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+      matte_image=ReadImage(image_info,&(*image)->exception);
+      (void) RelinquishUniqueFileResource(filename);
+      if (matte_image == (Image *) NULL)
+        break;
+      (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
+        filename);
+      status=WriteImage(image_info,matte_image);
+      matte_image=DestroyImage(matte_image);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to show matte",
+          (*image)->filename);
+      XDelay(display,1500);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case BackgroundCommand:
+    {
+      /*
+        Background image.
+      */
+      status=XBackgroundImage(display,resource_info,windows,image);
+      if (status == MagickFalse)
+        break;
+      nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
+      if (nexus != (Image *) NULL)
+        XClientMessage(display,windows->image.id,windows->im_protocols,
+          windows->im_next_image,CurrentTime);
+      break;
+    }
+    case SlideShowCommand:
+    {
+      static char
+        delay[MaxTextExtent] = "5";
+
+      /*
+        Display next image after pausing.
+      */
+      (void) XDialogWidget(display,windows,"Slide Show",
+        "Pause how many 1/100ths of a second between images:",delay);
+      if (*delay == '\0')
+        break;
+      resource_info->delay=StringToUnsignedLong(delay);
+      XClientMessage(display,windows->image.id,windows->im_protocols,
+        windows->im_next_image,CurrentTime);
+      break;
+    }
+    case PreferencesCommand:
+    {
+      /*
+        Set user preferences.
+      */
+      status=XPreferencesWidget(display,resource_info,windows);
+      if (status == MagickFalse)
+        break;
+      nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
+      if (nexus != (Image *) NULL)
+        XClientMessage(display,windows->image.id,windows->im_protocols,
+          windows->im_next_image,CurrentTime);
+      break;
+    }
+    case HelpCommand:
+    {
+      /*
+        User requested help.
+      */
+      XTextViewWidget(display,resource_info,windows,MagickFalse,
+        "Help Viewer - Display",DisplayHelp);
+      break;
+    }
+    case BrowseDocumentationCommand:
+    {
+      Atom
+        mozilla_atom;
+
+      Window
+        mozilla_window,
+        root_window;
+
+      /*
+        Browse the ImageMagick documentation.
+      */
+      root_window=XRootWindow(display,XDefaultScreen(display));
+      mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
+      mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
+      if (mozilla_window != (Window) NULL)
+        {
+          char
+            command[MaxTextExtent],
+            *url;
+
+          /*
+            Display documentation using Netscape remote control.
+          */
+          url=GetMagickHomeURL();
+          (void) FormatLocaleString(command,MaxTextExtent,
+            "openurl(%s,new-tab)",url);
+          url=DestroyString(url);
+          mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
+          (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
+            8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
+          XSetCursorState(display,windows,MagickFalse);
+          break;
+        }
+      XSetCursorState(display,windows,MagickTrue);
+      XCheckRefreshWindows(display,windows);
+      status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
+        &(*image)->exception);
+      if (status == MagickFalse)
+        XNoticeWidget(display,windows,"Unable to browse documentation",
+          (char *) NULL);
+      XDelay(display,1500);
+      XSetCursorState(display,windows,MagickFalse);
+      break;
+    }
+    case VersionCommand:
+    {
+      XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
+        GetMagickCopyright());
+      break;
+    }
+    case SaveToUndoBufferCommand:
+      break;
+    default:
+    {
+      (void) XBell(display,0);
+      break;
+    }
+  }
+  image_info=DestroyImageInfo(image_info);
+  return(nexus);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a g n i f y I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMagnifyImage() magnifies portions of the image as indicated by the pointer.
+%  The magnified portion is displayed in a separate window.
+%
+%  The format of the XMagnifyImage method is:
+%
+%      void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o event: Specifies a pointer to a XEvent structure.  If it is NULL,
+%      the entire image is refreshed.
+%
+*/
+static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
+{
+  char
+    text[MaxTextExtent];
+
+  register int
+    x,
+    y;
+
+  size_t
+    state;
+
+  /*
+    Update magnified image until the mouse button is released.
+  */
+  (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
+  state=DefaultState;
+  x=event->xbutton.x;
+  y=event->xbutton.y;
+  windows->magnify.x=(int) windows->image.x+x;
+  windows->magnify.y=(int) windows->image.y+y;
+  do
+  {
+    /*
+      Map and unmap Info widget as text cursor crosses its boundaries.
+    */
+    if (windows->info.mapped != MagickFalse)
+      {
+        if ((x < (int) (windows->info.x+windows->info.width)) &&
+            (y < (int) (windows->info.y+windows->info.height)))
+          (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      }
+    else
+      if ((x > (int) (windows->info.x+windows->info.width)) ||
+          (y > (int) (windows->info.y+windows->info.height)))
+        (void) XMapWindow(display,windows->info.id);
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
+          windows->magnify.x,windows->magnify.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,event);
+    switch (event->type)
+    {
+      case ButtonPress:
+        break;
+      case ButtonRelease:
+      {
+        /*
+          User has finished magnifying image.
+        */
+        x=event->xbutton.x;
+        y=event->xbutton.y;
+        state|=ExitState;
+        break;
+      }
+      case Expose:
+        break;
+      case MotionNotify:
+      {
+        x=event->xmotion.x;
+        y=event->xmotion.y;
+        break;
+      }
+      default:
+        break;
+    }
+    /*
+      Check boundary conditions.
+    */
+    if (x < 0)
+      x=0;
+    else
+      if (x >= (int) windows->image.width)
+        x=(int) windows->image.width-1;
+    if (y < 0)
+      y=0;
+    else
+     if (y >= (int) windows->image.height)
+       y=(int) windows->image.height-1;
+  } while ((state & ExitState) == 0);
+  /*
+    Display magnified image.
+  */
+  XSetCursorState(display,windows,MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a g n i f y W i n d o w C o m m a n d                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMagnifyWindowCommand() moves the image within an Magnify window by one
+%  pixel as specified by the key symbol.
+%
+%  The format of the XMagnifyWindowCommand method is:
+%
+%      void XMagnifyWindowCommand(Display *display,XWindows *windows,
+%        const MagickStatusType state,const KeySym key_symbol)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o state: key mask.
+%
+%    o key_symbol: Specifies a KeySym which indicates which side of the image
+%      to trim.
+%
+*/
+static void XMagnifyWindowCommand(Display *display,XWindows *windows,
+  const MagickStatusType state,const KeySym key_symbol)
+{
+  unsigned int
+    quantum;
+
+  /*
+    User specified a magnify factor or position.
+  */
+  quantum=1;
+  if ((state & Mod1Mask) != 0)
+    quantum=10;
+  switch ((int) key_symbol)
+  {
+    case QuitCommand:
+    {
+      (void) XWithdrawWindow(display,windows->magnify.id,
+        windows->magnify.screen);
+      break;
+    }
+    case XK_Home:
+    case XK_KP_Home:
+    {
+      windows->magnify.x=(int) windows->image.width/2;
+      windows->magnify.y=(int) windows->image.height/2;
+      break;
+    }
+    case XK_Left:
+    case XK_KP_Left:
+    {
+      if (windows->magnify.x > 0)
+        windows->magnify.x-=quantum;
+      break;
+    }
+    case XK_Up:
+    case XK_KP_Up:
+    {
+      if (windows->magnify.y > 0)
+        windows->magnify.y-=quantum;
+      break;
+    }
+    case XK_Right:
+    case XK_KP_Right:
+    {
+      if (windows->magnify.x < (int) (windows->image.ximage->width-1))
+        windows->magnify.x+=quantum;
+      break;
+    }
+    case XK_Down:
+    case XK_KP_Down:
+    {
+      if (windows->magnify.y < (int) (windows->image.ximage->height-1))
+        windows->magnify.y+=quantum;
+      break;
+    }
+    case XK_0:
+    case XK_1:
+    case XK_2:
+    case XK_3:
+    case XK_4:
+    case XK_5:
+    case XK_6:
+    case XK_7:
+    case XK_8:
+    case XK_9:
+    {
+      windows->magnify.data=(key_symbol-XK_0);
+      break;
+    }
+    case XK_KP_0:
+    case XK_KP_1:
+    case XK_KP_2:
+    case XK_KP_3:
+    case XK_KP_4:
+    case XK_KP_5:
+    case XK_KP_6:
+    case XK_KP_7:
+    case XK_KP_8:
+    case XK_KP_9:
+    {
+      windows->magnify.data=(key_symbol-XK_KP_0);
+      break;
+    }
+    default:
+      break;
+  }
+  XMakeMagnifyImage(display,windows);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a k e P a n I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakePanImage() creates a thumbnail of the image and displays it in the Pan
+%  icon window.
+%
+%  The format of the XMakePanImage method is:
+%
+%        void XMakePanImage(Display *display,XResourceInfo *resource_info,
+%          XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static void XMakePanImage(Display *display,XResourceInfo *resource_info,
+  XWindows *windows,Image *image)
+{
+  MagickStatusType
+    status;
+
+  /*
+    Create and display image for panning icon.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  windows->pan.x=(int) windows->image.x;
+  windows->pan.y=(int) windows->image.y;
+  status=XMakeImage(display,resource_info,&windows->pan,image,
+    windows->pan.width,windows->pan.height);
+  if (status == MagickFalse)
+    ThrowXWindowFatalException(XServerError,image->exception.reason,
+      image->exception.description);
+  (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
+    windows->pan.pixmap);
+  (void) XClearWindow(display,windows->pan.id);
+  XDrawPanRectangle(display,windows);
+  XSetCursorState(display,windows,MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a t t a E d i t I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMatteEditImage() allows the user to interactively change the Matte channel
+%  of an image.  If the image is PseudoClass it is promoted to DirectClass
+%  before the matte information is stored.
+%
+%  The format of the XMatteEditImage method is:
+%
+%      MagickBooleanType XMatteEditImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+*/
+static MagickBooleanType XMatteEditImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image **image)
+{
+  static char
+    matte[MaxTextExtent] = "0";
+
+  static const char
+    *MatteEditMenu[] =
+    {
+      "Method",
+      "Border Color",
+      "Fuzz",
+      "Matte Value",
+      "Undo",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static const ModeType
+    MatteEditCommands[] =
+    {
+      MatteEditMethod,
+      MatteEditBorderCommand,
+      MatteEditFuzzCommand,
+      MatteEditValueCommand,
+      MatteEditUndoCommand,
+      MatteEditHelpCommand,
+      MatteEditDismissCommand
+    };
+
+  static PaintMethod
+    method = PointMethod;
+
+  static XColor
+    border_color = { 0, 0, 0, 0, 0, 0 };
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  int
+    entry,
+    id,
+    x,
+    x_offset,
+    y,
+    y_offset;
+
+  register int
+    i;
+
+  register Quantum
+    *q;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Matte Edit");
+  windows->command.data=4;
+  (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Make cursor.
+  */
+  cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
+    resource_info->background_color,resource_info->foreground_color);
+  (void) XCheckDefineCursor(display,windows->image.id,cursor);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
+          x+windows->image.x,y+windows->image.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,MatteEditMenu,&event);
+        if (id < 0)
+          {
+            (void) XCheckDefineCursor(display,windows->image.id,cursor);
+            continue;
+          }
+        switch (MatteEditCommands[id])
+        {
+          case MatteEditMethod:
+          {
+            char
+              **methods;
+
+            /*
+              Select a method from the pop-up menu.
+            */
+            methods=GetCommandOptions(MagickMethodOptions);
+            if (methods == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,MatteEditMenu[id],
+              (const char **) methods,command);
+            if (entry >= 0)
+              method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
+                MagickFalse,methods[entry]);
+            methods=DestroyStringList(methods);
+            break;
+          }
+          case MatteEditBorderCommand:
+          {
+            const char
+              *ColorMenu[MaxNumberPens];
+
+            int
+              pen_number;
+
+            /*
+              Initialize menu selections.
+            */
+            for (i=0; i < (int) (MaxNumberPens-2); i++)
+              ColorMenu[i]=resource_info->pen_colors[i];
+            ColorMenu[MaxNumberPens-2]="Browser...";
+            ColorMenu[MaxNumberPens-1]=(const char *) NULL;
+            /*
+              Select a pen color from the pop-up menu.
+            */
+            pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
+              (const char **) ColorMenu,command);
+            if (pen_number < 0)
+              break;
+            if (pen_number == (MaxNumberPens-2))
+              {
+                static char
+                  color_name[MaxTextExtent] = "gray";
+
+                /*
+                  Select a pen color from a dialog.
+                */
+                resource_info->pen_colors[pen_number]=color_name;
+                XColorBrowserWidget(display,windows,"Select",color_name);
+                if (*color_name == '\0')
+                  break;
+              }
+            /*
+              Set border color.
+            */
+            (void) XParseColor(display,windows->map_info->colormap,
+              resource_info->pen_colors[pen_number],&border_color);
+            break;
+          }
+          case MatteEditFuzzCommand:
+          {
+            static char
+              fuzz[MaxTextExtent];
+
+            static const char
+              *FuzzMenu[] =
+              {
+                "0%",
+                "2%",
+                "5%",
+                "10%",
+                "15%",
+                "Dialog...",
+                (char *) NULL,
+              };
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
+              command);
+            if (entry < 0)
+              break;
+            if (entry != 5)
+              {
+                (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],1.0*
+                  QuantumRange+1.0);
+                break;
+              }
+            (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
+            (void) XDialogWidget(display,windows,"Ok",
+              "Enter fuzz factor (0.0 - 99.9%):",fuzz);
+            if (*fuzz == '\0')
+              break;
+            (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
+            (*image)->fuzz=SiPrefixToDouble(fuzz,1.0*QuantumRange+1.0);
+            break;
+          }
+          case MatteEditValueCommand:
+          {
+            static char
+              message[MaxTextExtent];
+
+            static const char
+              *MatteMenu[] =
+              {
+                "Opaque",
+                "Transparent",
+                "Dialog...",
+                (char *) NULL,
+              };
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
+              command);
+            if (entry < 0)
+              break;
+            if (entry != 2)
+              {
+                (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
+                  OpaqueAlpha);
+                if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
+                  (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
+                    (Quantum) TransparentAlpha);
+                break;
+              }
+            (void) FormatLocaleString(message,MaxTextExtent,
+              "Enter matte value (0 - " QuantumFormat "):",(Quantum)
+              QuantumRange);
+            (void) XDialogWidget(display,windows,"Matte",message,matte);
+            if (*matte == '\0')
+              break;
+            break;
+          }
+          case MatteEditUndoCommand:
+          {
+            (void) XMagickCommand(display,resource_info,windows,UndoCommand,
+              image);
+            break;
+          }
+          case MatteEditHelpCommand:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Matte Edit",ImageMatteEditHelp);
+            break;
+          }
+          case MatteEditDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if ((event.xbutton.window != windows->image.id) &&
+            (event.xbutton.window != windows->magnify.id))
+          break;
+        /*
+          Update matte data.
+        */
+        x=event.xbutton.x;
+        y=event.xbutton.y;
+        (void) XMagickCommand(display,resource_info,windows,
+          SaveToUndoBufferCommand,image);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if ((event.xbutton.window != windows->image.id) &&
+            (event.xbutton.window != windows->magnify.id))
+          break;
+        /*
+          Update colormap information.
+        */
+        x=event.xbutton.x;
+        y=event.xbutton.y;
+        XConfigureImageColormap(display,resource_info,windows,*image);
+        (void) XConfigureImage(display,resource_info,windows,*image);
+        XInfoWidget(display,windows,text);
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        state&=(~UpdateConfigurationState);
+        break;
+      }
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        char
+          command[MaxTextExtent];
+
+        KeySym
+          key_symbol;
+
+        if (event.xkey.window == windows->magnify.id)
+          {
+            Window
+              window;
+
+            window=windows->magnify.id;
+            while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
+          }
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Matte Edit",ImageMatteEditHelp);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        break;
+      }
+      default:
+        break;
+    }
+    if (event.xany.window == windows->magnify.id)
+      {
+        x=windows->magnify.x-windows->image.x;
+        y=windows->magnify.y-windows->image.y;
+      }
+    x_offset=x;
+    y_offset=y;
+    if ((state & UpdateConfigurationState) != 0)
+      {
+        CacheView
+          *image_view;
+
+        ExceptionInfo
+          *exception;
+
+        int
+          x,
+          y;
+
+        /*
+          Matte edit is relative to image configuration.
+        */
+        (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
+          MagickTrue);
+        XPutPixel(windows->image.ximage,x_offset,y_offset,
+          windows->pixel_info->background_color.pixel);
+        width=(unsigned int) (*image)->columns;
+        height=(unsigned int) (*image)->rows;
+        x=0;
+        y=0;
+        if (windows->image.crop_geometry != (char *) NULL)
+          (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
+            &height);
+        x_offset=(int) (width*(windows->image.x+x_offset)/
+          windows->image.ximage->width+x);
+        y_offset=(int) (height*(windows->image.y+y_offset)/
+          windows->image.ximage->height+y);
+        if ((x_offset < 0) || (y_offset < 0))
+          continue;
+        if ((x_offset >= (int) (*image)->columns) ||
+            (y_offset >= (int) (*image)->rows))
+          continue;
+        if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
+          return(MagickFalse);
+        (*image)->matte=MagickTrue;
+        exception=(&(*image)->exception);
+        image_view=AcquireCacheView(*image);
+        switch (method)
+        {
+          case PointMethod:
+          default:
+          {
+            /*
+              Update matte information using point algorithm.
+            */
+            q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
+              (ssize_t) y_offset,1,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
+            (void) SyncCacheViewAuthenticPixels(image_view,exception);
+            break;
+          }
+          case ReplaceMethod:
+          {
+            PixelPacket
+              pixel,
+              target;
+
+            /*
+              Update matte information using replace algorithm.
+            */
+            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
+              (ssize_t) y_offset,&target,exception);
+            for (y=0; y < (int) (*image)->rows; y++)
+            {
+              q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
+                (*image)->columns,1,&(*image)->exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (int) (*image)->columns; x++)
+              {
+                GetPixelPacket(*image,q,&pixel);
+                if (IsFuzzyEquivalencePixelPacket(*image,&pixel,&target))
+                  SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
+                q+=GetPixelChannels(*image);
+              }
+              if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+                break;
+            }
+            break;
+          }
+          case FloodfillMethod:
+          case FillToBorderMethod:
+          {
+            DrawInfo
+              *draw_info;
+
+            PixelInfo
+              target;
+
+            /*
+              Update matte information using floodfill algorithm.
+            */
+            (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
+              (ssize_t) y_offset,&target,exception);
+            if (method == FillToBorderMethod)
+              {
+                target.red=(MagickRealType) ScaleShortToQuantum(
+                  border_color.red);
+                target.green=(MagickRealType) ScaleShortToQuantum(
+                  border_color.green);
+                target.blue=(MagickRealType) ScaleShortToQuantum(
+                  border_color.blue);
+              }
+            draw_info=CloneDrawInfo(resource_info->image_info,
+              (DrawInfo *) NULL);
+            draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte,
+              (char **) NULL));
+            (void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
+              (ssize_t) x_offset,(ssize_t) y_offset,
+              method == FloodfillMethod ? MagickFalse : MagickTrue);
+            draw_info=DestroyDrawInfo(draw_info);
+            break;
+          }
+          case ResetMethod:
+          {
+            /*
+              Update matte information using reset algorithm.
+            */
+            if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
+              return(MagickFalse);
+            for (y=0; y < (int) (*image)->rows; y++)
+            {
+              q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
+                (*image)->columns,1,exception);
+              if (q == (Quantum *) NULL)
+                break;
+              for (x=0; x < (int) (*image)->columns; x++)
+              {
+                SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
+                q+=GetPixelChannels(*image);
+              }
+              if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+                break;
+            }
+            if (StringToLong(matte) == (long) OpaqueAlpha)
+              (*image)->matte=MagickFalse;
+            break;
+          }
+        }
+        image_view=DestroyCacheView(image_view);
+        state&=(~UpdateConfigurationState);
+      }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XFreeCursor(display,cursor);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X O p e n I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XOpenImage() loads an image from a file.
+%
+%  The format of the XOpenImage method is:
+%
+%     Image *XOpenImage(Display *display,XResourceInfo *resource_info,
+%       XWindows *windows,const unsigned int command)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o command: A value other than zero indicates that the file is selected
+%      from the command line argument list.
+%
+*/
+static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
+  XWindows *windows,const MagickBooleanType command)
+{
+  const MagickInfo
+    *magick_info;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *nexus;
+
+  ImageInfo
+    *image_info;
+
+  static char
+    filename[MaxTextExtent] = "\0";
+
+  /*
+    Request file name from user.
+  */
+  if (command == MagickFalse)
+    XFileBrowserWidget(display,windows,"Open",filename);
+  else
+    {
+      char
+        **filelist,
+        **files;
+
+      int
+        count,
+        status;
+
+      register int
+        i,
+        j;
+
+      /*
+        Select next image from the command line.
+      */
+      status=XGetCommand(display,windows->image.id,&files,&count);
+      if (status == 0)
+        {
+          ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
+          return((Image *) NULL);
+        }
+      filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
+      if (filelist == (char **) NULL)
+        {
+          ThrowXWindowFatalException(ResourceLimitError,
+            "MemoryAllocationFailed","...");
+          (void) XFreeStringList(files);
+          return((Image *) NULL);
+        }
+      j=0;
+      for (i=1; i < count; i++)
+        if (*files[i] != '-')
+          filelist[j++]=files[i];
+      filelist[j]=(char *) NULL;
+      XListBrowserWidget(display,windows,&windows->widget,
+        (const char **) filelist,"Load","Select Image to Load:",filename);
+      filelist=(char **) RelinquishMagickMemory(filelist);
+      (void) XFreeStringList(files);
+    }
+  if (*filename == '\0')
+    return((Image *) NULL);
+  image_info=CloneImageInfo(resource_info->image_info);
+  (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
+    (void *) NULL);
+  (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+  exception=AcquireExceptionInfo();
+  (void) SetImageInfo(image_info,0,exception);
+  if (LocaleCompare(image_info->magick,"X") == 0)
+    {
+      char
+        seconds[MaxTextExtent];
+
+      /*
+        User may want to delay the X server screen grab.
+      */
+      (void) CopyMagickString(seconds,"0",MaxTextExtent);
+      (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
+        seconds);
+      if (*seconds == '\0')
+        return((Image *) NULL);
+      XDelay(display,(size_t) (1000*StringToLong(seconds)));
+    }
+  magick_info=GetMagickInfo(image_info->magick,exception);
+  if ((magick_info != (const MagickInfo *) NULL) &&
+      (magick_info->raw != MagickFalse))
+    {
+      char
+        geometry[MaxTextExtent];
+
+      /*
+        Request image size from the user.
+      */
+      (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
+      if (image_info->size != (char *) NULL)
+        (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
+      (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
+        geometry);
+      (void) CloneString(&image_info->size,geometry);
+    }
+  /*
+    Load the image.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+  nexus=ReadImage(image_info,exception);
+  CatchException(exception);
+  XSetCursorState(display,windows,MagickFalse);
+  if (nexus != (Image *) NULL)
+    XClientMessage(display,windows->image.id,windows->im_protocols,
+      windows->im_next_image,CurrentTime);
+  else
+    {
+      char
+        *text,
+        **textlist;
+
+      /*
+        Unknown image format.
+      */
+      text=FileToString(filename,~0,exception);
+      if (text == (char *) NULL)
+        return((Image *) NULL);
+      textlist=StringToList(text);
+      if (textlist != (char **) NULL)
+        {
+          char
+            title[MaxTextExtent];
+
+          register int
+            i;
+
+          (void) FormatLocaleString(title,MaxTextExtent,
+            "Unknown format: %s",filename);
+          XTextViewWidget(display,resource_info,windows,MagickTrue,title,
+            (const char **) textlist);
+          for (i=0; textlist[i] != (char *) NULL; i++)
+            textlist[i]=DestroyString(textlist[i]);
+          textlist=(char **) RelinquishMagickMemory(textlist);
+        }
+      text=DestroyString(text);
+    }
+  exception=DestroyExceptionInfo(exception);
+  image_info=DestroyImageInfo(image_info);
+  return(nexus);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X P a n I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XPanImage() pans the image until the mouse button is released.
+%
+%  The format of the XPanImage method is:
+%
+%      void XPanImage(Display *display,XWindows *windows,XEvent *event)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o event: Specifies a pointer to a XEvent structure.  If it is NULL,
+%      the entire image is refreshed.
+%
+*/
+static void XPanImage(Display *display,XWindows *windows,XEvent *event)
+{
+  char
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  MagickRealType
+    x_factor,
+    y_factor;
+
+  RectangleInfo
+    pan_info;
+
+  size_t
+    state;
+
+  /*
+    Define cursor.
+  */
+  if ((windows->image.ximage->width > (int) windows->image.width) &&
+      (windows->image.ximage->height > (int) windows->image.height))
+    cursor=XCreateFontCursor(display,XC_fleur);
+  else
+    if (windows->image.ximage->width > (int) windows->image.width)
+      cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
+    else
+      if (windows->image.ximage->height > (int) windows->image.height)
+        cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
+      else
+        cursor=XCreateFontCursor(display,XC_arrow);
+  (void) XCheckDefineCursor(display,windows->pan.id,cursor);
+  /*
+    Pan image as pointer moves until the mouse button is released.
+  */
+  x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
+  y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
+  pan_info.width=windows->pan.width*windows->image.width/
+    windows->image.ximage->width;
+  pan_info.height=windows->pan.height*windows->image.height/
+    windows->image.ximage->height;
+  pan_info.x=0;
+  pan_info.y=0;
+  state=UpdateConfigurationState;
+  do
+  {
+    switch (event->type)
+    {
+      case ButtonPress:
+      {
+        /*
+          User choose an initial pan location.
+        */
+        pan_info.x=(ssize_t) event->xbutton.x;
+        pan_info.y=(ssize_t) event->xbutton.y;
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case ButtonRelease:
+      {
+        /*
+          User has finished panning the image.
+        */
+        pan_info.x=(ssize_t) event->xbutton.x;
+        pan_info.y=(ssize_t) event->xbutton.y;
+        state|=UpdateConfigurationState | ExitState;
+        break;
+      }
+      case MotionNotify:
+      {
+        pan_info.x=(ssize_t) event->xmotion.x;
+        pan_info.y=(ssize_t) event->xmotion.y;
+        state|=UpdateConfigurationState;
+      }
+      default:
+        break;
+    }
+    if ((state & UpdateConfigurationState) != 0)
+      {
+        /*
+          Check boundary conditions.
+        */
+        if (pan_info.x < (ssize_t) (pan_info.width/2))
+          pan_info.x=0;
+        else
+          pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
+        if (pan_info.x < 0)
+          pan_info.x=0;
+        else
+          if ((int) (pan_info.x+windows->image.width) >
+              windows->image.ximage->width)
+            pan_info.x=(ssize_t)
+              (windows->image.ximage->width-windows->image.width);
+        if (pan_info.y < (ssize_t) (pan_info.height/2))
+          pan_info.y=0;
+        else
+          pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
+        if (pan_info.y < 0)
+          pan_info.y=0;
+        else
+          if ((int) (pan_info.y+windows->image.height) >
+              windows->image.ximage->height)
+            pan_info.y=(ssize_t)
+              (windows->image.ximage->height-windows->image.height);
+        if ((windows->image.x != (int) pan_info.x) ||
+            (windows->image.y != (int) pan_info.y))
+          {
+            /*
+              Display image pan offset.
+            */
+            windows->image.x=(int) pan_info.x;
+            windows->image.y=(int) pan_info.y;
+            (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
+              windows->image.width,windows->image.height,windows->image.x,
+              windows->image.y);
+            XInfoWidget(display,windows,text);
+            /*
+              Refresh Image window.
+            */
+            XDrawPanRectangle(display,windows);
+            XRefreshWindow(display,&windows->image,(XEvent *) NULL);
+          }
+        state&=(~UpdateConfigurationState);
+      }
+    /*
+      Wait for next event.
+    */
+    if ((state & ExitState) == 0)
+      XScreenEvent(display,windows,event);
+  } while ((state & ExitState) == 0);
+  /*
+    Restore cursor.
+  */
+  (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
+  (void) XFreeCursor(display,cursor);
+  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X P a s t e I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XPasteImage() pastes an image previously saved with XCropImage in the X
+%  window image at a location the user chooses with the pointer.
+%
+%  The format of the XPasteImage method is:
+%
+%      MagickBooleanType XPasteImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+*/
+static MagickBooleanType XPasteImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  static const char
+    *PasteMenu[] =
+    {
+      "Operator",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static const ModeType
+    PasteCommands[] =
+    {
+      PasteOperatorsCommand,
+      PasteHelpCommand,
+      PasteDismissCommand
+    };
+
+  static CompositeOperator
+    compose = CopyCompositeOp;
+
+  char
+    text[MaxTextExtent];
+
+  Cursor
+    cursor;
+
+  Image
+    *paste_image;
+
+  int
+    entry,
+    id,
+    x,
+    y;
+
+  MagickRealType
+    scale_factor;
+
+  RectangleInfo
+    highlight_info,
+    paste_info;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  /*
+    Copy image.
+  */
+  if (resource_info->copy_image == (Image *) NULL)
+    return(MagickFalse);
+  paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
+    &image->exception);
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"Paste");
+  windows->command.data=1;
+  (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XSetCursorState(display,windows,MagickFalse);
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  paste_info.x=(ssize_t) windows->image.x+x;
+  paste_info.y=(ssize_t) windows->image.y+y;
+  paste_info.width=0;
+  paste_info.height=0;
+  cursor=XCreateFontCursor(display,XC_ul_angle);
+  (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
+          (long) paste_info.x,(long) paste_info.y);
+        XInfoWidget(display,windows,text);
+      }
+    highlight_info=paste_info;
+    highlight_info.x=paste_info.x-windows->image.x;
+    highlight_info.y=paste_info.y-windows->image.y;
+    XHighlightRectangle(display,windows->image.id,
+      windows->image.highlight_context,&highlight_info);
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    XHighlightRectangle(display,windows->image.id,
+      windows->image.highlight_context,&highlight_info);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,PasteMenu,&event);
+        if (id < 0)
+          continue;
+        switch (PasteCommands[id])
+        {
+          case PasteOperatorsCommand:
+          {
+            char
+              command[MaxTextExtent],
+              **operators;
+
+            /*
+              Select a command from the pop-up menu.
+            */
+            operators=GetCommandOptions(MagickComposeOptions);
+            if (operators == (char **) NULL)
+              break;
+            entry=XMenuWidget(display,windows,PasteMenu[id],
+              (const char **) operators,command);
+            if (entry >= 0)
+              compose=(CompositeOperator) ParseCommandOption(
+                MagickComposeOptions,MagickFalse,operators[entry]);
+            operators=DestroyStringList(operators);
+            break;
+          }
+          case PasteHelpCommand:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Composite",ImagePasteHelp);
+            break;
+          }
+          case PasteDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        /*
+          Paste rectangle is relative to image configuration.
+        */
+        width=(unsigned int) image->columns;
+        height=(unsigned int) image->rows;
+        x=0;
+        y=0;
+        if (windows->image.crop_geometry != (char *) NULL)
+          (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
+            &width,&height);
+        scale_factor=(MagickRealType) windows->image.ximage->width/width;
+        paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
+        scale_factor=(MagickRealType) windows->image.ximage->height/height;
+        paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+        paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        if ((paste_info.width != 0) && (paste_info.height != 0))
+          {
+            /*
+              User has selected the location of the paste image.
+            */
+            paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+            paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+            state|=ExitState;
+          }
+        break;
+      }
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        char
+          command[MaxTextExtent];
+
+        KeySym
+          key_symbol;
+
+        int
+          length;
+
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Key press: 0x%lx (%s)",(long) key_symbol,command);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            paste_image=DestroyImage(paste_image);
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Image Composite",ImagePasteHelp);
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as text cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        paste_info.x=(ssize_t) windows->image.x+x;
+        paste_info.y=(ssize_t) windows->image.y+y;
+        break;
+      }
+      default:
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
+            event.type);
+        break;
+      }
+    }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XFreeCursor(display,cursor);
+  if ((state & EscapeState) != 0)
+    return(MagickTrue);
+  /*
+    Image pasting is relative to image configuration.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  scale_factor=(MagickRealType) width/windows->image.ximage->width;
+  paste_info.x+=x;
+  paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
+  paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
+  scale_factor=(MagickRealType) height/windows->image.ximage->height;
+  paste_info.y+=y;
+  paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
+  paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
+  /*
+    Paste image with X Image window.
+  */
+  (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
+  paste_image=DestroyImage(paste_image);
+  XSetCursorState(display,windows,MagickFalse);
+  /*
+    Update image colormap.
+  */
+  XConfigureImageColormap(display,resource_info,windows,image);
+  (void) XConfigureImage(display,resource_info,windows,image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X P r i n t I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XPrintImage() prints an image to a Postscript printer.
+%
+%  The format of the XPrintImage method is:
+%
+%      MagickBooleanType XPrintImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XPrintImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  char
+    filename[MaxTextExtent],
+    geometry[MaxTextExtent];
+
+  Image
+    *print_image;
+
+  ImageInfo
+    *image_info;
+
+  MagickStatusType
+    status;
+
+  /*
+    Request Postscript page geometry from user.
+  */
+  image_info=CloneImageInfo(resource_info->image_info);
+  (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
+  if (image_info->page != (char *) NULL)
+    (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
+  XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
+    "Select Postscript Page Geometry:",geometry);
+  if (*geometry == '\0')
+    return(MagickTrue);
+  image_info->page=GetPageGeometry(geometry);
+  /*
+    Apply image transforms.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+  if (print_image == (Image *) NULL)
+    return(MagickFalse);
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
+    windows->image.ximage->width,windows->image.ximage->height);
+  (void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
+  /*
+    Print image.
+  */
+  (void) AcquireUniqueFilename(filename);
+  (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
+    filename);
+  status=WriteImage(image_info,print_image);
+  (void) RelinquishUniqueFileResource(filename);
+  print_image=DestroyImage(print_image);
+  image_info=DestroyImageInfo(image_info);
+  XSetCursorState(display,windows,MagickFalse);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X R O I I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XROIImage() applies an image processing technique to a region of interest.
+%
+%  The format of the XROIImage method is:
+%
+%      MagickBooleanType XROIImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+*/
+static MagickBooleanType XROIImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image **image)
+{
+#define ApplyMenus  7
+
+  static const char
+    *ROIMenu[] =
+    {
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    },
+    *ApplyMenu[] =
+    {
+      "File",
+      "Edit",
+      "Transform",
+      "Enhance",
+      "Effects",
+      "F/X",
+      "Miscellany",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    },
+    *FileMenu[] =
+    {
+      "Save...",
+      "Print...",
+      (char *) NULL
+    },
+    *EditMenu[] =
+    {
+      "Undo",
+      "Redo",
+      (char *) NULL
+    },
+    *TransformMenu[] =
+    {
+      "Flop",
+      "Flip",
+      "Rotate Right",
+      "Rotate Left",
+      (char *) NULL
+    },
+    *EnhanceMenu[] =
+    {
+      "Hue...",
+      "Saturation...",
+      "Brightness...",
+      "Gamma...",
+      "Spiff",
+      "Dull",
+      "Contrast Stretch...",
+      "Sigmoidal Contrast...",
+      "Normalize",
+      "Equalize",
+      "Negate",
+      "Grayscale",
+      "Map...",
+      "Quantize...",
+      (char *) NULL
+    },
+    *EffectsMenu[] =
+    {
+      "Despeckle",
+      "Emboss",
+      "Reduce Noise",
+      "Add Noise",
+      "Sharpen...",
+      "Blur...",
+      "Threshold...",
+      "Edge Detect...",
+      "Spread...",
+      "Shade...",
+      "Raise...",
+      "Segment...",
+      (char *) NULL
+    },
+    *FXMenu[] =
+    {
+      "Solarize...",
+      "Sepia Tone...",
+      "Swirl...",
+      "Implode...",
+      "Vignette...",
+      "Wave...",
+      "Oil Paint...",
+      "Charcoal Draw...",
+      (char *) NULL
+    },
+    *MiscellanyMenu[] =
+    {
+      "Image Info",
+      "Zoom Image",
+      "Show Preview...",
+      "Show Histogram",
+      "Show Matte",
+      (char *) NULL
+    };
+
+  static const char
+    **Menus[ApplyMenus] =
+    {
+      FileMenu,
+      EditMenu,
+      TransformMenu,
+      EnhanceMenu,
+      EffectsMenu,
+      FXMenu,
+      MiscellanyMenu
+    };
+
+  static const CommandType
+    ApplyCommands[] =
+    {
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      HelpCommand,
+      QuitCommand
+    },
+    FileCommands[] =
+    {
+      SaveCommand,
+      PrintCommand
+    },
+    EditCommands[] =
+    {
+      UndoCommand,
+      RedoCommand
+    },
+    TransformCommands[] =
+    {
+      FlopCommand,
+      FlipCommand,
+      RotateRightCommand,
+      RotateLeftCommand
+    },
+    EnhanceCommands[] =
+    {
+      HueCommand,
+      SaturationCommand,
+      BrightnessCommand,
+      GammaCommand,
+      SpiffCommand,
+      DullCommand,
+      ContrastStretchCommand,
+      SigmoidalContrastCommand,
+      NormalizeCommand,
+      EqualizeCommand,
+      NegateCommand,
+      GrayscaleCommand,
+      MapCommand,
+      QuantizeCommand
+    },
+    EffectsCommands[] =
+    {
+      DespeckleCommand,
+      EmbossCommand,
+      ReduceNoiseCommand,
+      AddNoiseCommand,
+      SharpenCommand,
+      BlurCommand,
+      EdgeDetectCommand,
+      SpreadCommand,
+      ShadeCommand,
+      RaiseCommand,
+      SegmentCommand
+    },
+    FXCommands[] =
+    {
+      SolarizeCommand,
+      SepiaToneCommand,
+      SwirlCommand,
+      ImplodeCommand,
+      VignetteCommand,
+      WaveCommand,
+      OilPaintCommand,
+      CharcoalDrawCommand
+    },
+    MiscellanyCommands[] =
+    {
+      InfoCommand,
+      ZoomCommand,
+      ShowPreviewCommand,
+      ShowHistogramCommand,
+      ShowMatteCommand
+    },
+    ROICommands[] =
+    {
+      ROIHelpCommand,
+      ROIDismissCommand
+    };
+
+  static const CommandType
+    *Commands[ApplyMenus] =
+    {
+      FileCommands,
+      EditCommands,
+      TransformCommands,
+      EnhanceCommands,
+      EffectsCommands,
+      FXCommands,
+      MiscellanyCommands
+    };
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  CommandType
+    command_type;
+
+  Cursor
+    cursor;
+
+  Image
+    *roi_image;
+
+  int
+    entry,
+    id,
+    x,
+    y;
+
+  MagickRealType
+    scale_factor;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  RectangleInfo
+    crop_info,
+    highlight_info,
+    roi_info;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  /*
+    Map Command widget.
+  */
+  (void) CloneString(&windows->command.name,"ROI");
+  windows->command.data=0;
+  (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
+  (void) XMapRaised(display,windows->command.id);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_widget,CurrentTime);
+  /*
+    Track pointer until button 1 is pressed.
+  */
+  XQueryPosition(display,windows->image.id,&x,&y);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask | PointerMotionMask);
+  roi_info.x=(ssize_t) windows->image.x+x;
+  roi_info.y=(ssize_t) windows->image.y+y;
+  roi_info.width=0;
+  roi_info.height=0;
+  cursor=XCreateFontCursor(display,XC_fleur);
+  state=DefaultState;
+  do
+  {
+    if (windows->info.mapped != MagickFalse)
+      {
+        /*
+          Display pointer position.
+        */
+        (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
+          (long) roi_info.x,(long) roi_info.y);
+        XInfoWidget(display,windows,text);
+      }
+    /*
+      Wait for next event.
+    */
+    XScreenEvent(display,windows,&event);
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,ROIMenu,&event);
+        if (id < 0)
+          continue;
+        switch (ROICommands[id])
+        {
+          case ROIHelpCommand:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Region of Interest",ImageROIHelp);
+            break;
+          }
+          case ROIDismissCommand:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          default:
+            break;
+        }
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.button != Button1)
+          break;
+        if (event.xbutton.window != windows->image.id)
+          break;
+        /*
+          Note first corner of region of interest rectangle-- exit loop.
+        */
+        (void) XCheckDefineCursor(display,windows->image.id,cursor);
+        roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+        roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+        state|=ExitState;
+        break;
+      }
+      case ButtonRelease:
+        break;
+      case Expose:
+        break;
+      case KeyPress:
+      {
+        KeySym
+          key_symbol;
+
+        if (event.xkey.window != windows->image.id)
+          break;
+        /*
+          Respond to a user key press.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        switch ((int) key_symbol)
+        {
+          case XK_Escape:
+          case XK_F20:
+          {
+            /*
+              Prematurely exit.
+            */
+            state|=EscapeState;
+            state|=ExitState;
+            break;
+          }
+          case XK_F1:
+          case XK_Help:
+          {
+            XTextViewWidget(display,resource_info,windows,MagickFalse,
+              "Help Viewer - Region of Interest",ImageROIHelp);
+            break;
+          }
+          default:
+          {
+            (void) XBell(display,0);
+            break;
+          }
+        }
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Map and unmap Info widget as text cursor crosses its boundaries.
+        */
+        x=event.xmotion.x;
+        y=event.xmotion.y;
+        if (windows->info.mapped != MagickFalse)
+          {
+            if ((x < (int) (windows->info.x+windows->info.width)) &&
+                (y < (int) (windows->info.y+windows->info.height)))
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+          }
+        else
+          if ((x > (int) (windows->info.x+windows->info.width)) ||
+              (y > (int) (windows->info.y+windows->info.height)))
+            (void) XMapWindow(display,windows->info.id);
+        roi_info.x=(ssize_t) windows->image.x+x;
+        roi_info.y=(ssize_t) windows->image.y+y;
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  (void) XSelectInput(display,windows->image.id,
+    windows->image.attributes.event_mask);
+  if ((state & EscapeState) != 0)
+    {
+      /*
+        User want to exit without region of interest.
+      */
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      (void) XFreeCursor(display,cursor);
+      return(MagickTrue);
+    }
+  (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+  do
+  {
+    /*
+      Size rectangle as pointer moves until the mouse button is released.
+    */
+    x=(int) roi_info.x;
+    y=(int) roi_info.y;
+    roi_info.width=0;
+    roi_info.height=0;
+    state=DefaultState;
+    do
+    {
+      highlight_info=roi_info;
+      highlight_info.x=roi_info.x-windows->image.x;
+      highlight_info.y=roi_info.y-windows->image.y;
+      if ((highlight_info.width > 3) && (highlight_info.height > 3))
+        {
+          /*
+            Display info and draw region of interest rectangle.
+          */
+          if (windows->info.mapped == MagickFalse)
+            (void) XMapWindow(display,windows->info.id);
+          (void) FormatLocaleString(text,MaxTextExtent,
+            " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
+            roi_info.height,(double) roi_info.x,(double) roi_info.y);
+          XInfoWidget(display,windows,text);
+          XHighlightRectangle(display,windows->image.id,
+            windows->image.highlight_context,&highlight_info);
+        }
+      else
+        if (windows->info.mapped != MagickFalse)
+          (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      /*
+        Wait for next event.
+      */
+      XScreenEvent(display,windows,&event);
+      if ((highlight_info.width > 3) && (highlight_info.height > 3))
+        XHighlightRectangle(display,windows->image.id,
+          windows->image.highlight_context,&highlight_info);
+      switch (event.type)
+      {
+        case ButtonPress:
+        {
+          roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+          roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+          break;
+        }
+        case ButtonRelease:
+        {
+          /*
+            User has committed to region of interest rectangle.
+          */
+          roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
+          roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
+          XSetCursorState(display,windows,MagickFalse);
+          state|=ExitState;
+          if (LocaleCompare(windows->command.name,"Apply") == 0)
+            break;
+          (void) CloneString(&windows->command.name,"Apply");
+          windows->command.data=ApplyMenus;
+          (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
+          break;
+        }
+        case Expose:
+          break;
+        case MotionNotify:
+        {
+          roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
+          roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
+        }
+        default:
+          break;
+      }
+      if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
+          ((state & ExitState) != 0))
+        {
+          /*
+            Check boundary conditions.
+          */
+          if (roi_info.x < 0)
+            roi_info.x=0;
+          else
+            if (roi_info.x > (ssize_t) windows->image.ximage->width)
+              roi_info.x=(ssize_t) windows->image.ximage->width;
+          if ((int) roi_info.x < x)
+            roi_info.width=(unsigned int) (x-roi_info.x);
+          else
+            {
+              roi_info.width=(unsigned int) (roi_info.x-x);
+              roi_info.x=(ssize_t) x;
+            }
+          if (roi_info.y < 0)
+            roi_info.y=0;
+          else
+            if (roi_info.y > (ssize_t) windows->image.ximage->height)
+              roi_info.y=(ssize_t) windows->image.ximage->height;
+          if ((int) roi_info.y < y)
+            roi_info.height=(unsigned int) (y-roi_info.y);
+          else
+            {
+              roi_info.height=(unsigned int) (roi_info.y-y);
+              roi_info.y=(ssize_t) y;
+            }
+        }
+    } while ((state & ExitState) == 0);
+    /*
+      Wait for user to grab a corner of the rectangle or press return.
+    */
+    state=DefaultState;
+    command_type=NullCommand;
+    (void) XMapWindow(display,windows->info.id);
+    do
+    {
+      if (windows->info.mapped != MagickFalse)
+        {
+          /*
+            Display pointer position.
+          */
+          (void) FormatLocaleString(text,MaxTextExtent,
+            " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
+            roi_info.height,(double) roi_info.x,(double) roi_info.y);
+          XInfoWidget(display,windows,text);
+        }
+      highlight_info=roi_info;
+      highlight_info.x=roi_info.x-windows->image.x;
+      highlight_info.y=roi_info.y-windows->image.y;
+      if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
+        {
+          state|=EscapeState;
+          state|=ExitState;
+          break;
+        }
+      if ((state & UpdateRegionState) != 0)
+        {
+          (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+          switch (command_type)
+          {
+            case UndoCommand:
+            case RedoCommand:
+            {
+              (void) XMagickCommand(display,resource_info,windows,command_type,
+                image);
+              break;
+            }
+            default:
+            {
+              /*
+                Region of interest is relative to image configuration.
+              */
+              progress_monitor=SetImageProgressMonitor(*image,
+                (MagickProgressMonitor) NULL,(*image)->client_data);
+              crop_info=roi_info;
+              width=(unsigned int) (*image)->columns;
+              height=(unsigned int) (*image)->rows;
+              x=0;
+              y=0;
+              if (windows->image.crop_geometry != (char *) NULL)
+                (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
+                  &width,&height);
+              scale_factor=(MagickRealType) width/windows->image.ximage->width;
+              crop_info.x+=x;
+              crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
+              crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
+              scale_factor=(MagickRealType)
+                height/windows->image.ximage->height;
+              crop_info.y+=y;
+              crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
+              crop_info.height=(unsigned int)
+                (scale_factor*crop_info.height+0.5);
+              roi_image=CropImage(*image,&crop_info,&(*image)->exception);
+              (void) SetImageProgressMonitor(*image,progress_monitor,
+                (*image)->client_data);
+              if (roi_image == (Image *) NULL)
+                continue;
+              /*
+                Apply image processing technique to the region of interest.
+              */
+              windows->image.orphan=MagickTrue;
+              (void) XMagickCommand(display,resource_info,windows,command_type,
+                &roi_image);
+              progress_monitor=SetImageProgressMonitor(*image,
+                (MagickProgressMonitor) NULL,(*image)->client_data);
+              (void) XMagickCommand(display,resource_info,windows,
+                SaveToUndoBufferCommand,image);
+              windows->image.orphan=MagickFalse;
+              (void) CompositeImage(*image,CopyCompositeOp,roi_image,
+                crop_info.x,crop_info.y);
+              roi_image=DestroyImage(roi_image);
+              (void) SetImageProgressMonitor(*image,progress_monitor,
+                (*image)->client_data);
+              break;
+            }
+          }
+          if (command_type != InfoCommand)
+            {
+              XConfigureImageColormap(display,resource_info,windows,*image);
+              (void) XConfigureImage(display,resource_info,windows,*image);
+            }
+          XCheckRefreshWindows(display,windows);
+          XInfoWidget(display,windows,text);
+          (void) XSetFunction(display,windows->image.highlight_context,
+            GXinvert);
+          state&=(~UpdateRegionState);
+        }
+      XHighlightRectangle(display,windows->image.id,
+        windows->image.highlight_context,&highlight_info);
+      XScreenEvent(display,windows,&event);
+      if (event.xany.window == windows->command.id)
+        {
+          /*
+            Select a command from the Command widget.
+          */
+          (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+          command_type=NullCommand;
+          id=XCommandWidget(display,windows,ApplyMenu,&event);
+          if (id >= 0)
+            {
+              (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
+              command_type=ApplyCommands[id];
+              if (id < ApplyMenus)
+                {
+                  /*
+                    Select a command from a pop-up menu.
+                  */
+                  entry=XMenuWidget(display,windows,ApplyMenu[id],
+                    (const char **) Menus[id],command);
+                  if (entry >= 0)
+                    {
+                      (void) CopyMagickString(command,Menus[id][entry],
+                        MaxTextExtent);
+                      command_type=Commands[id][entry];
+                    }
+                }
+            }
+          (void) XSetFunction(display,windows->image.highlight_context,
+            GXinvert);
+          XHighlightRectangle(display,windows->image.id,
+            windows->image.highlight_context,&highlight_info);
+          if (command_type == HelpCommand)
+            {
+              (void) XSetFunction(display,windows->image.highlight_context,
+                GXcopy);
+              XTextViewWidget(display,resource_info,windows,MagickFalse,
+                "Help Viewer - Region of Interest",ImageROIHelp);
+              (void) XSetFunction(display,windows->image.highlight_context,
+                GXinvert);
+              continue;
+            }
+          if (command_type == QuitCommand)
+            {
+              /*
+                exit.
+              */
+              state|=EscapeState;
+              state|=ExitState;
+              continue;
+            }
+          if (command_type != NullCommand)
+            state|=UpdateRegionState;
+          continue;
+        }
+      XHighlightRectangle(display,windows->image.id,
+        windows->image.highlight_context,&highlight_info);
+      switch (event.type)
+      {
+        case ButtonPress:
+        {
+          x=windows->image.x;
+          y=windows->image.y;
+          if (event.xbutton.button != Button1)
+            break;
+          if (event.xbutton.window != windows->image.id)
+            break;
+          x=windows->image.x+event.xbutton.x;
+          y=windows->image.y+event.xbutton.y;
+          if ((x < (int) (roi_info.x+RoiDelta)) &&
+              (x > (int) (roi_info.x-RoiDelta)) &&
+              (y < (int) (roi_info.y+RoiDelta)) &&
+              (y > (int) (roi_info.y-RoiDelta)))
+            {
+              roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
+              roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
+              state|=UpdateConfigurationState;
+              break;
+            }
+          if ((x < (int) (roi_info.x+RoiDelta)) &&
+              (x > (int) (roi_info.x-RoiDelta)) &&
+              (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
+              (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
+            {
+              roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
+              state|=UpdateConfigurationState;
+              break;
+            }
+          if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
+              (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
+              (y < (int) (roi_info.y+RoiDelta)) &&
+              (y > (int) (roi_info.y-RoiDelta)))
+            {
+              roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
+              state|=UpdateConfigurationState;
+              break;
+            }
+          if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
+              (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
+              (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
+              (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
+            {
+              state|=UpdateConfigurationState;
+              break;
+            }
+        }
+        case ButtonRelease:
+        {
+          if (event.xbutton.window == windows->pan.id)
+            if ((highlight_info.x != crop_info.x-windows->image.x) ||
+                (highlight_info.y != crop_info.y-windows->image.y))
+              XHighlightRectangle(display,windows->image.id,
+                windows->image.highlight_context,&highlight_info);
+          (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
+            event.xbutton.time);
+          break;
+        }
+        case Expose:
+        {
+          if (event.xexpose.window == windows->image.id)
+            if (event.xexpose.count == 0)
+              {
+                event.xexpose.x=(int) highlight_info.x;
+                event.xexpose.y=(int) highlight_info.y;
+                event.xexpose.width=(int) highlight_info.width;
+                event.xexpose.height=(int) highlight_info.height;
+                XRefreshWindow(display,&windows->image,&event);
+              }
+          if (event.xexpose.window == windows->info.id)
+            if (event.xexpose.count == 0)
+              XInfoWidget(display,windows,text);
+          break;
+        }
+        case KeyPress:
+        {
+          KeySym
+            key_symbol;
+
+          if (event.xkey.window != windows->image.id)
+            break;
+          /*
+            Respond to a user key press.
+          */
+          (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+            sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+          switch ((int) key_symbol)
+          {
+            case XK_Shift_L:
+            case XK_Shift_R:
+              break;
+            case XK_Escape:
+            case XK_F20:
+              state|=EscapeState;
+            case XK_Return:
+            {
+              state|=ExitState;
+              break;
+            }
+            case XK_Home:
+            case XK_KP_Home:
+            {
+              roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
+              roi_info.y=(ssize_t) (windows->image.height/2L-
+                roi_info.height/2L);
+              break;
+            }
+            case XK_Left:
+            case XK_KP_Left:
+            {
+              roi_info.x--;
+              break;
+            }
+            case XK_Up:
+            case XK_KP_Up:
+            case XK_Next:
+            {
+              roi_info.y--;
+              break;
+            }
+            case XK_Right:
+            case XK_KP_Right:
+            {
+              roi_info.x++;
+              break;
+            }
+            case XK_Prior:
+            case XK_Down:
+            case XK_KP_Down:
+            {
+              roi_info.y++;
+              break;
+            }
+            case XK_F1:
+            case XK_Help:
+            {
+              (void) XSetFunction(display,windows->image.highlight_context,
+                GXcopy);
+              XTextViewWidget(display,resource_info,windows,MagickFalse,
+                "Help Viewer - Region of Interest",ImageROIHelp);
+              (void) XSetFunction(display,windows->image.highlight_context,
+                GXinvert);
+              break;
+            }
+            default:
+            {
+              command_type=XImageWindowCommand(display,resource_info,windows,
+                event.xkey.state,key_symbol,image);
+              if (command_type != NullCommand)
+                state|=UpdateRegionState;
+              break;
+            }
+          }
+          (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
+            event.xkey.time);
+          break;
+        }
+        case KeyRelease:
+          break;
+        case MotionNotify:
+        {
+          if (event.xbutton.window != windows->image.id)
+            break;
+          /*
+            Map and unmap Info widget as text cursor crosses its boundaries.
+          */
+          x=event.xmotion.x;
+          y=event.xmotion.y;
+          if (windows->info.mapped != MagickFalse)
+            {
+              if ((x < (int) (windows->info.x+windows->info.width)) &&
+                  (y < (int) (windows->info.y+windows->info.height)))
+                (void) XWithdrawWindow(display,windows->info.id,
+                  windows->info.screen);
+            }
+          else
+            if ((x > (int) (windows->info.x+windows->info.width)) ||
+                (y > (int) (windows->info.y+windows->info.height)))
+              (void) XMapWindow(display,windows->info.id);
+          roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
+          roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
+          break;
+        }
+        case SelectionRequest:
+        {
+          XSelectionEvent
+            notify;
+
+          XSelectionRequestEvent
+            *request;
+
+          /*
+            Set primary selection.
+          */
+          (void) FormatLocaleString(text,MaxTextExtent,
+            "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
+            roi_info.height,(double) roi_info.x,(double) roi_info.y);
+          request=(&(event.xselectionrequest));
+          (void) XChangeProperty(request->display,request->requestor,
+            request->property,request->target,8,PropModeReplace,
+            (unsigned char *) text,(int) strlen(text));
+          notify.type=SelectionNotify;
+          notify.display=request->display;
+          notify.requestor=request->requestor;
+          notify.selection=request->selection;
+          notify.target=request->target;
+          notify.time=request->time;
+          if (request->property == None)
+            notify.property=request->target;
+          else
+            notify.property=request->property;
+          (void) XSendEvent(request->display,request->requestor,False,0,
+            (XEvent *) &notify);
+        }
+        default:
+          break;
+      }
+      if ((state & UpdateConfigurationState) != 0)
+        {
+          (void) XPutBackEvent(display,&event);
+          (void) XCheckDefineCursor(display,windows->image.id,cursor);
+          break;
+        }
+    } while ((state & ExitState) == 0);
+  } while ((state & ExitState) == 0);
+  (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+  XSetCursorState(display,windows,MagickFalse);
+  if ((state & EscapeState) != 0)
+    return(MagickTrue);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X R o t a t e I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XRotateImage() rotates the X image.  If the degrees parameter if zero, the
+%  rotation angle is computed from the slope of a line drawn by the user.
+%
+%  The format of the XRotateImage method is:
+%
+%      MagickBooleanType XRotateImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,double degrees,
+%        Image **image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o degrees: Specifies the number of degrees to rotate the image.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XRotateImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
+{
+  static const char
+    *RotateMenu[] =
+    {
+      "Pixel Color",
+      "Direction",
+      "Help",
+      "Dismiss",
+      (char *) NULL
+    };
+
+  static ModeType
+    direction = HorizontalRotateCommand;
+
+  static const ModeType
+    DirectionCommands[] =
+    {
+      HorizontalRotateCommand,
+      VerticalRotateCommand
+    },
+    RotateCommands[] =
+    {
+      RotateColorCommand,
+      RotateDirectionCommand,
+      RotateHelpCommand,
+      RotateDismissCommand
+    };
+
+  static unsigned int
+    pen_id = 0;
+
+  char
+    command[MaxTextExtent],
+    text[MaxTextExtent];
+
+  Image
+    *rotate_image;
+
+  int
+    id,
+    x,
+    y;
+
+  MagickRealType
+    normalized_degrees;
+
+  register int
+    i;
+
+  unsigned int
+    height,
+    rotations,
+    width;
+
+  if (degrees == 0.0)
+    {
+      unsigned int
+        distance;
+
+      size_t
+        state;
+
+      XEvent
+        event;
+
+      XSegment
+        rotate_info;
+
+      /*
+        Map Command widget.
+      */
+      (void) CloneString(&windows->command.name,"Rotate");
+      windows->command.data=2;
+      (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
+      (void) XMapRaised(display,windows->command.id);
+      XClientMessage(display,windows->image.id,windows->im_protocols,
+        windows->im_update_widget,CurrentTime);
+      /*
+        Wait for first button press.
+      */
+      (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+      XQueryPosition(display,windows->image.id,&x,&y);
+      rotate_info.x1=x;
+      rotate_info.y1=y;
+      rotate_info.x2=x;
+      rotate_info.y2=y;
+      state=DefaultState;
+      do
+      {
+        XHighlightLine(display,windows->image.id,
+          windows->image.highlight_context,&rotate_info);
+        /*
+          Wait for next event.
+        */
+        XScreenEvent(display,windows,&event);
+        XHighlightLine(display,windows->image.id,
+          windows->image.highlight_context,&rotate_info);
+        if (event.xany.window == windows->command.id)
+          {
+            /*
+              Select a command from the Command widget.
+            */
+            id=XCommandWidget(display,windows,RotateMenu,&event);
+            if (id < 0)
+              continue;
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            switch (RotateCommands[id])
+            {
+              case RotateColorCommand:
+              {
+                const char
+                  *ColorMenu[MaxNumberPens];
+
+                int
+                  pen_number;
+
+                XColor
+                  color;
+
+                /*
+                  Initialize menu selections.
+                */
+                for (i=0; i < (int) (MaxNumberPens-2); i++)
+                  ColorMenu[i]=resource_info->pen_colors[i];
+                ColorMenu[MaxNumberPens-2]="Browser...";
+                ColorMenu[MaxNumberPens-1]=(const char *) NULL;
+                /*
+                  Select a pen color from the pop-up menu.
+                */
+                pen_number=XMenuWidget(display,windows,RotateMenu[id],
+                  (const char **) ColorMenu,command);
+                if (pen_number < 0)
+                  break;
+                if (pen_number == (MaxNumberPens-2))
+                  {
+                    static char
+                      color_name[MaxTextExtent] = "gray";
+
+                    /*
+                      Select a pen color from a dialog.
+                    */
+                    resource_info->pen_colors[pen_number]=color_name;
+                    XColorBrowserWidget(display,windows,"Select",color_name);
+                    if (*color_name == '\0')
+                      break;
+                  }
+                /*
+                  Set pen color.
+                */
+                (void) XParseColor(display,windows->map_info->colormap,
+                  resource_info->pen_colors[pen_number],&color);
+                XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
+                  (unsigned int) MaxColors,&color);
+                windows->pixel_info->pen_colors[pen_number]=color;
+                pen_id=(unsigned int) pen_number;
+                break;
+              }
+              case RotateDirectionCommand:
+              {
+                static const char
+                  *Directions[] =
+                  {
+                    "horizontal",
+                    "vertical",
+                    (char *) NULL,
+                  };
+
+                /*
+                  Select a command from the pop-up menu.
+                */
+                id=XMenuWidget(display,windows,RotateMenu[id],
+                  Directions,command);
+                if (id >= 0)
+                  direction=DirectionCommands[id];
+                break;
+              }
+              case RotateHelpCommand:
+              {
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Rotation",ImageRotateHelp);
+                break;
+              }
+              case RotateDismissCommand:
+              {
+                /*
+                  Prematurely exit.
+                */
+                state|=EscapeState;
+                state|=ExitState;
+                break;
+              }
+              default:
+                break;
+            }
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXinvert);
+            continue;
+          }
+        switch (event.type)
+        {
+          case ButtonPress:
+          {
+            if (event.xbutton.button != Button1)
+              break;
+            if (event.xbutton.window != windows->image.id)
+              break;
+            /*
+              exit loop.
+            */
+            (void) XSetFunction(display,windows->image.highlight_context,
+              GXcopy);
+            rotate_info.x1=event.xbutton.x;
+            rotate_info.y1=event.xbutton.y;
+            state|=ExitState;
+            break;
+          }
+          case ButtonRelease:
+            break;
+          case Expose:
+            break;
+          case KeyPress:
+          {
+            char
+              command[MaxTextExtent];
+
+            KeySym
+              key_symbol;
+
+            if (event.xkey.window != windows->image.id)
+              break;
+            /*
+              Respond to a user key press.
+            */
+            (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+              sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+            switch ((int) key_symbol)
+            {
+              case XK_Escape:
+              case XK_F20:
+              {
+                /*
+                  Prematurely exit.
+                */
+                state|=EscapeState;
+                state|=ExitState;
+                break;
+              }
+              case XK_F1:
+              case XK_Help:
+              {
+                (void) XSetFunction(display,windows->image.highlight_context,
+                  GXcopy);
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Rotation",ImageRotateHelp);
+                (void) XSetFunction(display,windows->image.highlight_context,
+                  GXinvert);
+                break;
+              }
+              default:
+              {
+                (void) XBell(display,0);
+                break;
+              }
+            }
+            break;
+          }
+          case MotionNotify:
+          {
+            rotate_info.x1=event.xmotion.x;
+            rotate_info.y1=event.xmotion.y;
+          }
+        }
+        rotate_info.x2=rotate_info.x1;
+        rotate_info.y2=rotate_info.y1;
+        if (direction == HorizontalRotateCommand)
+          rotate_info.x2+=32;
+        else
+          rotate_info.y2-=32;
+      } while ((state & ExitState) == 0);
+      (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      if ((state & EscapeState) != 0)
+        return(MagickTrue);
+      /*
+        Draw line as pointer moves until the mouse button is released.
+      */
+      distance=0;
+      (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
+      state=DefaultState;
+      do
+      {
+        if (distance > 9)
+          {
+            /*
+              Display info and draw rotation line.
+            */
+            if (windows->info.mapped == MagickFalse)
+              (void) XMapWindow(display,windows->info.id);
+            (void) FormatLocaleString(text,MaxTextExtent," %g",
+              direction == VerticalRotateCommand ? degrees-90.0 : degrees);
+            XInfoWidget(display,windows,text);
+            XHighlightLine(display,windows->image.id,
+              windows->image.highlight_context,&rotate_info);
+          }
+        else
+          if (windows->info.mapped != MagickFalse)
+            (void) XWithdrawWindow(display,windows->info.id,
+              windows->info.screen);
+        /*
+          Wait for next event.
+        */
+        XScreenEvent(display,windows,&event);
+        if (distance > 9)
+          XHighlightLine(display,windows->image.id,
+            windows->image.highlight_context,&rotate_info);
+        switch (event.type)
+        {
+          case ButtonPress:
+            break;
+          case ButtonRelease:
+          {
+            /*
+              User has committed to rotation line.
+            */
+            rotate_info.x2=event.xbutton.x;
+            rotate_info.y2=event.xbutton.y;
+            state|=ExitState;
+            break;
+          }
+          case Expose:
+            break;
+          case MotionNotify:
+          {
+            rotate_info.x2=event.xmotion.x;
+            rotate_info.y2=event.xmotion.y;
+          }
+          default:
+            break;
+        }
+        /*
+          Check boundary conditions.
+        */
+        if (rotate_info.x2 < 0)
+          rotate_info.x2=0;
+        else
+          if (rotate_info.x2 > (int) windows->image.width)
+            rotate_info.x2=(short) windows->image.width;
+        if (rotate_info.y2 < 0)
+          rotate_info.y2=0;
+        else
+          if (rotate_info.y2 > (int) windows->image.height)
+            rotate_info.y2=(short) windows->image.height;
+        /*
+          Compute rotation angle from the slope of the line.
+        */
+        degrees=0.0;
+        distance=(unsigned int)
+          ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
+          ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
+        if (distance > 9)
+          degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
+            rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
+      } while ((state & ExitState) == 0);
+      (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      if (distance <= 9)
+        return(MagickTrue);
+    }
+  if (direction == VerticalRotateCommand)
+    degrees-=90.0;
+  if (degrees == 0.0)
+    return(MagickTrue);
+  /*
+    Rotate image.
+  */
+  normalized_degrees=degrees;
+  while (normalized_degrees < -45.0)
+    normalized_degrees+=360.0;
+  for (rotations=0; normalized_degrees > 45.0; rotations++)
+    normalized_degrees-=90.0;
+  if (normalized_degrees != 0.0)
+    (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  (*image)->background_color.red=ScaleShortToQuantum(
+    windows->pixel_info->pen_colors[pen_id].red);
+  (*image)->background_color.green=ScaleShortToQuantum(
+    windows->pixel_info->pen_colors[pen_id].green);
+  (*image)->background_color.blue=ScaleShortToQuantum(
+    windows->pixel_info->pen_colors[pen_id].blue);
+  rotate_image=RotateImage(*image,degrees,&(*image)->exception);
+  XSetCursorState(display,windows,MagickFalse);
+  if (rotate_image == (Image *) NULL)
+    return(MagickFalse);
+  *image=DestroyImage(*image);
+  *image=rotate_image;
+  if (windows->image.crop_geometry != (char *) NULL)
+    {
+      /*
+        Rotate crop geometry.
+      */
+      width=(unsigned int) (*image)->columns;
+      height=(unsigned int) (*image)->rows;
+      (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+      switch (rotations % 4)
+      {
+        default:
+        case 0:
+          break;
+        case 1:
+        {
+          /*
+            Rotate 90 degrees.
+          */
+          (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
+            "%ux%u%+d%+d",height,width,(int) (*image)->columns-
+            (int) height-y,x);
+          break;
+        }
+        case 2:
+        {
+          /*
+            Rotate 180 degrees.
+          */
+          (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
+            "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
+          break;
+        }
+        case 3:
+        {
+          /*
+            Rotate 270 degrees.
+          */
+          (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
+            "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
+          break;
+        }
+      }
+    }
+  if (windows->image.orphan != MagickFalse)
+    return(MagickTrue);
+  if (normalized_degrees != 0.0)
+    {
+      /*
+        Update image colormap.
+      */
+      windows->image.window_changes.width=(int) (*image)->columns;
+      windows->image.window_changes.height=(int) (*image)->rows;
+      if (windows->image.crop_geometry != (char *) NULL)
+        {
+          /*
+            Obtain dimensions of image from crop geometry.
+          */
+          (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
+            &width,&height);
+          windows->image.window_changes.width=(int) width;
+          windows->image.window_changes.height=(int) height;
+        }
+      XConfigureImageColormap(display,resource_info,windows,*image);
+    }
+  else
+    if (((rotations % 4) == 1) || ((rotations % 4) == 3))
+      {
+        windows->image.window_changes.width=windows->image.ximage->height;
+        windows->image.window_changes.height=windows->image.ximage->width;
+      }
+  /*
+    Update image configuration.
+  */
+  (void) XConfigureImage(display,resource_info,windows,*image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S a v e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSaveImage() saves an image to a file.
+%
+%  The format of the XSaveImage method is:
+%
+%      MagickBooleanType XSaveImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XSaveImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  char
+    filename[MaxTextExtent],
+    geometry[MaxTextExtent];
+
+  Image
+    *save_image;
+
+  ImageInfo
+    *image_info;
+
+  MagickStatusType
+    status;
+
+  /*
+    Request file name from user.
+  */
+  if (resource_info->write_filename != (char *) NULL)
+    (void) CopyMagickString(filename,resource_info->write_filename,
+      MaxTextExtent);
+  else
+    {
+      char
+        path[MaxTextExtent];
+
+      int
+        status;
+
+      GetPathComponent(image->filename,HeadPath,path);
+      GetPathComponent(image->filename,TailPath,filename);
+      status=chdir(path);
+      if (status == -1)
+        (void) ThrowMagickException(&image->exception,GetMagickModule(),
+          FileOpenError,"UnableToOpenFile","%s",path);
+    }
+  XFileBrowserWidget(display,windows,"Save",filename);
+  if (*filename == '\0')
+    return(MagickTrue);
+  if (IsPathAccessible(filename) != MagickFalse)
+    {
+      int
+        status;
+
+      /*
+        File exists-- seek user's permission before overwriting.
+      */
+      status=XConfirmWidget(display,windows,"Overwrite",filename);
+      if (status <= 0)
+        return(MagickTrue);
+    }
+  image_info=CloneImageInfo(resource_info->image_info);
+  (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+  (void) SetImageInfo(image_info,1,&image->exception);
+  if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
+      (LocaleCompare(image_info->magick,"JPG") == 0))
+    {
+      char
+        quality[MaxTextExtent];
+
+      int
+        status;
+
+      /*
+        Request JPEG quality from user.
+      */
+      (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
+        image->quality);
+      status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
+        quality);
+      if (*quality == '\0')
+        return(MagickTrue);
+      image->quality=StringToUnsignedLong(quality);
+      image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
+    }
+  if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
+      (LocaleCompare(image_info->magick,"PDF") == 0) ||
+      (LocaleCompare(image_info->magick,"PS") == 0) ||
+      (LocaleCompare(image_info->magick,"PS2") == 0))
+    {
+      char
+        geometry[MaxTextExtent];
+
+      /*
+        Request page geometry from user.
+      */
+      (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
+      if (LocaleCompare(image_info->magick,"PDF") == 0)
+        (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
+      if (image_info->page != (char *) NULL)
+        (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
+      XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
+        "Select page geometry:",geometry);
+      if (*geometry != '\0')
+        image_info->page=GetPageGeometry(geometry);
+    }
+  /*
+    Apply image transforms.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+  if (save_image == (Image *) NULL)
+    return(MagickFalse);
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
+    windows->image.ximage->width,windows->image.ximage->height);
+  (void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
+  /*
+    Write image.
+  */
+  (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
+  status=WriteImage(image_info,save_image);
+  if (status != MagickFalse)
+    image->taint=MagickFalse;
+  save_image=DestroyImage(save_image);
+  image_info=DestroyImageInfo(image_info);
+  XSetCursorState(display,windows,MagickFalse);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S c r e e n E v e n t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XScreenEvent() handles global events associated with the Pan and Magnify
+%  windows.
+%
+%  The format of the XScreenEvent function is:
+%
+%      void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o event: Specifies a pointer to a X11 XEvent structure.
+%
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
+{
+  register XWindows
+    *windows;
+
+  windows=(XWindows *) data;
+  if ((event->type == ClientMessage) &&
+      (event->xclient.window == windows->image.id))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
+{
+  register int
+    x,
+    y;
+
+  (void) XIfEvent(display,event,XPredicate,(char *) windows);
+  if (event->xany.window == windows->command.id)
+    return;
+  switch (event->type)
+  {
+    case ButtonPress:
+    case ButtonRelease:
+    {
+      if ((event->xbutton.button == Button3) &&
+          (event->xbutton.state & Mod1Mask))
+        {
+          /*
+            Convert Alt-Button3 to Button2.
+          */
+          event->xbutton.button=Button2;
+          event->xbutton.state&=(~Mod1Mask);
+        }
+      if (event->xbutton.window == windows->backdrop.id)
+        {
+          (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
+            event->xbutton.time);
+          break;
+        }
+      if (event->xbutton.window == windows->pan.id)
+        {
+          XPanImage(display,windows,event);
+          break;
+        }
+      if (event->xbutton.window == windows->image.id)
+        if (event->xbutton.button == Button2)
+          {
+            /*
+              Update magnified image.
+            */
+            x=event->xbutton.x;
+            y=event->xbutton.y;
+            if (x < 0)
+              x=0;
+            else
+              if (x >= (int) windows->image.width)
+                x=(int) (windows->image.width-1);
+            windows->magnify.x=(int) windows->image.x+x;
+            if (y < 0)
+              y=0;
+            else
+             if (y >= (int) windows->image.height)
+               y=(int) (windows->image.height-1);
+            windows->magnify.y=windows->image.y+y;
+            if (windows->magnify.mapped == MagickFalse)
+              (void) XMapRaised(display,windows->magnify.id);
+            XMakeMagnifyImage(display,windows);
+            if (event->type == ButtonRelease)
+              (void) XWithdrawWindow(display,windows->info.id,
+                windows->info.screen);
+            break;
+          }
+      break;
+    }
+    case ClientMessage:
+    {
+      /*
+        If client window delete message, exit.
+      */
+      if (event->xclient.message_type != windows->wm_protocols)
+        break;
+      if (*event->xclient.data.l != (long) windows->wm_delete_window)
+        break;
+      if (event->xclient.window == windows->magnify.id)
+        {
+          (void) XWithdrawWindow(display,windows->magnify.id,
+            windows->magnify.screen);
+          break;
+        }
+      break;
+    }
+    case ConfigureNotify:
+    {
+      if (event->xconfigure.window == windows->magnify.id)
+        {
+          unsigned int
+            magnify;
+
+          /*
+            Magnify window has a new configuration.
+          */
+          windows->magnify.width=(unsigned int) event->xconfigure.width;
+          windows->magnify.height=(unsigned int) event->xconfigure.height;
+          if (windows->magnify.mapped == MagickFalse)
+            break;
+          magnify=1;
+          while ((int) magnify <= event->xconfigure.width)
+            magnify<<=1;
+          while ((int) magnify <= event->xconfigure.height)
+            magnify<<=1;
+          magnify>>=1;
+          if (((int) magnify != event->xconfigure.width) ||
+              ((int) magnify != event->xconfigure.height))
+            {
+              XWindowChanges
+                window_changes;
+
+              window_changes.width=(int) magnify;
+              window_changes.height=(int) magnify;
+              (void) XReconfigureWMWindow(display,windows->magnify.id,
+                windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
+                &window_changes);
+              break;
+            }
+          XMakeMagnifyImage(display,windows);
+          break;
+        }
+      break;
+    }
+    case Expose:
+    {
+      if (event->xexpose.window == windows->image.id)
+        {
+          XRefreshWindow(display,&windows->image,event);
+          break;
+        }
+      if (event->xexpose.window == windows->pan.id)
+        if (event->xexpose.count == 0)
+          {
+            XDrawPanRectangle(display,windows);
+            break;
+          }
+      if (event->xexpose.window == windows->magnify.id)
+        if (event->xexpose.count == 0)
+          {
+            XMakeMagnifyImage(display,windows);
+            break;
+          }
+      break;
+    }
+    case KeyPress:
+    {
+      char
+        command[MaxTextExtent];
+
+      KeySym
+        key_symbol;
+
+      if (event->xkey.window != windows->magnify.id)
+        break;
+      /*
+        Respond to a user key press.
+      */
+      (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
+        sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+      XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
+      break;
+    }
+    case MapNotify:
+    {
+      if (event->xmap.window == windows->magnify.id)
+        {
+          windows->magnify.mapped=MagickTrue;
+          (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+          break;
+        }
+      if (event->xmap.window == windows->info.id)
+        {
+          windows->info.mapped=MagickTrue;
+          break;
+        }
+      break;
+    }
+    case MotionNotify:
+    {
+      while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
+      if (event->xmotion.window == windows->image.id)
+        if (windows->magnify.mapped != MagickFalse)
+          {
+            /*
+              Update magnified image.
+            */
+            x=event->xmotion.x;
+            y=event->xmotion.y;
+            if (x < 0)
+              x=0;
+            else
+              if (x >= (int) windows->image.width)
+                x=(int) (windows->image.width-1);
+            windows->magnify.x=(int) windows->image.x+x;
+            if (y < 0)
+              y=0;
+            else
+             if (y >= (int) windows->image.height)
+               y=(int) (windows->image.height-1);
+            windows->magnify.y=windows->image.y+y;
+            XMakeMagnifyImage(display,windows);
+          }
+      break;
+    }
+    case UnmapNotify:
+    {
+      if (event->xunmap.window == windows->magnify.id)
+        {
+          windows->magnify.mapped=MagickFalse;
+          break;
+        }
+      if (event->xunmap.window == windows->info.id)
+        {
+          windows->info.mapped=MagickFalse;
+          break;
+        }
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S e t C r o p G e o m e t r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSetCropGeometry() accepts a cropping geometry relative to the Image window
+%  and translates it to a cropping geometry relative to the image.
+%
+%  The format of the XSetCropGeometry method is:
+%
+%      void XSetCropGeometry(Display *display,XWindows *windows,
+%        RectangleInfo *crop_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o crop_info:  A pointer to a RectangleInfo that defines a region of the
+%      Image window to crop.
+%
+%    o image: the image.
+%
+*/
+static void XSetCropGeometry(Display *display,XWindows *windows,
+  RectangleInfo *crop_info,Image *image)
+{
+  char
+    text[MaxTextExtent];
+
+  int
+    x,
+    y;
+
+  MagickRealType
+    scale_factor;
+
+  unsigned int
+    height,
+    width;
+
+  if (windows->info.mapped != MagickFalse)
+    {
+      /*
+        Display info on cropping rectangle.
+      */
+      (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
+        (double) crop_info->width,(double) crop_info->height,(double)
+        crop_info->x,(double) crop_info->y);
+      XInfoWidget(display,windows,text);
+    }
+  /*
+    Cropping geometry is relative to any previous crop geometry.
+  */
+  x=0;
+  y=0;
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  else
+    windows->image.crop_geometry=AcquireString((char *) NULL);
+  /*
+    Define the crop geometry string from the cropping rectangle.
+  */
+  scale_factor=(MagickRealType) width/windows->image.ximage->width;
+  if (crop_info->x > 0)
+    x+=(int) (scale_factor*crop_info->x+0.5);
+  width=(unsigned int) (scale_factor*crop_info->width+0.5);
+  if (width == 0)
+    width=1;
+  scale_factor=(MagickRealType) height/windows->image.ximage->height;
+  if (crop_info->y > 0)
+    y+=(int) (scale_factor*crop_info->y+0.5);
+  height=(unsigned int) (scale_factor*crop_info->height+0.5);
+  if (height == 0)
+    height=1;
+  (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
+    "%ux%u%+d%+d",width,height,x,y);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X T i l e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XTileImage() loads or deletes a selected tile from a visual image directory.
+%  The load or delete command is chosen from a menu.
+%
+%  The format of the XTileImage method is:
+%
+%      Image *XTileImage(Display *display,XResourceInfo *resource_info,
+%        XWindows *windows,Image *image,XEvent *event)
+%
+%  A description of each parameter follows:
+%
+%    o tile_image:  XTileImage reads or deletes the tile image
+%      and returns it.  A null image is returned if an error occurs.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image; returned from ReadImage.
+%
+%    o event: Specifies a pointer to a XEvent structure.  If it is NULL,
+%      the entire image is refreshed.
+%
+*/
+static Image *XTileImage(Display *display,XResourceInfo *resource_info,
+  XWindows *windows,Image *image,XEvent *event)
+{
+  static const char
+    *VerbMenu[] =
+    {
+      "Load",
+      "Next",
+      "Former",
+      "Delete",
+      "Update",
+      (char *) NULL,
+    };
+
+  static const ModeType
+    TileCommands[] =
+    {
+      TileLoadCommand,
+      TileNextCommand,
+      TileFormerCommand,
+      TileDeleteCommand,
+      TileUpdateCommand
+    };
+
+  char
+    command[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  Image
+    *tile_image;
+
+  int
+    id,
+    status,
+    tile,
+    x,
+    y;
+
+  MagickRealType
+    scale_factor;
+
+  register char
+    *p,
+    *q;
+
+  register int
+    i;
+
+  unsigned int
+    height,
+    width;
+
+  /*
+    Tile image is relative to montage image configuration.
+  */
+  x=0;
+  y=0;
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
+  scale_factor=(MagickRealType) width/windows->image.ximage->width;
+  event->xbutton.x+=windows->image.x;
+  event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
+  scale_factor=(MagickRealType) height/windows->image.ximage->height;
+  event->xbutton.y+=windows->image.y;
+  event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
+  /*
+    Determine size and location of each tile in the visual image directory.
+  */
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  (void) XParseGeometry(image->montage,&x,&y,&width,&height);
+  tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
+    (event->xbutton.x-x)/width;
+  if (tile < 0)
+    {
+      /*
+        Button press is outside any tile.
+      */
+      (void) XBell(display,0);
+      return((Image *) NULL);
+    }
+  /*
+    Determine file name from the tile directory.
+  */
+  p=image->directory;
+  for (i=tile; (i != 0) && (*p != '\0'); )
+  {
+    if (*p == '\n')
+      i--;
+    p++;
+  }
+  if (*p == '\0')
+    {
+      /*
+        Button press is outside any tile.
+      */
+      (void) XBell(display,0);
+      return((Image *) NULL);
+    }
+  /*
+    Select a command from the pop-up menu.
+  */
+  id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
+  if (id < 0)
+    return((Image *) NULL);
+  q=p;
+  while ((*q != '\n') && (*q != '\0'))
+    q++;
+  (void) CopyMagickString(filename,p,(size_t) (q-p+1));
+  /*
+    Perform command for the selected tile.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  tile_image=NewImageList();
+  switch (TileCommands[id])
+  {
+    case TileLoadCommand:
+    {
+      /*
+        Load tile image.
+      */
+      XCheckRefreshWindows(display,windows);
+      (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
+        MaxTextExtent);
+      (void) CopyMagickString(resource_info->image_info->filename,filename,
+        MaxTextExtent);
+      tile_image=ReadImage(resource_info->image_info,&image->exception);
+      CatchException(&image->exception);
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      break;
+    }
+    case TileNextCommand:
+    {
+      /*
+        Display next image.
+      */
+      XClientMessage(display,windows->image.id,windows->im_protocols,
+        windows->im_next_image,CurrentTime);
+      break;
+    }
+    case TileFormerCommand:
+    {
+      /*
+        Display former image.
+      */
+      XClientMessage(display,windows->image.id,windows->im_protocols,
+        windows->im_former_image,CurrentTime);
+      break;
+    }
+    case TileDeleteCommand:
+    {
+      /*
+        Delete tile image.
+      */
+      if (IsPathAccessible(filename) == MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Image file does not exist:",filename);
+          break;
+        }
+      status=XConfirmWidget(display,windows,"Really delete tile",filename);
+      if (status <= 0)
+        break;
+      status=remove(filename) != 0 ? MagickTrue : MagickFalse;
+      if (status != MagickFalse)
+        {
+          XNoticeWidget(display,windows,"Unable to delete image file:",
+            filename);
+          break;
+        }
+    }
+    case TileUpdateCommand:
+    {
+      ExceptionInfo
+        *exception;
+
+      int
+        x_offset,
+        y_offset;
+
+      PixelPacket
+        pixel;
+
+      register int
+        j;
+
+      register Quantum
+        *s;
+
+      /*
+        Ensure all the images exist.
+      */
+      tile=0;
+      for (p=image->directory; *p != '\0'; p++)
+      {
+        CacheView
+          *image_view;
+
+        q=p;
+        while ((*q != '\n') && (*q != '\0'))
+          q++;
+        (void) CopyMagickString(filename,p,(size_t) (q-p+1));
+        p=q;
+        if (IsPathAccessible(filename) != MagickFalse)
+          {
+            tile++;
+            continue;
+          }
+        /*
+          Overwrite tile with background color.
+        */
+        x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
+        y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
+        exception=(&image->exception);
+        image_view=AcquireCacheView(image);
+        (void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
+        for (i=0; i < (int) height; i++)
+        {
+          s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
+            y_offset+i,width,1,exception);
+          if (s == (Quantum *) NULL)
+            break;
+          for (j=0; j < (int) width; j++)
+          {
+            SetPixelPacket(image,&pixel,s);
+            s+=GetPixelChannels(image);
+          }
+          if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+            break;
+        }
+        image_view=DestroyCacheView(image_view);
+        tile++;
+      }
+      windows->image.window_changes.width=(int) image->columns;
+      windows->image.window_changes.height=(int) image->rows;
+      XConfigureImageColormap(display,resource_info,windows,image);
+      (void) XConfigureImage(display,resource_info,windows,image);
+      break;
+    }
+    default:
+      break;
+  }
+  XSetCursorState(display,windows,MagickFalse);
+  return(tile_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X T r a n s l a t e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XTranslateImage() translates the image within an Image window by one pixel
+%  as specified by the key symbol.  If the image has a `montage string the
+%  translation is respect to the width and height contained within the string.
+%
+%  The format of the XTranslateImage method is:
+%
+%      void XTranslateImage(Display *display,XWindows *windows,
+%        Image *image,const KeySym key_symbol)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+%    o key_symbol: Specifies a KeySym which indicates which side of the image
+%      to trim.
+%
+*/
+static void XTranslateImage(Display *display,XWindows *windows,
+  Image *image,const KeySym key_symbol)
+{
+  char
+    text[MaxTextExtent];
+
+  int
+    x,
+    y;
+
+  unsigned int
+    x_offset,
+    y_offset;
+
+  /*
+    User specified a pan position offset.
+  */
+  x_offset=windows->image.width;
+  y_offset=windows->image.height;
+  if (image->montage != (char *) NULL)
+    (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
+  switch ((int) key_symbol)
+  {
+    case XK_Home:
+    case XK_KP_Home:
+    {
+      windows->image.x=(int) windows->image.width/2;
+      windows->image.y=(int) windows->image.height/2;
+      break;
+    }
+    case XK_Left:
+    case XK_KP_Left:
+    {
+      windows->image.x-=x_offset;
+      break;
+    }
+    case XK_Next:
+    case XK_Up:
+    case XK_KP_Up:
+    {
+      windows->image.y-=y_offset;
+      break;
+    }
+    case XK_Right:
+    case XK_KP_Right:
+    {
+      windows->image.x+=x_offset;
+      break;
+    }
+    case XK_Prior:
+    case XK_Down:
+    case XK_KP_Down:
+    {
+      windows->image.y+=y_offset;
+      break;
+    }
+    default:
+      return;
+  }
+  /*
+    Check boundary conditions.
+  */
+  if (windows->image.x < 0)
+    windows->image.x=0;
+  else
+    if ((int) (windows->image.x+windows->image.width) >
+        windows->image.ximage->width)
+      windows->image.x=(int) windows->image.ximage->width-windows->image.width;
+  if (windows->image.y < 0)
+    windows->image.y=0;
+  else
+    if ((int) (windows->image.y+windows->image.height) >
+        windows->image.ximage->height)
+      windows->image.y=(int) windows->image.ximage->height-windows->image.height;
+  /*
+    Refresh Image window.
+  */
+  (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
+    windows->image.width,windows->image.height,windows->image.x,
+    windows->image.y);
+  XInfoWidget(display,windows,text);
+  XCheckRefreshWindows(display,windows);
+  XDrawPanRectangle(display,windows);
+  XRefreshWindow(display,&windows->image,(XEvent *) NULL);
+  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X T r i m I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XTrimImage() trims the edges from the Image window.
+%
+%  The format of the XTrimImage method is:
+%
+%      MagickBooleanType XTrimImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+static MagickBooleanType XTrimImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  RectangleInfo
+    trim_info;
+
+  register int
+    x,
+    y;
+
+  size_t
+    background,
+    pixel;
+
+  /*
+    Trim edges from image.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  /*
+    Crop the left edge.
+  */
+  background=XGetPixel(windows->image.ximage,0,0);
+  trim_info.width=(size_t) windows->image.ximage->width;
+  for (x=0; x < windows->image.ximage->width; x++)
+  {
+    for (y=0; y < windows->image.ximage->height; y++)
+    {
+      pixel=XGetPixel(windows->image.ximage,x,y);
+      if (pixel != background)
+        break;
+    }
+    if (y < windows->image.ximage->height)
+      break;
+  }
+  trim_info.x=(ssize_t) x;
+  if (trim_info.x == (ssize_t) windows->image.ximage->width)
+    {
+      XSetCursorState(display,windows,MagickFalse);
+      return(MagickFalse);
+    }
+  /*
+    Crop the right edge.
+  */
+  background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
+  for (x=windows->image.ximage->width-1; x != 0; x--)
+  {
+    for (y=0; y < windows->image.ximage->height; y++)
+    {
+      pixel=XGetPixel(windows->image.ximage,x,y);
+      if (pixel != background)
+        break;
+    }
+    if (y < windows->image.ximage->height)
+      break;
+  }
+  trim_info.width=(size_t) (x-trim_info.x+1);
+  /*
+    Crop the top edge.
+  */
+  background=XGetPixel(windows->image.ximage,0,0);
+  trim_info.height=(size_t) windows->image.ximage->height;
+  for (y=0; y < windows->image.ximage->height; y++)
+  {
+    for (x=0; x < windows->image.ximage->width; x++)
+    {
+      pixel=XGetPixel(windows->image.ximage,x,y);
+      if (pixel != background)
+        break;
+    }
+    if (x < windows->image.ximage->width)
+      break;
+  }
+  trim_info.y=(ssize_t) y;
+  /*
+    Crop the bottom edge.
+  */
+  background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
+  for (y=windows->image.ximage->height-1; y != 0; y--)
+  {
+    for (x=0; x < windows->image.ximage->width; x++)
+    {
+      pixel=XGetPixel(windows->image.ximage,x,y);
+      if (pixel != background)
+        break;
+    }
+    if (x < windows->image.ximage->width)
+      break;
+  }
+  trim_info.height=(size_t) y-trim_info.y+1;
+  if (((unsigned int) trim_info.width != windows->image.width) ||
+      ((unsigned int) trim_info.height != windows->image.height))
+    {
+      /*
+        Reconfigure Image window as defined by the trimming rectangle.
+      */
+      XSetCropGeometry(display,windows,&trim_info,image);
+      windows->image.window_changes.width=(int) trim_info.width;
+      windows->image.window_changes.height=(int) trim_info.height;
+      (void) XConfigureImage(display,resource_info,windows,image);
+    }
+  XSetCursorState(display,windows,MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X V i s u a l D i r e c t o r y I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XVisualDirectoryImage() creates a Visual Image Directory.
+%
+%  The format of the XVisualDirectoryImage method is:
+%
+%      Image *XVisualDirectoryImage(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows)
+%
+%  A description of each parameter follows:
+%
+%    o nexus: Method XVisualDirectoryImage returns a visual image
+%      directory if it can be created successfully.  Otherwise a null image
+%      is returned.
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+*/
+static Image *XVisualDirectoryImage(Display *display,
+  XResourceInfo *resource_info,XWindows *windows)
+{
+#define TileImageTag  "Scale/Image"
+#define XClientName  "montage"
+
+  char
+    **filelist;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *images,
+    *montage_image,
+    *next_image,
+    *thumbnail_image;
+
+  ImageInfo
+    *read_info;
+
+  int
+    number_files;
+
+  MagickBooleanType
+    backdrop;
+
+  MagickStatusType
+    status;
+
+  MontageInfo
+    *montage_info;
+
+  RectangleInfo
+    geometry;
+
+  register int
+    i;
+
+  static char
+    filename[MaxTextExtent] = "\0",
+    filenames[MaxTextExtent] = "*";
+
+  XResourceInfo
+    background_resources;
+
+  /*
+    Request file name from user.
+  */
+  XFileBrowserWidget(display,windows,"Directory",filenames);
+  if (*filenames == '\0')
+    return((Image *) NULL);
+  /*
+    Expand the filenames.
+  */
+  filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
+  if (filelist == (char **) NULL)
+    {
+      ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
+        filenames);
+      return((Image *) NULL);
+    }
+  number_files=1;
+  filelist[0]=filenames;
+  status=ExpandFilenames(&number_files,&filelist);
+  if ((status == MagickFalse) || (number_files == 0))
+    {
+      if (number_files == 0)
+        ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
+      else
+        ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
+          filenames);
+      return((Image *) NULL);
+    }
+  /*
+    Set image background resources.
+  */
+  background_resources=(*resource_info);
+  background_resources.window_id=AcquireString("");
+  (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
+    "0x%lx",windows->image.id);
+  background_resources.backdrop=MagickTrue;
+  /*
+    Read each image and convert them to a tile.
+  */
+  backdrop=(windows->visual_info->klass == TrueColor) ||
+    (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
+  read_info=CloneImageInfo(resource_info->image_info);
+  (void) SetImageOption(read_info,"jpeg:size","120x120");
+  (void) CloneString(&read_info->size,DefaultTileGeometry);
+  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
+    (void *) NULL);
+  images=NewImageList();
+  exception=AcquireExceptionInfo();
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  for (i=0; i < (int) number_files; i++)
+  {
+    (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
+    filelist[i]=DestroyString(filelist[i]);
+    *read_info->magick='\0';
+    next_image=ReadImage(read_info,exception);
+    CatchException(exception);
+    if (next_image != (Image *) NULL)
+      {
+        (void) DeleteImageProperty(next_image,"label");
+        (void) SetImageProperty(next_image,"label",InterpretImageProperties(
+          read_info,next_image,DefaultTileLabel));
+        (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
+          exception);
+        thumbnail_image=ThumbnailImage(next_image,geometry.width,
+          geometry.height,exception);
+        if (thumbnail_image != (Image *) NULL)
+          {
+            next_image=DestroyImage(next_image);
+            next_image=thumbnail_image;
+          }
+        if (backdrop)
+          {
+            (void) XDisplayBackgroundImage(display,&background_resources,
+              next_image);
+            XSetCursorState(display,windows,MagickTrue);
+          }
+        AppendImageToList(&images,next_image);
+        if (images->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
+              (MagickSizeType) number_files);
+            if (proceed == MagickFalse)
+              break;
+          }
+      }
+  }
+  exception=DestroyExceptionInfo(exception);
+  filelist=(char **) RelinquishMagickMemory(filelist);
+  if (images == (Image *) NULL)
+    {
+      read_info=DestroyImageInfo(read_info);
+      XSetCursorState(display,windows,MagickFalse);
+      ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
+      return((Image *) NULL);
+    }
+  /*
+    Create the Visual Image Directory.
+  */
+  montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
+  montage_info->pointsize=10;
+  if (resource_info->font != (char *) NULL)
+    (void) CloneString(&montage_info->font,resource_info->font);
+  (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
+  montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
+    images),&images->exception);
+  images=DestroyImageList(images);
+  montage_info=DestroyMontageInfo(montage_info);
+  read_info=DestroyImageInfo(read_info);
+  XSetCursorState(display,windows,MagickFalse);
+  if (montage_image == (Image *) NULL)
+    return(montage_image);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_next_image,CurrentTime);
+  return(montage_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D i s p l a y B a c k g r o u n d I m a g e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDisplayBackgroundImage() displays an image in the background of a window.
+%
+%  The format of the XDisplayBackgroundImage method is:
+%
+%      MagickBooleanType XDisplayBackgroundImage(Display *display,
+%        XResourceInfo *resource_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
+  XResourceInfo *resource_info,Image *image)
+{
+  char
+    geometry[MaxTextExtent],
+    visual_type[MaxTextExtent];
+
+  int
+    height,
+    status,
+    width;
+
+  RectangleInfo
+    geometry_info;
+
+  static XPixelInfo
+    pixel;
+
+  static XStandardColormap
+    *map_info;
+
+  static XVisualInfo
+    *visual_info = (XVisualInfo *) NULL;
+
+  static XWindowInfo
+    window_info;
+
+  size_t
+    delay;
+
+  Window
+    root_window;
+
+  XGCValues
+    context_values;
+
+  XResourceInfo
+    resources;
+
+  XWindowAttributes
+    window_attributes;
+
+  /*
+    Determine target window.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  resources=(*resource_info);
+  window_info.id=(Window) NULL;
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  if (LocaleCompare(resources.window_id,"root") == 0)
+    window_info.id=root_window;
+  else
+    {
+      if (isdigit((unsigned char) *resources.window_id) != 0)
+        window_info.id=XWindowByID(display,root_window,
+          (Window) strtol((char *) resources.window_id,(char **) NULL,0));
+      if (window_info.id == (Window) NULL)
+        window_info.id=XWindowByName(display,root_window,resources.window_id);
+    }
+  if (window_info.id == (Window) NULL)
+    {
+      ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
+        resources.window_id);
+      return(MagickFalse);
+    }
+  /*
+    Determine window visual id.
+  */
+  window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
+  window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
+  (void) CopyMagickString(visual_type,"default",MaxTextExtent);
+  status=XGetWindowAttributes(display,window_info.id,&window_attributes);
+  if (status != 0)
+    (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
+      XVisualIDFromVisual(window_attributes.visual));
+  if (visual_info == (XVisualInfo *) NULL)
+    {
+      /*
+        Allocate standard colormap.
+      */
+      map_info=XAllocStandardColormap();
+      if (map_info == (XStandardColormap *) NULL)
+        ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
+          image->filename);
+      map_info->colormap=(Colormap) NULL;
+      pixel.pixels=(unsigned long *) NULL;
+      /*
+        Initialize visual info.
+      */
+      resources.map_type=(char *) NULL;
+      resources.visual_type=visual_type;
+      visual_info=XBestVisualInfo(display,map_info,&resources);
+      if (visual_info == (XVisualInfo *) NULL)
+        ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
+          resources.visual_type);
+      /*
+        Initialize window info.
+      */
+      window_info.ximage=(XImage *) NULL;
+      window_info.matte_image=(XImage *) NULL;
+      window_info.pixmap=(Pixmap) NULL;
+      window_info.matte_pixmap=(Pixmap) NULL;
+    }
+  /*
+    Free previous root colors.
+  */
+  if (window_info.id == root_window)
+    (void) XDestroyWindowColors(display,root_window);
+  /*
+    Initialize Standard Colormap.
+  */
+  resources.colormap=SharedColormap;
+  XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
+  /*
+    Graphic context superclass.
+  */
+  context_values.background=pixel.background_color.pixel;
+  context_values.foreground=pixel.foreground_color.pixel;
+  pixel.annotate_context=XCreateGC(display,window_info.id,
+    (size_t) (GCBackground | GCForeground),&context_values);
+  if (pixel.annotate_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      image->filename);
+  /*
+    Initialize Image window attributes.
+  */
+  window_info.name=AcquireString("\0");
+  window_info.icon_name=AcquireString("\0");
+  XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
+    &resources,&window_info);
+  /*
+    Create the X image.
+  */
+  window_info.width=(unsigned int) image->columns;
+  window_info.height=(unsigned int) image->rows;
+  if ((image->columns != window_info.width) ||
+      (image->rows != window_info.height))
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      image->filename);
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
+    window_attributes.width,window_attributes.height);
+  geometry_info.width=window_info.width;
+  geometry_info.height=window_info.height;
+  geometry_info.x=(ssize_t) window_info.x;
+  geometry_info.y=(ssize_t) window_info.y;
+  (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
+    &geometry_info.width,&geometry_info.height);
+  window_info.width=(unsigned int) geometry_info.width;
+  window_info.height=(unsigned int) geometry_info.height;
+  window_info.x=(int) geometry_info.x;
+  window_info.y=(int) geometry_info.y;
+  status=XMakeImage(display,&resources,&window_info,image,window_info.width,
+    window_info.height);
+  if (status == MagickFalse)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      image->filename);
+  window_info.x=0;
+  window_info.y=0;
+  if (image->debug != MagickFalse)
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
+        (double) image->columns,(double) image->rows);
+      if (image->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
+          image->colors);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
+    }
+  /*
+    Adjust image dimensions as specified by backdrop or geometry options.
+  */
+  width=(int) window_info.width;
+  height=(int) window_info.height;
+  if (resources.backdrop != MagickFalse)
+    {
+      /*
+        Center image on window.
+      */
+      window_info.x=(window_attributes.width/2)-
+        (window_info.ximage->width/2);
+      window_info.y=(window_attributes.height/2)-
+        (window_info.ximage->height/2);
+      width=window_attributes.width;
+      height=window_attributes.height;
+    }
+  if ((resources.image_geometry != (char *) NULL) &&
+      (*resources.image_geometry != '\0'))
+    {
+      char
+        default_geometry[MaxTextExtent];
+
+      int
+        flags,
+        gravity;
+
+      XSizeHints
+        *size_hints;
+
+      /*
+        User specified geometry.
+      */
+      size_hints=XAllocSizeHints();
+      if (size_hints == (XSizeHints *) NULL)
+        ThrowXWindowFatalException(ResourceLimitFatalError,
+          "MemoryAllocationFailed",image->filename);
+      size_hints->flags=0L;
+      (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
+        width,height);
+      flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
+        default_geometry,window_info.border_width,size_hints,&window_info.x,
+        &window_info.y,&width,&height,&gravity);
+      if (flags & (XValue | YValue))
+        {
+          width=window_attributes.width;
+          height=window_attributes.height;
+        }
+      (void) XFree((void *) size_hints);
+    }
+  /*
+    Create the X pixmap.
+  */
+  window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
+    (unsigned int) height,window_info.depth);
+  if (window_info.pixmap == (Pixmap) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
+      image->filename);
+  /*
+    Display pixmap on the window.
+  */
+  if (((unsigned int) width > window_info.width) ||
+      ((unsigned int) height > window_info.height))
+    (void) XFillRectangle(display,window_info.pixmap,
+      window_info.annotate_context,0,0,(unsigned int) width,
+      (unsigned int) height);
+  (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
+    window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
+    window_info.width,(unsigned int) window_info.height);
+  (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
+  (void) XClearWindow(display,window_info.id);
+  delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
+  XDelay(display,delay == 0UL ? 10UL : delay);
+  (void) XSync(display,MagickFalse);
+  return(window_info.id == root_window ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D i s p l a y I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDisplayImage() displays an image via X11.  A new image is created and
+%  returned if the user interactively transforms the displayed image.
+%
+%  The format of the XDisplayImage method is:
+%
+%      Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
+%        char **argv,int argc,Image **image,size_t *state)
+%
+%  A description of each parameter follows:
+%
+%    o nexus:  Method XDisplayImage returns an image when the
+%      user chooses 'Open Image' from the command menu or picks a tile
+%      from the image directory.  Otherwise a null image is returned.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o argv: Specifies the application's argument list.
+%
+%    o argc: Specifies the number of arguments.
+%
+%    o image: Specifies an address to an address of an Image structure;
+%
+*/
+MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
+  char **argv,int argc,Image **image,size_t *state)
+{
+#define MagnifySize  256  /* must be a power of 2 */
+#define MagickMenus  10
+#define MagickTitle  "Commands"
+
+  static const char
+    *CommandMenu[] =
+    {
+      "File",
+      "Edit",
+      "View",
+      "Transform",
+      "Enhance",
+      "Effects",
+      "F/X",
+      "Image Edit",
+      "Miscellany",
+      "Help",
+      (char *) NULL
+    },
+    *FileMenu[] =
+    {
+      "Open...",
+      "Next",
+      "Former",
+      "Select...",
+      "Save...",
+      "Print...",
+      "Delete...",
+      "New...",
+      "Visual Directory...",
+      "Quit",
+      (char *) NULL
+    },
+    *EditMenu[] =
+    {
+      "Undo",
+      "Redo",
+      "Cut",
+      "Copy",
+      "Paste",
+      (char *) NULL
+    },
+    *ViewMenu[] =
+    {
+      "Half Size",
+      "Original Size",
+      "Double Size",
+      "Resize...",
+      "Apply",
+      "Refresh",
+      "Restore",
+      (char *) NULL
+    },
+    *TransformMenu[] =
+    {
+      "Crop",
+      "Chop",
+      "Flop",
+      "Flip",
+      "Rotate Right",
+      "Rotate Left",
+      "Rotate...",
+      "Shear...",
+      "Roll...",
+      "Trim Edges",
+      (char *) NULL
+    },
+    *EnhanceMenu[] =
+    {
+      "Hue...",
+      "Saturation...",
+      "Brightness...",
+      "Gamma...",
+      "Spiff",
+      "Dull",
+      "Contrast Stretch...",
+      "Sigmoidal Contrast...",
+      "Normalize",
+      "Equalize",
+      "Negate",
+      "Grayscale",
+      "Map...",
+      "Quantize...",
+      (char *) NULL
+    },
+    *EffectsMenu[] =
+    {
+      "Despeckle",
+      "Emboss",
+      "Reduce Noise",
+      "Add Noise...",
+      "Sharpen...",
+      "Blur...",
+      "Threshold...",
+      "Edge Detect...",
+      "Spread...",
+      "Shade...",
+      "Raise...",
+      "Segment...",
+      (char *) NULL
+    },
+    *FXMenu[] =
+    {
+      "Solarize...",
+      "Sepia Tone...",
+      "Swirl...",
+      "Implode...",
+      "Vignette...",
+      "Wave...",
+      "Oil Paint...",
+      "Charcoal Draw...",
+      (char *) NULL
+    },
+    *ImageEditMenu[] =
+    {
+      "Annotate...",
+      "Draw...",
+      "Color...",
+      "Matte...",
+      "Composite...",
+      "Add Border...",
+      "Add Frame...",
+      "Comment...",
+      "Launch...",
+      "Region of Interest...",
+      (char *) NULL
+    },
+    *MiscellanyMenu[] =
+    {
+      "Image Info",
+      "Zoom Image",
+      "Show Preview...",
+      "Show Histogram",
+      "Show Matte",
+      "Background...",
+      "Slide Show...",
+      "Preferences...",
+      (char *) NULL
+    },
+    *HelpMenu[] =
+    {
+      "Overview",
+      "Browse Documentation",
+      "About Display",
+      (char *) NULL
+    },
+    *ShortCutsMenu[] =
+    {
+      "Next",
+      "Former",
+      "Open...",
+      "Save...",
+      "Print...",
+      "Undo",
+      "Restore",
+      "Image Info",
+      "Quit",
+      (char *) NULL
+    },
+    *VirtualMenu[] =
+    {
+      "Image Info",
+      "Print",
+      "Next",
+      "Quit",
+      (char *) NULL
+    };
+
+  static const char
+    **Menus[MagickMenus] =
+    {
+      FileMenu,
+      EditMenu,
+      ViewMenu,
+      TransformMenu,
+      EnhanceMenu,
+      EffectsMenu,
+      FXMenu,
+      ImageEditMenu,
+      MiscellanyMenu,
+      HelpMenu
+    };
+
+  static CommandType
+    CommandMenus[] =
+    {
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+      NullCommand,
+    },
+    FileCommands[] =
+    {
+      OpenCommand,
+      NextCommand,
+      FormerCommand,
+      SelectCommand,
+      SaveCommand,
+      PrintCommand,
+      DeleteCommand,
+      NewCommand,
+      VisualDirectoryCommand,
+      QuitCommand
+    },
+    EditCommands[] =
+    {
+      UndoCommand,
+      RedoCommand,
+      CutCommand,
+      CopyCommand,
+      PasteCommand
+    },
+    ViewCommands[] =
+    {
+      HalfSizeCommand,
+      OriginalSizeCommand,
+      DoubleSizeCommand,
+      ResizeCommand,
+      ApplyCommand,
+      RefreshCommand,
+      RestoreCommand
+    },
+    TransformCommands[] =
+    {
+      CropCommand,
+      ChopCommand,
+      FlopCommand,
+      FlipCommand,
+      RotateRightCommand,
+      RotateLeftCommand,
+      RotateCommand,
+      ShearCommand,
+      RollCommand,
+      TrimCommand
+    },
+    EnhanceCommands[] =
+    {
+      HueCommand,
+      SaturationCommand,
+      BrightnessCommand,
+      GammaCommand,
+      SpiffCommand,
+      DullCommand,
+      ContrastStretchCommand,
+      SigmoidalContrastCommand,
+      NormalizeCommand,
+      EqualizeCommand,
+      NegateCommand,
+      GrayscaleCommand,
+      MapCommand,
+      QuantizeCommand
+    },
+    EffectsCommands[] =
+    {
+      DespeckleCommand,
+      EmbossCommand,
+      ReduceNoiseCommand,
+      AddNoiseCommand,
+      SharpenCommand,
+      BlurCommand,
+      ThresholdCommand,
+      EdgeDetectCommand,
+      SpreadCommand,
+      ShadeCommand,
+      RaiseCommand,
+      SegmentCommand
+    },
+    FXCommands[] =
+    {
+      SolarizeCommand,
+      SepiaToneCommand,
+      SwirlCommand,
+      ImplodeCommand,
+      VignetteCommand,
+      WaveCommand,
+      OilPaintCommand,
+      CharcoalDrawCommand
+    },
+    ImageEditCommands[] =
+    {
+      AnnotateCommand,
+      DrawCommand,
+      ColorCommand,
+      MatteCommand,
+      CompositeCommand,
+      AddBorderCommand,
+      AddFrameCommand,
+      CommentCommand,
+      LaunchCommand,
+      RegionofInterestCommand
+    },
+    MiscellanyCommands[] =
+    {
+      InfoCommand,
+      ZoomCommand,
+      ShowPreviewCommand,
+      ShowHistogramCommand,
+      ShowMatteCommand,
+      BackgroundCommand,
+      SlideShowCommand,
+      PreferencesCommand
+    },
+    HelpCommands[] =
+    {
+      HelpCommand,
+      BrowseDocumentationCommand,
+      VersionCommand
+    },
+    ShortCutsCommands[] =
+    {
+      NextCommand,
+      FormerCommand,
+      OpenCommand,
+      SaveCommand,
+      PrintCommand,
+      UndoCommand,
+      RestoreCommand,
+      InfoCommand,
+      QuitCommand
+    },
+    VirtualCommands[] =
+    {
+      InfoCommand,
+      PrintCommand,
+      NextCommand,
+      QuitCommand
+    };
+
+  static CommandType
+    *Commands[MagickMenus] =
+    {
+      FileCommands,
+      EditCommands,
+      ViewCommands,
+      TransformCommands,
+      EnhanceCommands,
+      EffectsCommands,
+      FXCommands,
+      ImageEditCommands,
+      MiscellanyCommands,
+      HelpCommands
+    };
+
+  char
+    command[MaxTextExtent],
+    *directory,
+    geometry[MaxTextExtent],
+    resource_name[MaxTextExtent];
+
+  CommandType
+    command_type;
+
+  Image
+    *display_image,
+    *nexus;
+
+  int
+    entry,
+    id;
+
+  KeySym
+    key_symbol;
+
+  MagickStatusType
+    context_mask,
+    status;
+
+  RectangleInfo
+    geometry_info;
+
+  register int
+    i;
+
+  static char
+    working_directory[MaxTextExtent];
+
+  static XPoint
+    vid_info;
+
+  static XWindowInfo
+    *magick_windows[MaxXWindows];
+
+  static unsigned int
+    number_windows;
+
+  struct stat
+    attributes;
+
+  time_t
+    timer,
+    timestamp,
+    update_time;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    delay;
+
+  WarningHandler
+    warning_handler;
+
+  Window
+    root_window;
+
+  XClassHint
+    *class_hints;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XGCValues
+    context_values;
+
+  XPixelInfo
+    *icon_pixel,
+    *pixel;
+
+  XResourceInfo
+    *icon_resources;
+
+  XStandardColormap
+    *icon_map,
+    *map_info;
+
+  XVisualInfo
+    *icon_visual,
+    *visual_info;
+
+  XWindowChanges
+    window_changes;
+
+  XWindows
+    *windows;
+
+  XWMHints
+    *manager_hints;
+
+  assert(image != (Image **) NULL);
+  assert((*image)->signature == MagickSignature);
+  if ((*image)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
+  display_image=(*image);
+  warning_handler=(WarningHandler) NULL;
+  windows=XSetWindows((XWindows *) ~0);
+  if (windows != (XWindows *) NULL)
+    {
+      int
+        status;
+
+      status=chdir(working_directory);
+      if (status == -1)
+        (void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
+          FileOpenError,"UnableToOpenFile","%s",working_directory);
+      warning_handler=resource_info->display_warnings ?
+        SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
+      warning_handler=resource_info->display_warnings ?
+        SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
+    }
+  else
+    {
+      /*
+        Allocate windows structure.
+      */
+      resource_info->colors=display_image->colors;
+      windows=XSetWindows(XInitializeWindows(display,resource_info));
+      if (windows == (XWindows *) NULL)
+        ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
+          (*image)->filename);
+      /*
+        Initialize window id's.
+      */
+      number_windows=0;
+      magick_windows[number_windows++]=(&windows->icon);
+      magick_windows[number_windows++]=(&windows->backdrop);
+      magick_windows[number_windows++]=(&windows->image);
+      magick_windows[number_windows++]=(&windows->info);
+      magick_windows[number_windows++]=(&windows->command);
+      magick_windows[number_windows++]=(&windows->widget);
+      magick_windows[number_windows++]=(&windows->popup);
+      magick_windows[number_windows++]=(&windows->magnify);
+      magick_windows[number_windows++]=(&windows->pan);
+      for (i=0; i < (int) number_windows; i++)
+        magick_windows[i]->id=(Window) NULL;
+      vid_info.x=0;
+      vid_info.y=0;
+    }
+  /*
+    Initialize font info.
+  */
+  if (windows->font_info != (XFontStruct *) NULL)
+    (void) XFreeFont(display,windows->font_info);
+  windows->font_info=XBestFont(display,resource_info,MagickFalse);
+  if (windows->font_info == (XFontStruct *) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
+      resource_info->font);
+  /*
+    Initialize Standard Colormap.
+  */
+  map_info=windows->map_info;
+  icon_map=windows->icon_map;
+  visual_info=windows->visual_info;
+  icon_visual=windows->icon_visual;
+  pixel=windows->pixel_info;
+  icon_pixel=windows->icon_pixel;
+  font_info=windows->font_info;
+  icon_resources=windows->icon_resources;
+  class_hints=windows->class_hints;
+  manager_hints=windows->manager_hints;
+  root_window=XRootWindow(display,visual_info->screen);
+  nexus=NewImageList();
+  if (display_image->debug != MagickFalse)
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
+        (double) display_image->scene,(double) display_image->columns,
+        (double) display_image->rows);
+      if (display_image->colors != 0)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
+          display_image->colors);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
+        display_image->magick);
+    }
+  XMakeStandardColormap(display,visual_info,resource_info,display_image,
+    map_info,pixel);
+  display_image->taint=MagickFalse;
+  /*
+    Initialize graphic context.
+  */
+  windows->context.id=(Window) NULL;
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->context);
+  (void) CloneString(&class_hints->res_name,resource_info->client_name);
+  (void) CloneString(&class_hints->res_class,resource_info->client_name);
+  class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
+  manager_hints->flags=InputHint | StateHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=WithdrawnState;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->context);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (context)",windows->context.id);
+  context_values.background=pixel->background_color.pixel;
+  context_values.font=font_info->fid;
+  context_values.foreground=pixel->foreground_color.pixel;
+  context_values.graphics_exposures=MagickFalse;
+  context_mask=(MagickStatusType)
+    (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
+  if (pixel->annotate_context != (GC) NULL)
+    (void) XFreeGC(display,pixel->annotate_context);
+  pixel->annotate_context=XCreateGC(display,windows->context.id,
+    context_mask,&context_values);
+  if (pixel->annotate_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      display_image->filename);
+  context_values.background=pixel->depth_color.pixel;
+  if (pixel->widget_context != (GC) NULL)
+    (void) XFreeGC(display,pixel->widget_context);
+  pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
+    &context_values);
+  if (pixel->widget_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      display_image->filename);
+  context_values.background=pixel->foreground_color.pixel;
+  context_values.foreground=pixel->background_color.pixel;
+  context_values.plane_mask=context_values.background ^
+    context_values.foreground;
+  if (pixel->highlight_context != (GC) NULL)
+    (void) XFreeGC(display,pixel->highlight_context);
+  pixel->highlight_context=XCreateGC(display,windows->context.id,
+    (size_t) (context_mask | GCPlaneMask),&context_values);
+  if (pixel->highlight_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      display_image->filename);
+  (void) XDestroyWindow(display,windows->context.id);
+  /*
+    Initialize icon window.
+  */
+  XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
+    icon_resources,&windows->icon);
+  windows->icon.geometry=resource_info->icon_geometry;
+  XBestIconSize(display,&windows->icon,display_image);
+  windows->icon.attributes.colormap=XDefaultColormap(display,
+    icon_visual->screen);
+  windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=IconicState;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->icon);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
+      windows->icon.id);
+  /*
+    Initialize graphic context for icon window.
+  */
+  if (icon_pixel->annotate_context != (GC) NULL)
+    (void) XFreeGC(display,icon_pixel->annotate_context);
+  context_values.background=icon_pixel->background_color.pixel;
+  context_values.foreground=icon_pixel->foreground_color.pixel;
+  icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
+    (size_t) (GCBackground | GCForeground),&context_values);
+  if (icon_pixel->annotate_context == (GC) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
+      display_image->filename);
+  windows->icon.annotate_context=icon_pixel->annotate_context;
+  /*
+    Initialize Image window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
+    &windows->image);
+  windows->image.shape=MagickTrue;  /* non-rectangular shape hint */
+  if (resource_info->use_shared_memory == MagickFalse)
+    windows->image.shared_memory=MagickFalse;
+  if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
+    {
+      char
+        *title;
+
+      title=InterpretImageProperties(resource_info->image_info,display_image,
+        resource_info->title);
+      (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
+      (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
+      title=DestroyString(title);
+    }
+  else
+    {
+      char
+        filename[MaxTextExtent];
+
+      /*
+        Window name is the base of the filename.
+      */
+      GetPathComponent(display_image->magick_filename,TailPath,filename);
+      if (GetImageListLength(display_image) == 1)
+        (void) FormatLocaleString(windows->image.name,MaxTextExtent,
+          "%s: %s",MagickPackageName,filename);
+      else
+        (void) FormatLocaleString(windows->image.name,MaxTextExtent,
+          "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
+          (double) display_image->scene,(double) GetImageListLength(
+          display_image));
+      (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
+    }
+  if (resource_info->immutable)
+    windows->image.immutable=MagickTrue;
+  windows->image.use_pixmap=resource_info->use_pixmap;
+  windows->image.geometry=resource_info->image_geometry;
+  (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
+    XDisplayWidth(display,visual_info->screen),
+    XDisplayHeight(display,visual_info->screen));
+  geometry_info.width=display_image->columns;
+  geometry_info.height=display_image->rows;
+  geometry_info.x=0;
+  geometry_info.y=0;
+  (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
+    &geometry_info.width,&geometry_info.height);
+  windows->image.width=(unsigned int) geometry_info.width;
+  windows->image.height=(unsigned int) geometry_info.height;
+  windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
+    KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
+    PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->backdrop);
+  if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
+    {
+      /*
+        Initialize backdrop window.
+      */
+      windows->backdrop.x=0;
+      windows->backdrop.y=0;
+      (void) CloneString(&windows->backdrop.name,"Backdrop");
+      windows->backdrop.flags=(size_t) (USSize | USPosition);
+      windows->backdrop.width=(unsigned int)
+        XDisplayWidth(display,visual_info->screen);
+      windows->backdrop.height=(unsigned int)
+        XDisplayHeight(display,visual_info->screen);
+      windows->backdrop.border_width=0;
+      windows->backdrop.immutable=MagickTrue;
+      windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
+        ButtonReleaseMask;
+      windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
+        StructureNotifyMask;
+      manager_hints->flags=IconWindowHint | InputHint | StateHint;
+      manager_hints->icon_window=windows->icon.id;
+      manager_hints->input=MagickTrue;
+      manager_hints->initial_state=resource_info->iconic ? IconicState :
+        NormalState;
+      XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+        &windows->backdrop);
+      if (display_image->debug != MagickFalse)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),
+          "Window id: 0x%lx (backdrop)",windows->backdrop.id);
+      (void) XMapWindow(display,windows->backdrop.id);
+      (void) XClearWindow(display,windows->backdrop.id);
+      if (windows->image.id != (Window) NULL)
+        {
+          (void) XDestroyWindow(display,windows->image.id);
+          windows->image.id=(Window) NULL;
+        }
+      /*
+        Position image in the center the backdrop.
+      */
+      windows->image.flags|=USPosition;
+      windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
+        (windows->image.width/2);
+      windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
+        (windows->image.height/2);
+    }
+  manager_hints->flags=IconWindowHint | InputHint | StateHint;
+  manager_hints->icon_window=windows->icon.id;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=resource_info->iconic ? IconicState :
+    NormalState;
+  if (windows->group_leader.id != (Window) NULL)
+    {
+      /*
+        Follow the leader.
+      */
+      manager_hints->flags|=WindowGroupHint;
+      manager_hints->window_group=windows->group_leader.id;
+      (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
+      if (display_image->debug != MagickFalse)
+        (void) LogMagickEvent(X11Event,GetMagickModule(),
+          "Window id: 0x%lx (group leader)",windows->group_leader.id);
+    }
+  XMakeWindow(display,
+    (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
+    argv,argc,class_hints,manager_hints,&windows->image);
+  (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
+    XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
+  if (windows->group_leader.id != (Window) NULL)
+    (void) XSetTransientForHint(display,windows->image.id,
+      windows->group_leader.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
+      windows->image.id);
+  /*
+    Initialize Info widget.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
+    &windows->info);
+  (void) CloneString(&windows->info.name,"Info");
+  (void) CloneString(&windows->info.icon_name,"Info");
+  windows->info.border_width=1;
+  windows->info.x=2;
+  windows->info.y=2;
+  windows->info.flags|=PPosition;
+  windows->info.attributes.win_gravity=UnmapGravity;
+  windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
+    StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
+    &windows->info);
+  windows->info.highlight_stipple=XCreateBitmapFromData(display,
+    windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
+  windows->info.shadow_stipple=XCreateBitmapFromData(display,
+    windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
+  if (windows->image.mapped != MagickFalse)
+    (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
+      windows->info.id);
+  /*
+    Initialize Command widget.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->command);
+  windows->command.data=MagickMenus;
+  (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
+  (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
+    resource_info->client_name);
+  windows->command.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  (void) CloneString(&windows->command.name,MagickTitle);
+  windows->command.border_width=0;
+  windows->command.flags|=PPosition;
+  windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
+    OwnerGrabButtonMask | StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->command);
+  windows->command.highlight_stipple=XCreateBitmapFromData(display,
+    windows->command.id,(char *) HighlightBitmap,HighlightWidth,
+    HighlightHeight);
+  windows->command.shadow_stipple=XCreateBitmapFromData(display,
+    windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
+  if (windows->command.mapped != MagickFalse)
+    (void) XMapRaised(display,windows->command.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (command)",windows->command.id);
+  /*
+    Initialize Widget window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->widget);
+  (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
+    resource_info->client_name);
+  windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  windows->widget.border_width=0;
+  windows->widget.flags|=PPosition;
+  windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
+    KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
+    StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->widget);
+  windows->widget.highlight_stipple=XCreateBitmapFromData(display,
+    windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
+  windows->widget.shadow_stipple=XCreateBitmapFromData(display,
+    windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (widget)",windows->widget.id);
+  /*
+    Initialize popup window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->popup);
+  windows->popup.border_width=0;
+  windows->popup.flags|=PPosition;
+  windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
+    KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->popup);
+  windows->popup.highlight_stipple=XCreateBitmapFromData(display,
+    windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
+  windows->popup.shadow_stipple=XCreateBitmapFromData(display,
+    windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
+  (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (pop up)",windows->popup.id);
+  /*
+    Initialize Magnify window and cursor.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->magnify);
+  if (resource_info->use_shared_memory == MagickFalse)
+    windows->magnify.shared_memory=MagickFalse;
+  (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
+    resource_info->client_name);
+  windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
+    resource_info->magnify);
+  if (windows->magnify.cursor != (Cursor) NULL)
+    (void) XFreeCursor(display,windows->magnify.cursor);
+  windows->magnify.cursor=XMakeCursor(display,windows->image.id,
+    map_info->colormap,resource_info->background_color,
+    resource_info->foreground_color);
+  if (windows->magnify.cursor == (Cursor) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
+      display_image->filename);
+  windows->magnify.width=MagnifySize;
+  windows->magnify.height=MagnifySize;
+  windows->magnify.flags|=PPosition;
+  windows->magnify.min_width=MagnifySize;
+  windows->magnify.min_height=MagnifySize;
+  windows->magnify.width_inc=MagnifySize;
+  windows->magnify.height_inc=MagnifySize;
+  windows->magnify.data=resource_info->magnify;
+  windows->magnify.attributes.cursor=windows->magnify.cursor;
+  windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
+    ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
+    StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickTrue;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->magnify);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),
+      "Window id: 0x%lx (magnify)",windows->magnify.id);
+  (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
+  /*
+    Initialize panning window.
+  */
+  XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
+    resource_info,&windows->pan);
+  (void) CloneString(&windows->pan.name,"Pan Icon");
+  windows->pan.width=windows->icon.width;
+  windows->pan.height=windows->icon.height;
+  (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
+    resource_info->client_name);
+  windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
+    resource_name,"geometry",(char *) NULL);
+  (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
+    &windows->pan.width,&windows->pan.height);
+  windows->pan.flags|=PPosition;
+  windows->pan.immutable=MagickTrue;
+  windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
+    ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
+    StructureNotifyMask;
+  manager_hints->flags=InputHint | StateHint | WindowGroupHint;
+  manager_hints->input=MagickFalse;
+  manager_hints->initial_state=NormalState;
+  manager_hints->window_group=windows->image.id;
+  XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
+    &windows->pan);
+  if (display_image->debug != MagickFalse)
+    (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
+      windows->pan.id);
+  (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
+  if (windows->info.mapped != MagickFalse)
+    (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  if ((windows->image.mapped == MagickFalse) ||
+      (windows->backdrop.id != (Window) NULL))
+    (void) XMapWindow(display,windows->image.id);
+  /*
+    Set our progress monitor and warning handlers.
+  */
+  if (warning_handler == (WarningHandler) NULL)
+    {
+      warning_handler=resource_info->display_warnings ?
+        SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
+      warning_handler=resource_info->display_warnings ?
+        SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
+    }
+  /*
+    Initialize Image and Magnify X images.
+  */
+  windows->image.x=0;
+  windows->image.y=0;
+  windows->magnify.shape=MagickFalse;
+  width=(unsigned int) display_image->columns;
+  height=(unsigned int) display_image->rows;
+  if ((display_image->columns != width) || (display_image->rows != height))
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      display_image->filename);
+  status=XMakeImage(display,resource_info,&windows->image,display_image,
+    width,height);
+  if (status == MagickFalse)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      display_image->filename);
+  status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
+    windows->magnify.width,windows->magnify.height);
+  if (status == MagickFalse)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
+      display_image->filename);
+  if (windows->magnify.mapped != MagickFalse)
+    (void) XMapRaised(display,windows->magnify.id);
+  if (windows->pan.mapped != MagickFalse)
+    (void) XMapRaised(display,windows->pan.id);
+  windows->image.window_changes.width=(int) display_image->columns;
+  windows->image.window_changes.height=(int) display_image->rows;
+  (void) XConfigureImage(display,resource_info,windows,display_image);
+  (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+  (void) XSync(display,MagickFalse);
+  /*
+    Respond to events.
+  */
+  delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
+  timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
+  update_time=0;
+  if (resource_info->update != MagickFalse)
+    {
+      MagickBooleanType
+        status;
+
+      /*
+        Determine when file data was last modified.
+      */
+      status=GetPathAttributes(display_image->filename,&attributes);
+      if (status != MagickFalse)
+        update_time=attributes.st_mtime;
+    }
+  *state&=(~FormerImageState);
+  *state&=(~MontageImageState);
+  *state&=(~NextImageState);
+  do
+  {
+    /*
+      Handle a window event.
+    */
+    if (windows->image.mapped != MagickFalse)
+      if ((display_image->delay != 0) || (resource_info->update != 0))
+        {
+          if (timer < time((time_t *) NULL))
+            {
+              if (resource_info->update == MagickFalse)
+                *state|=NextImageState | ExitState;
+              else
+                {
+                  MagickBooleanType
+                    status;
+
+                  /*
+                    Determine if image file was modified.
+                  */
+                  status=GetPathAttributes(display_image->filename,&attributes);
+                  if (status != MagickFalse)
+                    if (update_time != attributes.st_mtime)
+                      {
+                        /*
+                          Redisplay image.
+                        */
+                        (void) FormatLocaleString(
+                          resource_info->image_info->filename,MaxTextExtent,
+                          "%s:%s",display_image->magick,
+                          display_image->filename);
+                        nexus=ReadImage(resource_info->image_info,
+                          &display_image->exception);
+                        if (nexus != (Image *) NULL)
+                          {
+                            nexus=DestroyImage(nexus);
+                            *state|=NextImageState | ExitState;
+                          }
+                      }
+                  delay=display_image->delay/MagickMax(
+                    display_image->ticks_per_second,1L);
+                  timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
+                }
+            }
+          if (XEventsQueued(display,QueuedAfterFlush) == 0)
+            {
+              /*
+                Do not block if delay > 0.
+              */
+              XDelay(display,SuspendTime << 2);
+              continue;
+            }
+        }
+    timestamp=time((time_t *) NULL);
+    (void) XNextEvent(display,&event);
+    if (windows->image.stasis == MagickFalse)
+      windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
+        MagickTrue : MagickFalse;
+    if (windows->magnify.stasis == MagickFalse)
+      windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
+        MagickTrue : MagickFalse;
+    if (event.xany.window == windows->command.id)
+      {
+        /*
+          Select a command from the Command widget.
+        */
+        id=XCommandWidget(display,windows,CommandMenu,&event);
+        if (id < 0)
+          continue;
+        (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
+        command_type=CommandMenus[id];
+        if (id < MagickMenus)
+          {
+            /*
+              Select a command from a pop-up menu.
+            */
+            entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
+              command);
+            if (entry < 0)
+              continue;
+            (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
+            command_type=Commands[id][entry];
+          }
+        if (command_type != NullCommand)
+          nexus=XMagickCommand(display,resource_info,windows,command_type,
+            &display_image);
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        if ((event.xbutton.button == Button3) &&
+            (event.xbutton.state & Mod1Mask))
+          {
+            /*
+              Convert Alt-Button3 to Button2.
+            */
+            event.xbutton.button=Button2;
+            event.xbutton.state&=(~Mod1Mask);
+          }
+        if (event.xbutton.window == windows->backdrop.id)
+          {
+            (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
+              event.xbutton.time);
+            break;
+          }
+        if (event.xbutton.window == windows->image.id)
+          {
+            switch (event.xbutton.button)
+            {
+              case Button1:
+              {
+                if (resource_info->immutable)
+                  {
+                    /*
+                      Select a command from the Virtual menu.
+                    */
+                    entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
+                      command);
+                    if (entry >= 0)
+                      nexus=XMagickCommand(display,resource_info,windows,
+                        VirtualCommands[entry],&display_image);
+                    break;
+                  }
+                /*
+                  Map/unmap Command widget.
+                */
+                if (windows->command.mapped != MagickFalse)
+                  (void) XWithdrawWindow(display,windows->command.id,
+                    windows->command.screen);
+                else
+                  {
+                    (void) XCommandWidget(display,windows,CommandMenu,
+                      (XEvent *) NULL);
+                    (void) XMapRaised(display,windows->command.id);
+                  }
+                break;
+              }
+              case Button2:
+              {
+                /*
+                  User pressed the image magnify button.
+                */
+                (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
+                  &display_image);
+                XMagnifyImage(display,windows,&event);
+                break;
+              }
+              case Button3:
+              {
+                if (resource_info->immutable)
+                  {
+                    /*
+                      Select a command from the Virtual menu.
+                    */
+                    entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
+                      command);
+                    if (entry >= 0)
+                      nexus=XMagickCommand(display,resource_info,windows,
+                        VirtualCommands[entry],&display_image);
+                    break;
+                  }
+                if (display_image->montage != (char *) NULL)
+                  {
+                    /*
+                      Open or delete a tile from a visual image directory.
+                    */
+                    nexus=XTileImage(display,resource_info,windows,
+                      display_image,&event);
+                    if (nexus != (Image *) NULL)
+                      *state|=MontageImageState | NextImageState | ExitState;
+                    vid_info.x=(short int) windows->image.x;
+                    vid_info.y=(short int) windows->image.y;
+                    break;
+                  }
+                /*
+                  Select a command from the Short Cuts menu.
+                */
+                entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
+                  command);
+                if (entry >= 0)
+                  nexus=XMagickCommand(display,resource_info,windows,
+                    ShortCutsCommands[entry],&display_image);
+                break;
+              }
+              case Button4:
+              {
+                /*
+                  Wheel up.
+                */
+                XTranslateImage(display,windows,*image,XK_Up);
+                break;
+              }
+              case Button5:
+              {
+                /*
+                  Wheel down.
+                */
+                XTranslateImage(display,windows,*image,XK_Down);
+                break;
+              }
+              default:
+                break;
+            }
+            break;
+          }
+        if (event.xbutton.window == windows->magnify.id)
+          {
+            int
+              factor;
+
+            static const char
+              *MagnifyMenu[] =
+              {
+                "2",
+                "4",
+                "5",
+                "6",
+                "7",
+                "8",
+                "9",
+                "3",
+                (char *) NULL,
+              };
+
+            static KeySym
+              MagnifyCommands[] =
+              {
+                XK_2,
+                XK_4,
+                XK_5,
+                XK_6,
+                XK_7,
+                XK_8,
+                XK_9,
+                XK_3
+              };
+
+            /*
+              Select a magnify factor from the pop-up menu.
+            */
+            factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
+            if (factor >= 0)
+              XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
+            break;
+          }
+        if (event.xbutton.window == windows->pan.id)
+          {
+            switch (event.xbutton.button)
+            {
+              case Button4:
+              {
+                /*
+                  Wheel up.
+                */
+                XTranslateImage(display,windows,*image,XK_Up);
+                break;
+              }
+              case Button5:
+              {
+                /*
+                  Wheel down.
+                */
+                XTranslateImage(display,windows,*image,XK_Down);
+                break;
+              }
+              default:
+              {
+                XPanImage(display,windows,&event);
+                break;
+              }
+            }
+            break;
+          }
+        delay=display_image->delay/MagickMax(display_image->ticks_per_second,
+          1L);
+        timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
+            event.xbutton.button,event.xbutton.x,event.xbutton.y);
+        break;
+      }
+      case ClientMessage:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
+            event.xclient.message_type,event.xclient.format,(unsigned long)
+            event.xclient.data.l[0]);
+        if (event.xclient.message_type == windows->im_protocols)
+          {
+            if (*event.xclient.data.l == (long) windows->im_update_widget)
+              {
+                (void) CloneString(&windows->command.name,MagickTitle);
+                windows->command.data=MagickMenus;
+                (void) XCommandWidget(display,windows,CommandMenu,
+                  (XEvent *) NULL);
+                break;
+              }
+            if (*event.xclient.data.l == (long) windows->im_update_colormap)
+              {
+                /*
+                  Update graphic context and window colormap.
+                */
+                for (i=0; i < (int) number_windows; i++)
+                {
+                  if (magick_windows[i]->id == windows->icon.id)
+                    continue;
+                  context_values.background=pixel->background_color.pixel;
+                  context_values.foreground=pixel->foreground_color.pixel;
+                  (void) XChangeGC(display,magick_windows[i]->annotate_context,
+                    context_mask,&context_values);
+                  (void) XChangeGC(display,magick_windows[i]->widget_context,
+                    context_mask,&context_values);
+                  context_values.background=pixel->foreground_color.pixel;
+                  context_values.foreground=pixel->background_color.pixel;
+                  context_values.plane_mask=context_values.background ^
+                    context_values.foreground;
+                  (void) XChangeGC(display,magick_windows[i]->highlight_context,
+                    (size_t) (context_mask | GCPlaneMask),
+                    &context_values);
+                  magick_windows[i]->attributes.background_pixel=
+                    pixel->background_color.pixel;
+                  magick_windows[i]->attributes.border_pixel=
+                    pixel->border_color.pixel;
+                  magick_windows[i]->attributes.colormap=map_info->colormap;
+                  (void) XChangeWindowAttributes(display,magick_windows[i]->id,
+                    (unsigned long) magick_windows[i]->mask,
+                    &magick_windows[i]->attributes);
+                }
+                if (windows->pan.mapped != MagickFalse)
+                  {
+                    (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
+                      windows->pan.pixmap);
+                    (void) XClearWindow(display,windows->pan.id);
+                    XDrawPanRectangle(display,windows);
+                  }
+                if (windows->backdrop.id != (Window) NULL)
+                  (void) XInstallColormap(display,map_info->colormap);
+                break;
+              }
+            if (*event.xclient.data.l == (long) windows->im_former_image)
+              {
+                *state|=FormerImageState | ExitState;
+                break;
+              }
+            if (*event.xclient.data.l == (long) windows->im_next_image)
+              {
+                *state|=NextImageState | ExitState;
+                break;
+              }
+            if (*event.xclient.data.l == (long) windows->im_retain_colors)
+              {
+                *state|=RetainColorsState;
+                break;
+              }
+            if (*event.xclient.data.l == (long) windows->im_exit)
+              {
+                *state|=ExitState;
+                break;
+              }
+            break;
+          }
+        if (event.xclient.message_type == windows->dnd_protocols)
+          {
+            Atom
+              selection,
+              type;
+
+            int
+              format,
+              status;
+
+            unsigned char
+              *data;
+
+            unsigned long
+              after,
+              length;
+
+            /*
+              Display image named by the Drag-and-Drop selection.
+            */
+            if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
+              break;
+            selection=XInternAtom(display,"DndSelection",MagickFalse);
+            status=XGetWindowProperty(display,root_window,selection,0L,(long)
+              MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
+              &length,&after,&data);
+            if ((status != Success) || (length == 0))
+              break;
+            if (*event.xclient.data.l == 2)
+              {
+                /*
+                  Offix DND.
+                */
+                (void) CopyMagickString(resource_info->image_info->filename,
+                  (char *) data,MaxTextExtent);
+              }
+            else
+              {
+                /*
+                  XDND.
+                */
+                if (strncmp((char *) data, "file:", 5) != 0)
+                  {
+                    (void) XFree((void *) data);
+                    break;
+                  }
+                (void) CopyMagickString(resource_info->image_info->filename,
+                  ((char *) data)+5,MaxTextExtent);
+              }
+            nexus=ReadImage(resource_info->image_info,
+              &display_image->exception);
+            CatchException(&display_image->exception);
+            if (nexus != (Image *) NULL)
+              *state|=NextImageState | ExitState;
+            (void) XFree((void *) data);
+            break;
+          }
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l != (long) windows->wm_delete_window)
+          break;
+        (void) XWithdrawWindow(display,event.xclient.window,
+          visual_info->screen);
+        if (event.xclient.window == windows->image.id)
+          {
+            *state|=ExitState;
+            break;
+          }
+        if (event.xclient.window == windows->pan.id)
+          {
+            /*
+              Restore original image size when pan window is deleted.
+            */
+            windows->image.window_changes.width=windows->image.ximage->width;
+            windows->image.window_changes.height=windows->image.ximage->height;
+            (void) XConfigureImage(display,resource_info,windows,
+              display_image);
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
+            event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
+            event.xconfigure.y,event.xconfigure.send_event);
+        if (event.xconfigure.window == windows->image.id)
+          {
+            /*
+              Image window has a new configuration.
+            */
+            if (event.xconfigure.send_event != 0)
+              {
+                XWindowChanges
+                  window_changes;
+
+                /*
+                  Position the transient windows relative of the Image window.
+                */
+                if (windows->command.geometry == (char *) NULL)
+                  if (windows->command.mapped == MagickFalse)
+                    {
+                      windows->command.x=event.xconfigure.x-
+                        windows->command.width-25;
+                      windows->command.y=event.xconfigure.y;
+                      XConstrainWindowPosition(display,&windows->command);
+                      window_changes.x=windows->command.x;
+                      window_changes.y=windows->command.y;
+                      (void) XReconfigureWMWindow(display,windows->command.id,
+                        windows->command.screen,(unsigned int) (CWX | CWY),
+                        &window_changes);
+                    }
+                if (windows->widget.geometry == (char *) NULL)
+                  if (windows->widget.mapped == MagickFalse)
+                    {
+                      windows->widget.x=event.xconfigure.x+
+                        event.xconfigure.width/10;
+                      windows->widget.y=event.xconfigure.y+
+                        event.xconfigure.height/10;
+                      XConstrainWindowPosition(display,&windows->widget);
+                      window_changes.x=windows->widget.x;
+                      window_changes.y=windows->widget.y;
+                      (void) XReconfigureWMWindow(display,windows->widget.id,
+                        windows->widget.screen,(unsigned int) (CWX | CWY),
+                        &window_changes);
+                    }
+                if (windows->magnify.geometry == (char *) NULL)
+                  if (windows->magnify.mapped == MagickFalse)
+                    {
+                      windows->magnify.x=event.xconfigure.x+
+                        event.xconfigure.width+25;
+                      windows->magnify.y=event.xconfigure.y;
+                      XConstrainWindowPosition(display,&windows->magnify);
+                      window_changes.x=windows->magnify.x;
+                      window_changes.y=windows->magnify.y;
+                      (void) XReconfigureWMWindow(display,windows->magnify.id,
+                        windows->magnify.screen,(unsigned int) (CWX | CWY),
+                        &window_changes);
+                    }
+                if (windows->pan.geometry == (char *) NULL)
+                  if (windows->pan.mapped == MagickFalse)
+                    {
+                      windows->pan.x=event.xconfigure.x+
+                        event.xconfigure.width+25;
+                      windows->pan.y=event.xconfigure.y+
+                        windows->magnify.height+50;
+                      XConstrainWindowPosition(display,&windows->pan);
+                      window_changes.x=windows->pan.x;
+                      window_changes.y=windows->pan.y;
+                      (void) XReconfigureWMWindow(display,windows->pan.id,
+                        windows->pan.screen,(unsigned int) (CWX | CWY),
+                        &window_changes);
+                    }
+              }
+            if ((event.xconfigure.width == (int) windows->image.width) &&
+                (event.xconfigure.height == (int) windows->image.height))
+              break;
+            windows->image.width=(unsigned int) event.xconfigure.width;
+            windows->image.height=(unsigned int) event.xconfigure.height;
+            windows->image.x=0;
+            windows->image.y=0;
+            if (display_image->montage != (char *) NULL)
+              {
+                windows->image.x=vid_info.x;
+                windows->image.y=vid_info.y;
+              }
+            if ((windows->image.mapped != MagickFalse) &&
+                (windows->image.stasis != MagickFalse))
+              {
+                /*
+                  Update image window configuration.
+                */
+                windows->image.window_changes.width=event.xconfigure.width;
+                windows->image.window_changes.height=event.xconfigure.height;
+                (void) XConfigureImage(display,resource_info,windows,
+                  display_image);
+              }
+            /*
+              Update pan window configuration.
+            */
+            if ((event.xconfigure.width < windows->image.ximage->width) ||
+                (event.xconfigure.height < windows->image.ximage->height))
+              {
+                (void) XMapRaised(display,windows->pan.id);
+                XDrawPanRectangle(display,windows);
+              }
+            else
+              if (windows->pan.mapped != MagickFalse)
+                (void) XWithdrawWindow(display,windows->pan.id,
+                  windows->pan.screen);
+            break;
+          }
+        if (event.xconfigure.window == windows->magnify.id)
+          {
+            unsigned int
+              magnify;
+
+            /*
+              Magnify window has a new configuration.
+            */
+            windows->magnify.width=(unsigned int) event.xconfigure.width;
+            windows->magnify.height=(unsigned int) event.xconfigure.height;
+            if (windows->magnify.mapped == MagickFalse)
+              break;
+            magnify=1;
+            while ((int) magnify <= event.xconfigure.width)
+              magnify<<=1;
+            while ((int) magnify <= event.xconfigure.height)
+              magnify<<=1;
+            magnify>>=1;
+            if (((int) magnify != event.xconfigure.width) ||
+                ((int) magnify != event.xconfigure.height))
+              {
+                window_changes.width=(int) magnify;
+                window_changes.height=(int) magnify;
+                (void) XReconfigureWMWindow(display,windows->magnify.id,
+                  windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
+                  &window_changes);
+                break;
+              }
+            if ((windows->magnify.mapped != MagickFalse) &&
+                (windows->magnify.stasis != MagickFalse))
+              {
+                status=XMakeImage(display,resource_info,&windows->magnify,
+                  display_image,windows->magnify.width,windows->magnify.height);
+                XMakeMagnifyImage(display,windows);
+              }
+            break;
+          }
+        if ((windows->magnify.mapped != MagickFalse) &&
+            (event.xconfigure.window == windows->pan.id))
+          {
+            /*
+              Pan icon window has a new configuration.
+            */
+            if (event.xconfigure.send_event != 0)
+              {
+                windows->pan.x=event.xconfigure.x;
+                windows->pan.y=event.xconfigure.y;
+              }
+            windows->pan.width=(unsigned int) event.xconfigure.width;
+            windows->pan.height=(unsigned int) event.xconfigure.height;
+            break;
+          }
+        if (event.xconfigure.window == windows->icon.id)
+          {
+            /*
+              Icon window has a new configuration.
+            */
+            windows->icon.width=(unsigned int) event.xconfigure.width;
+            windows->icon.height=(unsigned int) event.xconfigure.height;
+            break;
+          }
+        break;
+      }
+      case DestroyNotify:
+      {
+        /*
+          Group leader has exited.
+        */
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Destroy Notify: 0x%lx",event.xdestroywindow.window);
+        if (event.xdestroywindow.window == windows->group_leader.id)
+          {
+            *state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case EnterNotify:
+      {
+        /*
+          Selectively install colormap.
+        */
+        if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
+          if (event.xcrossing.mode != NotifyUngrab)
+            XInstallColormap(display,map_info->colormap);
+        break;
+      }
+      case Expose:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
+            event.xexpose.width,event.xexpose.height,event.xexpose.x,
+            event.xexpose.y);
+        /*
+          Refresh windows that are now exposed.
+        */
+        if ((event.xexpose.window == windows->image.id) &&
+            (windows->image.mapped != MagickFalse))
+          {
+            XRefreshWindow(display,&windows->image,&event);
+            delay=display_image->delay/MagickMax(
+              display_image->ticks_per_second,1L);
+            timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
+            break;
+          }
+        if ((event.xexpose.window == windows->magnify.id) &&
+            (windows->magnify.mapped != MagickFalse))
+          {
+            XMakeMagnifyImage(display,windows);
+            break;
+          }
+        if (event.xexpose.window == windows->pan.id)
+          {
+            XDrawPanRectangle(display,windows);
+            break;
+          }
+        if (event.xexpose.window == windows->icon.id)
+          {
+            XRefreshWindow(display,&windows->icon,&event);
+            break;
+          }
+        break;
+      }
+      case KeyPress:
+      {
+        int
+          length;
+
+        /*
+          Respond to a user key press.
+        */
+        length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
+            key_symbol,command);
+        if (event.xkey.window == windows->image.id)
+          {
+            command_type=XImageWindowCommand(display,resource_info,windows,
+              event.xkey.state,key_symbol,&display_image);
+            if (command_type != NullCommand)
+              nexus=XMagickCommand(display,resource_info,windows,command_type,
+                &display_image);
+          }
+        if (event.xkey.window == windows->magnify.id)
+          XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
+        if (event.xkey.window == windows->pan.id)
+          {
+            if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
+              (void) XWithdrawWindow(display,windows->pan.id,
+                windows->pan.screen);
+            else
+              if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
+                XTextViewWidget(display,resource_info,windows,MagickFalse,
+                  "Help Viewer - Image Pan",ImagePanHelp);
+              else
+                XTranslateImage(display,windows,*image,key_symbol);
+          }
+        delay=display_image->delay/MagickMax(
+          display_image->ticks_per_second,1L);
+        timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
+        break;
+      }
+      case KeyRelease:
+      {
+        /*
+          Respond to a user key release.
+        */
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
+          sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
+        break;
+      }
+      case LeaveNotify:
+      {
+        /*
+          Selectively uninstall colormap.
+        */
+        if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
+          if (event.xcrossing.mode != NotifyUngrab)
+            XUninstallColormap(display,map_info->colormap);
+        break;
+      }
+      case MapNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
+            event.xmap.window);
+        if (event.xmap.window == windows->backdrop.id)
+          {
+            (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
+              CurrentTime);
+            windows->backdrop.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->image.id)
+          {
+            if (windows->backdrop.id != (Window) NULL)
+              (void) XInstallColormap(display,map_info->colormap);
+            if (LocaleCompare(display_image->magick,"LOGO") == 0)
+              {
+                if (LocaleCompare(display_image->filename,"LOGO") == 0)
+                  nexus=XOpenImage(display,resource_info,windows,MagickFalse);
+              }
+            if (((int) windows->image.width < windows->image.ximage->width) ||
+                ((int) windows->image.height < windows->image.ximage->height))
+              (void) XMapRaised(display,windows->pan.id);
+            windows->image.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->magnify.id)
+          {
+            XMakeMagnifyImage(display,windows);
+            windows->magnify.mapped=MagickTrue;
+            (void) XWithdrawWindow(display,windows->info.id,
+              windows->info.screen);
+            break;
+          }
+        if (event.xmap.window == windows->pan.id)
+          {
+            XMakePanImage(display,resource_info,windows,display_image);
+            windows->pan.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->info.id)
+          {
+            windows->info.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->icon.id)
+          {
+            MagickBooleanType
+              taint;
+
+            /*
+              Create an icon image.
+            */
+            taint=display_image->taint;
+            XMakeStandardColormap(display,icon_visual,icon_resources,
+              display_image,icon_map,icon_pixel);
+            (void) XMakeImage(display,icon_resources,&windows->icon,
+              display_image,windows->icon.width,windows->icon.height);
+            display_image->taint=taint;
+            (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
+              windows->icon.pixmap);
+            (void) XClearWindow(display,windows->icon.id);
+            (void) XWithdrawWindow(display,windows->info.id,
+              windows->info.screen);
+            windows->icon.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->command.id)
+          {
+            windows->command.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->popup.id)
+          {
+            windows->popup.mapped=MagickTrue;
+            break;
+          }
+        if (event.xmap.window == windows->widget.id)
+          {
+            windows->widget.mapped=MagickTrue;
+            break;
+          }
+        break;
+      }
+      case MappingNotify:
+      {
+        (void) XRefreshKeyboardMapping(&event.xmapping);
+        break;
+      }
+      case NoExpose:
+        break;
+      case PropertyNotify:
+      {
+        Atom
+          type;
+
+        int
+          format,
+          status;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
+            event.xproperty.atom,event.xproperty.state);
+        if (event.xproperty.atom != windows->im_remote_command)
+          break;
+        /*
+          Display image named by the remote command protocol.
+        */
+        status=XGetWindowProperty(display,event.xproperty.window,
+          event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
+          AnyPropertyType,&type,&format,&length,&after,&data);
+        if ((status != Success) || (length == 0))
+          break;
+        if (LocaleCompare((char *) data,"-quit") == 0)
+          {
+            XClientMessage(display,windows->image.id,windows->im_protocols,
+              windows->im_exit,CurrentTime);
+            (void) XFree((void *) data);
+            break;
+          }
+        (void) CopyMagickString(resource_info->image_info->filename,
+          (char *) data,MaxTextExtent);
+        (void) XFree((void *) data);
+        nexus=ReadImage(resource_info->image_info,&display_image->exception);
+        CatchException(&display_image->exception);
+        if (nexus != (Image *) NULL)
+          *state|=NextImageState | ExitState;
+        break;
+      }
+      case ReparentNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
+            event.xreparent.window);
+        break;
+      }
+      case UnmapNotify:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Unmap Notify: 0x%lx",event.xunmap.window);
+        if (event.xunmap.window == windows->backdrop.id)
+          {
+            windows->backdrop.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->image.id)
+          {
+            windows->image.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->magnify.id)
+          {
+            windows->magnify.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->pan.id)
+          {
+            windows->pan.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->info.id)
+          {
+            windows->info.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->icon.id)
+          {
+            if (map_info->colormap == icon_map->colormap)
+              XConfigureImageColormap(display,resource_info,windows,
+                display_image);
+            (void) XFreeStandardColormap(display,icon_visual,icon_map,
+              icon_pixel);
+            windows->icon.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->command.id)
+          {
+            windows->command.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->popup.id)
+          {
+            if (windows->backdrop.id != (Window) NULL)
+              (void) XSetInputFocus(display,windows->image.id,RevertToParent,
+                CurrentTime);
+            windows->popup.mapped=MagickFalse;
+            break;
+          }
+        if (event.xunmap.window == windows->widget.id)
+          {
+            if (windows->backdrop.id != (Window) NULL)
+              (void) XSetInputFocus(display,windows->image.id,RevertToParent,
+                CurrentTime);
+            windows->widget.mapped=MagickFalse;
+            break;
+          }
+        break;
+      }
+      default:
+      {
+        if (display_image->debug != MagickFalse)
+          (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
+            event.type);
+        break;
+      }
+    }
+  } while (!(*state & ExitState));
+  if ((*state & ExitState) == 0)
+    (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
+      &display_image);
+  else
+    if (resource_info->confirm_edit != MagickFalse)
+      {
+        /*
+          Query user if image has changed.
+        */
+        if ((resource_info->immutable == MagickFalse) &&
+            (display_image->taint != MagickFalse))
+          {
+            int
+              status;
+
+            status=XConfirmWidget(display,windows,"Your image changed.",
+              "Do you want to save it");
+            if (status == 0)
+              *state&=(~ExitState);
+            else
+              if (status > 0)
+                (void) XMagickCommand(display,resource_info,windows,SaveCommand,
+                  &display_image);
+          }
+      }
+  if ((windows->visual_info->klass == GrayScale) ||
+      (windows->visual_info->klass == PseudoColor) ||
+      (windows->visual_info->klass == DirectColor))
+    {
+      /*
+        Withdraw pan and Magnify window.
+      */
+      if (windows->info.mapped != MagickFalse)
+        (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      if (windows->magnify.mapped != MagickFalse)
+        (void) XWithdrawWindow(display,windows->magnify.id,
+          windows->magnify.screen);
+      if (windows->command.mapped != MagickFalse)
+        (void) XWithdrawWindow(display,windows->command.id,
+          windows->command.screen);
+    }
+  if (windows->pan.mapped != MagickFalse)
+    (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
+  if (resource_info->backdrop == MagickFalse)
+    if (windows->backdrop.mapped)
+      {
+        (void) XWithdrawWindow(display,windows->backdrop.id,
+          windows->backdrop.screen);
+        (void) XDestroyWindow(display,windows->backdrop.id);
+        windows->backdrop.id=(Window) NULL;
+        (void) XWithdrawWindow(display,windows->image.id,
+          windows->image.screen);
+        (void) XDestroyWindow(display,windows->image.id);
+        windows->image.id=(Window) NULL;
+      }
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
+    *state&=(~ExitState);
+  if (*state & ExitState)
+    {
+      /*
+        Free Standard Colormap.
+      */
+      (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
+      if (resource_info->map_type == (char *) NULL)
+        (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
+      /*
+        Free X resources.
+      */
+      if (resource_info->copy_image != (Image *) NULL)
+        {
+          resource_info->copy_image=DestroyImage(resource_info->copy_image);
+          resource_info->copy_image=NewImageList();
+        }
+      DestroyXResources();
+    }
+  (void) XSync(display,MagickFalse);
+  /*
+    Restore our progress monitor and warning handlers.
+  */
+  (void) SetErrorHandler(warning_handler);
+  (void) SetWarningHandler(warning_handler);
+  /*
+    Change to home directory.
+  */
+  directory=getcwd(working_directory,MaxTextExtent);
+  (void) directory;
+  {
+    int
+      status;
+
+    status=chdir(resource_info->home_directory);
+    if (status == -1)
+      (void) ThrowMagickException(&display_image->exception,GetMagickModule(),
+        FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
+  }
+  *image=display_image;
+  return(nexus);
+}
+#else
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D i s p l a y I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DisplayImages() displays an image sequence to any X window screen.  It
+%  returns a value other than 0 if successful.  Check the exception member
+%  of image to determine the reason for any failure.
+%
+%  The format of the DisplayImages method is:
+%
+%      MagickBooleanType DisplayImages(const ImageInfo *image_info,
+%        Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
+  Image *image)
+{
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),
+    MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
+    image->filename);
+  return(MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e m o t e D i s p l a y C o m m a n d                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoteDisplayCommand() encourages a remote display program to display the
+%  specified image filename.
+%
+%  The format of the RemoteDisplayCommand method is:
+%
+%      MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
+%        const char *window,const char *filename,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o window: Specifies the name or id of an X window.
+%
+%    o filename: the name of the image filename to display.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
+  const char *window,const char *filename,ExceptionInfo *exception)
+{
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(filename != (char *) NULL);
+  (void) window;
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
+    "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
+  return(MagickFalse);
+}
+#endif
diff --git a/MagickCore/display.h b/MagickCore/display.h
new file mode 100644
index 0000000..79f180e
--- /dev/null
+++ b/MagickCore/display.h
@@ -0,0 +1,34 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore methods to interactively display and edit an image.
+*/
+#ifndef _MAGICKCORE_DISPLAY_H
+#define _MAGICKCORE_DISPLAY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  DisplayImages(const ImageInfo *,Image *),
+  RemoteDisplayCommand(const ImageInfo *,const char *,const char *,
+    ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/distort.c b/MagickCore/distort.c
new file mode 100644
index 0000000..e2e170c
--- /dev/null
+++ b/MagickCore/distort.c
@@ -0,0 +1,3055 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               DDDD   IIIII  SSSSS  TTTTT   OOO   RRRR   TTTTT               %
+%               D   D    I    SS       T    O   O  R   R    T                 %
+%               D   D    I     SSS     T    O   O  RRRR     T                 %
+%               D   D    I       SS    T    O   O  R R      T                 %
+%               DDDD   IIIII  SSSSS    T     OOO   R  R     T                 %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Distortion Methods                     %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                              Anthony Thyssen                                %
+%                                 June 2007                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/distort.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/image.h"
+#include "MagickCore/list.h"
+#include "MagickCore/matrix.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resample-private.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/transform.h"
+
+/*
+  Numerous internal routines for image distortions.
+*/
+static inline double MagickMin(const double x,const double y)
+{
+  return( x < y ? x : y);
+}
+static inline double MagickMax(const double x,const double y)
+{
+  return( x > y ? x : y);
+}
+
+static inline void AffineArgsToCoefficients(double *affine)
+{
+  /* map  external sx,ry,rx,sy,tx,ty  to  internal c0,c2,c4,c1,c3,c5 */
+  double tmp[4];  /* note indexes  0 and 5 remain unchanged */
+  tmp[0]=affine[1]; tmp[1]=affine[2]; tmp[2]=affine[3]; tmp[3]=affine[4];
+  affine[3]=tmp[0]; affine[1]=tmp[1]; affine[4]=tmp[2]; affine[2]=tmp[3];
+}
+
+static inline void CoefficientsToAffineArgs(double *coeff)
+{
+  /* map  internal c0,c1,c2,c3,c4,c5  to  external sx,ry,rx,sy,tx,ty */
+  double tmp[4];  /* note indexes 0 and 5 remain unchanged */
+  tmp[0]=coeff[3]; tmp[1]=coeff[1]; tmp[2]=coeff[4]; tmp[3]=coeff[2];
+  coeff[1]=tmp[0]; coeff[2]=tmp[1]; coeff[3]=tmp[2]; coeff[4]=tmp[3];
+}
+static void InvertAffineCoefficients(const double *coeff,double *inverse)
+{
+  /* From "Digital Image Warping" by George Wolberg, page 50 */
+  double determinant;
+
+  determinant=1.0/(coeff[0]*coeff[4]-coeff[1]*coeff[3]);
+  inverse[0]=determinant*coeff[4];
+  inverse[1]=determinant*(-coeff[1]);
+  inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[2]*coeff[4]);
+  inverse[3]=determinant*(-coeff[3]);
+  inverse[4]=determinant*coeff[0];
+  inverse[5]=determinant*(coeff[2]*coeff[3]-coeff[0]*coeff[5]);
+}
+
+static void InvertPerspectiveCoefficients(const double *coeff,
+  double *inverse)
+{
+  /* From "Digital Image Warping" by George Wolberg, page 53 */
+  double determinant;
+
+  determinant=1.0/(coeff[0]*coeff[4]-coeff[3]*coeff[1]);
+  inverse[0]=determinant*(coeff[4]-coeff[7]*coeff[5]);
+  inverse[1]=determinant*(coeff[7]*coeff[2]-coeff[1]);
+  inverse[2]=determinant*(coeff[1]*coeff[5]-coeff[4]*coeff[2]);
+  inverse[3]=determinant*(coeff[6]*coeff[5]-coeff[3]);
+  inverse[4]=determinant*(coeff[0]-coeff[6]*coeff[2]);
+  inverse[5]=determinant*(coeff[3]*coeff[2]-coeff[0]*coeff[5]);
+  inverse[6]=determinant*(coeff[3]*coeff[7]-coeff[6]*coeff[4]);
+  inverse[7]=determinant*(coeff[6]*coeff[1]-coeff[0]*coeff[7]);
+}
+
+static inline double MagickRound(double x)
+{
+  /*
+    Round the fraction to nearest integer.
+  */
+  if (x >= 0.0)
+    return((double) ((ssize_t) (x+0.5)));
+  return((double) ((ssize_t) (x-0.5)));
+}
+
+/*
+ * Polynomial Term Defining Functions
+ *
+ * Order must either be an integer, or 1.5 to produce
+ * the 2 number_valuesal polynomial function...
+ *    affine     1   (3)      u = c0 + c1*x + c2*y
+ *    bilinear   1.5 (4)      u = '' + c3*x*y
+ *    quadratic  2   (6)      u = '' + c4*x*x + c5*y*y
+ *    cubic      3   (10)     u = '' + c6*x^3 + c7*x*x*y + c8*x*y*y + c9*y^3
+ *    quartic    4   (15)     u = '' + c10*x^4 + ... + c14*y^4
+ *    quintic    5   (21)     u = '' + c15*x^5 + ... + c20*y^5
+ * number in parenthesis minimum number of points needed.
+ * Anything beyond quintic, has not been implemented until
+ * a more automated way of determining terms is found.
+
+ * Note the slight re-ordering of the terms for a quadratic polynomial
+ * which is to allow the use of a bi-linear (order=1.5) polynomial.
+ * All the later polynomials are ordered simply from x^N to y^N
+ */
+static size_t poly_number_terms(double order)
+{
+ /* Return the number of terms for a 2d polynomial */
+  if ( order < 1 || order > 5 ||
+       ( order != floor(order) && (order-1.5) > MagickEpsilon) )
+    return 0; /* invalid polynomial order */
+  return((size_t) floor((order+1)*(order+2)/2));
+}
+
+static double poly_basis_fn(ssize_t n, double x, double y)
+{
+  /* Return the result for this polynomial term */
+  switch(n) {
+    case  0:  return( 1.0 ); /* constant */
+    case  1:  return(  x  );
+    case  2:  return(  y  ); /* affine          order = 1   terms = 3 */
+    case  3:  return( x*y ); /* bilinear        order = 1.5 terms = 4 */
+    case  4:  return( x*x );
+    case  5:  return( y*y ); /* quadratic       order = 2   terms = 6 */
+    case  6:  return( x*x*x );
+    case  7:  return( x*x*y );
+    case  8:  return( x*y*y );
+    case  9:  return( y*y*y ); /* cubic         order = 3   terms = 10 */
+    case 10:  return( x*x*x*x );
+    case 11:  return( x*x*x*y );
+    case 12:  return( x*x*y*y );
+    case 13:  return( x*y*y*y );
+    case 14:  return( y*y*y*y ); /* quartic     order = 4   terms = 15 */
+    case 15:  return( x*x*x*x*x );
+    case 16:  return( x*x*x*x*y );
+    case 17:  return( x*x*x*y*y );
+    case 18:  return( x*x*y*y*y );
+    case 19:  return( x*y*y*y*y );
+    case 20:  return( y*y*y*y*y ); /* quintic   order = 5   terms = 21 */
+  }
+  return( 0 ); /* should never happen */
+}
+static const char *poly_basis_str(ssize_t n)
+{
+  /* return the result for this polynomial term */
+  switch(n) {
+    case  0:  return(""); /* constant */
+    case  1:  return("*ii");
+    case  2:  return("*jj"); /* affine                order = 1   terms = 3 */
+    case  3:  return("*ii*jj"); /* bilinear           order = 1.5 terms = 4 */
+    case  4:  return("*ii*ii");
+    case  5:  return("*jj*jj"); /* quadratic          order = 2   terms = 6 */
+    case  6:  return("*ii*ii*ii");
+    case  7:  return("*ii*ii*jj");
+    case  8:  return("*ii*jj*jj");
+    case  9:  return("*jj*jj*jj"); /* cubic           order = 3   terms = 10 */
+    case 10:  return("*ii*ii*ii*ii");
+    case 11:  return("*ii*ii*ii*jj");
+    case 12:  return("*ii*ii*jj*jj");
+    case 13:  return("*ii*jj*jj*jj");
+    case 14:  return("*jj*jj*jj*jj"); /* quartic      order = 4   terms = 15 */
+    case 15:  return("*ii*ii*ii*ii*ii");
+    case 16:  return("*ii*ii*ii*ii*jj");
+    case 17:  return("*ii*ii*ii*jj*jj");
+    case 18:  return("*ii*ii*jj*jj*jj");
+    case 19:  return("*ii*jj*jj*jj*jj");
+    case 20:  return("*jj*jj*jj*jj*jj"); /* quintic   order = 5   terms = 21 */
+  }
+  return( "UNKNOWN" ); /* should never happen */
+}
+static double poly_basis_dx(ssize_t n, double x, double y)
+{
+  /* polynomial term for x derivative */
+  switch(n) {
+    case  0:  return( 0.0 ); /* constant */
+    case  1:  return( 1.0 );
+    case  2:  return( 0.0 ); /* affine      order = 1   terms = 3 */
+    case  3:  return(  y  ); /* bilinear    order = 1.5 terms = 4 */
+    case  4:  return(  x  );
+    case  5:  return( 0.0 ); /* quadratic   order = 2   terms = 6 */
+    case  6:  return( x*x );
+    case  7:  return( x*y );
+    case  8:  return( y*y );
+    case  9:  return( 0.0 ); /* cubic       order = 3   terms = 10 */
+    case 10:  return( x*x*x );
+    case 11:  return( x*x*y );
+    case 12:  return( x*y*y );
+    case 13:  return( y*y*y );
+    case 14:  return( 0.0 ); /* quartic     order = 4   terms = 15 */
+    case 15:  return( x*x*x*x );
+    case 16:  return( x*x*x*y );
+    case 17:  return( x*x*y*y );
+    case 18:  return( x*y*y*y );
+    case 19:  return( y*y*y*y );
+    case 20:  return( 0.0 ); /* quintic     order = 5   terms = 21 */
+  }
+  return( 0.0 ); /* should never happen */
+}
+static double poly_basis_dy(ssize_t n, double x, double y)
+{
+  /* polynomial term for y derivative */
+  switch(n) {
+    case  0:  return( 0.0 ); /* constant */
+    case  1:  return( 0.0 );
+    case  2:  return( 1.0 ); /* affine      order = 1   terms = 3 */
+    case  3:  return(  x  ); /* bilinear    order = 1.5 terms = 4 */
+    case  4:  return( 0.0 );
+    case  5:  return(  y  ); /* quadratic   order = 2   terms = 6 */
+    default:  return( poly_basis_dx(n-1,x,y) ); /* weird but true */
+  }
+  /* NOTE: the only reason that last is not true for 'quadratic'
+     is due to the re-arrangement of terms to allow for 'bilinear'
+  */
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e n e r a t e C o e f f i c i e n t s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GenerateCoefficients() takes user provided input arguments and generates
+%  the coefficients, needed to apply the specific distortion for either
+%  distorting images (generally using control points) or generating a color
+%  gradient from sparsely separated color points.
+%
+%  The format of the GenerateCoefficients() method is:
+%
+%    Image *GenerateCoefficients(const Image *image,DistortImageMethod method,
+%        const size_t number_arguments,const double *arguments,
+%        size_t number_values, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to be distorted.
+%
+%    o method: the method of image distortion/ sparse gradient
+%
+%    o number_arguments: the number of arguments given.
+%
+%    o arguments: the arguments for this distortion method.
+%
+%    o number_values: the style and format of given control points, (caller type)
+%         0: 2 dimensional mapping of control points (Distort)
+%            Format:  u,v,x,y  where u,v is the 'source' of the
+%            the color to be plotted, for DistortImage()
+%         N: Interpolation of control points with N values (usally r,g,b)
+%            Format: x,y,r,g,b    mapping x,y to color values r,g,b
+%            IN future, variable number of values may be given (1 to N)
+%
+%    o exception: return any errors or warnings in this structure
+%
+%  Note that the returned array of double values must be freed by the
+%  calling method using RelinquishMagickMemory().  This however may change in
+%  the future to require a more 'method' specific method.
+%
+%  Because of this this method should not be classed as stable or used
+%  outside other MagickCore library methods.
+*/
+
+static double *GenerateCoefficients(const Image *image,
+  DistortImageMethod *method,const size_t number_arguments,
+  const double *arguments,size_t number_values,ExceptionInfo *exception)
+{
+  double
+    *coeff;
+
+  register size_t
+    i;
+
+  size_t
+    number_coeff, /* number of coefficients to return (array size) */
+    cp_size,      /* number floating point numbers per control point */
+    cp_x,cp_y,    /* the x,y indexes for control point */
+    cp_values;    /* index of values for this control point */
+    /* number_values   Number of values given per control point */
+
+  if ( number_values == 0 ) {
+    /* Image distortion using control points (or other distortion)
+       That is generate a mapping so that   x,y->u,v   given  u,v,x,y
+    */
+    number_values = 2;   /* special case: two values of u,v */
+    cp_values = 0;       /* the values i,j are BEFORE the destination CP x,y */
+    cp_x = 2;            /* location of x,y in input control values */
+    cp_y = 3;
+    /* NOTE: cp_values, also used for later 'reverse map distort' tests */
+  }
+  else {
+    cp_x = 0;            /* location of x,y in input control values */
+    cp_y = 1;
+    cp_values = 2;       /* and the other values are after x,y */
+    /* Typically in this case the values are R,G,B color values */
+  }
+  cp_size = number_values+2; /* each CP defintion involves this many numbers */
+
+  /* If not enough control point pairs are found for specific distortions
+     fall back to Affine distortion (allowing 0 to 3 point pairs)
+  */
+  if ( number_arguments < 4*cp_size &&
+       (  *method == BilinearForwardDistortion
+       || *method == BilinearReverseDistortion
+       || *method == PerspectiveDistortion
+       ) )
+    *method = AffineDistortion;
+
+  number_coeff=0;
+  switch (*method) {
+    case AffineDistortion:
+    /* also BarycentricColorInterpolate: */
+      number_coeff=3*number_values;
+      break;
+    case PolynomialDistortion:
+      /* number of coefficents depend on the given polynomal 'order' */
+      if ( number_arguments <= 1 && (number_arguments-1)%cp_size != 0)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+                   "InvalidArgument","%s : '%s'","Polynomial",
+                   "Invalid number of args: order [CPs]...");
+        return((double *) NULL);
+      }
+      i = poly_number_terms(arguments[0]);
+      number_coeff = 2 + i*number_values;
+      if ( i == 0 ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+                   "InvalidArgument","%s : '%s'","Polynomial",
+                   "Invalid order, should be interger 1 to 5, or 1.5");
+        return((double *) NULL);
+      }
+      if ( number_arguments < 1+i*cp_size ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+               "InvalidArgument", "%s : 'require at least %.20g CPs'",
+               "Polynomial", (double) i);
+        return((double *) NULL);
+      }
+      break;
+    case BilinearReverseDistortion:
+      number_coeff=4*number_values;
+      break;
+    /*
+      The rest are constants as they are only used for image distorts
+    */
+    case BilinearForwardDistortion:
+      number_coeff=10; /* 2*4 coeff plus 2 constants */
+      cp_x = 0;        /* Reverse src/dest coords for forward mapping */
+      cp_y = 1;
+      cp_values = 2;
+      break;
+#if 0
+    case QuadraterialDistortion:
+      number_coeff=19; /* BilinearForward + BilinearReverse */
+#endif
+      break;
+    case ShepardsDistortion:
+      number_coeff=1;  /* not used, but provide some type of return */
+      break;
+    case ArcDistortion:
+      number_coeff=5;
+      break;
+    case ScaleRotateTranslateDistortion:
+    case AffineProjectionDistortion:
+    case Plane2CylinderDistortion:
+    case Cylinder2PlaneDistortion:
+      number_coeff=6;
+      break;
+    case PolarDistortion:
+    case DePolarDistortion:
+      number_coeff=8;
+      break;
+    case PerspectiveDistortion:
+    case PerspectiveProjectionDistortion:
+      number_coeff=9;
+      break;
+    case BarrelDistortion:
+    case BarrelInverseDistortion:
+      number_coeff=10;
+      break;
+    default:
+      assert(! "Unknown Method Given"); /* just fail assertion */
+  }
+
+  /* allocate the array of coefficients needed */
+  coeff = (double *) AcquireQuantumMemory(number_coeff,sizeof(*coeff));
+  if (coeff == (double *) NULL) {
+    (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed",
+                  "%s", "GenerateCoefficients");
+    return((double *) NULL);
+  }
+
+  /* zero out coefficients array */
+  for (i=0; i < number_coeff; i++)
+    coeff[i] = 0.0;
+
+  switch (*method)
+  {
+    case AffineDistortion:
+    {
+      /* Affine Distortion
+           v =  c0*x + c1*y + c2
+         for each 'value' given
+
+         Input Arguments are sets of control points...
+         For Distort Images    u,v, x,y  ...
+         For Sparse Gradients  x,y, r,g,b  ...
+      */
+      if ( number_arguments%cp_size != 0 ||
+           number_arguments < cp_size ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+               "InvalidArgument", "%s : 'require at least %.20g CPs'",
+               "Affine", 1.0);
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      /* handle special cases of not enough arguments */
+      if ( number_arguments == cp_size ) {
+        /* Only 1 CP Set Given */
+        if ( cp_values == 0 ) {
+          /* image distortion - translate the image */
+          coeff[0] = 1.0;
+          coeff[2] = arguments[0] - arguments[2];
+          coeff[4] = 1.0;
+          coeff[5] = arguments[1] - arguments[3];
+        }
+        else {
+          /* sparse gradient - use the values directly */
+          for (i=0; i<number_values; i++)
+            coeff[i*3+2] = arguments[cp_values+i];
+        }
+      }
+      else {
+        /* 2 or more points (usally 3) given.
+           Solve a least squares simultaneous equation for coefficients.
+        */
+        double
+          **matrix,
+          **vectors,
+          terms[3];
+
+        MagickBooleanType
+          status;
+
+        /* create matrix, and a fake vectors matrix */
+        matrix = AcquireMagickMatrix(3UL,3UL);
+        vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
+        if (matrix == (double **) NULL || vectors == (double **) NULL)
+        {
+          matrix  = RelinquishMagickMatrix(matrix, 3UL);
+          vectors = (double **) RelinquishMagickMemory(vectors);
+          coeff   = (double *) RelinquishMagickMemory(coeff);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed",
+                  "%s", "DistortCoefficients");
+          return((double *) NULL);
+        }
+        /* fake a number_values x3 vectors matrix from coefficients array */
+        for (i=0; i < number_values; i++)
+          vectors[i] = &(coeff[i*3]);
+        /* Add given control point pairs for least squares solving */
+        for (i=0; i < number_arguments; i+=cp_size) {
+          terms[0] = arguments[i+cp_x];  /* x */
+          terms[1] = arguments[i+cp_y];  /* y */
+          terms[2] = 1;                  /* 1 */
+          LeastSquaresAddTerms(matrix,vectors,terms,
+                   &(arguments[i+cp_values]),3UL,number_values);
+        }
+        if ( number_arguments == 2*cp_size ) {
+          /* Only two pairs were given, but we need 3 to solve the affine.
+             Fake extra coordinates by rotating p1 around p0 by 90 degrees.
+               x2 = x0 - (y1-y0)   y2 = y0 + (x1-x0)
+           */
+          terms[0] = arguments[cp_x]
+                   - ( arguments[cp_size+cp_y] - arguments[cp_y] ); /* x2 */
+          terms[1] = arguments[cp_y] +
+                   + ( arguments[cp_size+cp_x] - arguments[cp_x] ); /* y2 */
+          terms[2] = 1;                                             /* 1 */
+          if ( cp_values == 0 ) {
+            /* Image Distortion - rotate the u,v coordients too */
+            double
+              uv2[2];
+            uv2[0] = arguments[0] - arguments[5] + arguments[1];   /* u2 */
+            uv2[1] = arguments[1] + arguments[4] - arguments[0];   /* v2 */
+            LeastSquaresAddTerms(matrix,vectors,terms,uv2,3UL,2UL);
+          }
+          else {
+            /* Sparse Gradient - use values of p0 for linear gradient */
+            LeastSquaresAddTerms(matrix,vectors,terms,
+                  &(arguments[cp_values]),3UL,number_values);
+          }
+        }
+        /* Solve for LeastSquares Coefficients */
+        status=GaussJordanElimination(matrix,vectors,3UL,number_values);
+        matrix = RelinquishMagickMatrix(matrix, 3UL);
+        vectors = (double **) RelinquishMagickMemory(vectors);
+        if ( status == MagickFalse ) {
+          coeff = (double *) RelinquishMagickMemory(coeff);
+          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument","%s : 'Unsolvable Matrix'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method) );
+          return((double *) NULL);
+        }
+      }
+      return(coeff);
+    }
+    case AffineProjectionDistortion:
+    {
+      /*
+        Arguments: Affine Matrix (forward mapping)
+        Arguments  sx, rx, ry, sy, tx, ty
+        Where      u = sx*x + ry*y + tx
+                   v = rx*x + sy*y + ty
+
+        Returns coefficients (in there inverse form) ordered as...
+             sx ry tx  rx sy ty
+
+        AffineProjection Distortion Notes...
+           + Will only work with a 2 number_values for Image Distortion
+           + Can not be used for generating a sparse gradient (interpolation)
+      */
+      double inverse[8];
+      if (number_arguments != 6) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument","%s : 'Needs 6 coeff values'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      /* FUTURE: trap test for sx*sy-rx*ry == 0 (determinant = 0, no inverse) */
+      for(i=0; i<6UL; i++ )
+        inverse[i] = arguments[i];
+      AffineArgsToCoefficients(inverse); /* map into coefficents */
+      InvertAffineCoefficients(inverse, coeff); /* invert */
+      *method = AffineDistortion;
+
+      return(coeff);
+    }
+    case ScaleRotateTranslateDistortion:
+    {
+      /* Scale, Rotate and Translate Distortion
+         An alternative Affine Distortion
+         Argument options, by number of arguments given:
+           7: x,y, sx,sy, a, nx,ny
+           6: x,y,   s,   a, nx,ny
+           5: x,y, sx,sy, a
+           4: x,y,   s,   a
+           3: x,y,        a
+           2:        s,   a
+           1:             a
+         Where actions are (in order of application)
+            x,y     'center' of transforms     (default = image center)
+            sx,sy   scale image by this amount (default = 1)
+            a       angle of rotation          (argument required)
+            nx,ny   move 'center' here         (default = x,y or no movement)
+         And convert to affine mapping coefficients
+
+         ScaleRotateTranslate Distortion Notes...
+           + Does not use a set of CPs in any normal way
+           + Will only work with a 2 number_valuesal Image Distortion
+           + Cannot be used for generating a sparse gradient (interpolation)
+      */
+      double
+        cosine, sine,
+        x,y,sx,sy,a,nx,ny;
+
+      /* set default center, and default scale */
+      x = nx = (double)(image->columns)/2.0 + (double)image->page.x;
+      y = ny = (double)(image->rows)/2.0    + (double)image->page.y;
+      sx = sy = 1.0;
+      switch ( number_arguments ) {
+      case 0:
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument","%s : 'Needs at least 1 argument'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      case 1:
+        a = arguments[0];
+        break;
+      case 2:
+        sx = sy = arguments[0];
+        a = arguments[1];
+        break;
+      default:
+        x = nx = arguments[0];
+        y = ny = arguments[1];
+        switch ( number_arguments ) {
+        case 3:
+          a = arguments[2];
+          break;
+        case 4:
+          sx = sy = arguments[2];
+          a = arguments[3];
+          break;
+        case 5:
+          sx = arguments[2];
+          sy = arguments[3];
+          a = arguments[4];
+          break;
+        case 6:
+          sx = sy = arguments[2];
+          a = arguments[3];
+          nx = arguments[4];
+          ny = arguments[5];
+          break;
+        case 7:
+          sx = arguments[2];
+          sy = arguments[3];
+          a = arguments[4];
+          nx = arguments[5];
+          ny = arguments[6];
+          break;
+        default:
+          coeff = (double *) RelinquishMagickMemory(coeff);
+          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument","%s : 'Too Many Arguments (7 or less)'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method) );
+          return((double *) NULL);
+        }
+        break;
+      }
+      /* Trap if sx or sy == 0 -- image is scaled out of existance! */
+      if ( fabs(sx) < MagickEpsilon || fabs(sy) < MagickEpsilon ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument","%s : 'Zero Scale Given'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      /* Save the given arguments as an affine distortion */
+      a=DegreesToRadians(a); cosine=cos(a); sine=sin(a);
+
+      *method = AffineDistortion;
+      coeff[0]=cosine/sx;
+      coeff[1]=sine/sx;
+      coeff[2]=x-nx*coeff[0]-ny*coeff[1];
+      coeff[3]=(-sine)/sy;
+      coeff[4]=cosine/sy;
+      coeff[5]=y-nx*coeff[3]-ny*coeff[4];
+      return(coeff);
+    }
+    case PerspectiveDistortion:
+    { /*
+         Perspective Distortion (a ratio of affine distortions)
+
+                p(x,y)    c0*x + c1*y + c2
+            u = ------ = ------------------
+                r(x,y)    c6*x + c7*y + 1
+
+                q(x,y)    c3*x + c4*y + c5
+            v = ------ = ------------------
+                r(x,y)    c6*x + c7*y + 1
+
+           c8 = Sign of 'r', or the denominator affine, for the actual image.
+                This determines what part of the distorted image is 'ground'
+                side of the horizon, the other part is 'sky' or invalid.
+                Valid values are  +1.0  or  -1.0  only.
+
+         Input Arguments are sets of control points...
+         For Distort Images    u,v, x,y  ...
+         For Sparse Gradients  x,y, r,g,b  ...
+
+         Perspective Distortion Notes...
+           + Can be thought of as ratio of  3 affine transformations
+           + Not separatable: r() or c6 and c7 are used by both equations
+           + All 8 coefficients must be determined simultaniously
+           + Will only work with a 2 number_valuesal Image Distortion
+           + Can not be used for generating a sparse gradient (interpolation)
+           + It is not linear, but is simple to generate an inverse
+           + All lines within an image remain lines.
+           + but distances between points may vary.
+      */
+      double
+        **matrix,
+        *vectors[1],
+        terms[8];
+
+      size_t
+        cp_u = cp_values,
+        cp_v = cp_values+1;
+
+      MagickBooleanType
+        status;
+
+      if ( number_arguments%cp_size != 0 ||
+           number_arguments < cp_size*4 ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument", "%s : 'require at least %.20g CPs'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method), 4.0);
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      /* fake 1x8 vectors matrix directly using the coefficients array */
+      vectors[0] = &(coeff[0]);
+      /* 8x8 least-squares matrix (zeroed) */
+      matrix = AcquireMagickMatrix(8UL,8UL);
+      if (matrix == (double **) NULL) {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed",
+                  "%s", "DistortCoefficients");
+        return((double *) NULL);
+      }
+      /* Add control points for least squares solving */
+      for (i=0; i < number_arguments; i+=4) {
+        terms[0]=arguments[i+cp_x];            /*   c0*x   */
+        terms[1]=arguments[i+cp_y];            /*   c1*y   */
+        terms[2]=1.0;                          /*   c2*1   */
+        terms[3]=0.0;
+        terms[4]=0.0;
+        terms[5]=0.0;
+        terms[6]=-terms[0]*arguments[i+cp_u];  /* 1/(c6*x) */
+        terms[7]=-terms[1]*arguments[i+cp_u];  /* 1/(c7*y) */
+        LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_u]),
+            8UL,1UL);
+
+        terms[0]=0.0;
+        terms[1]=0.0;
+        terms[2]=0.0;
+        terms[3]=arguments[i+cp_x];           /*   c3*x   */
+        terms[4]=arguments[i+cp_y];           /*   c4*y   */
+        terms[5]=1.0;                         /*   c5*1   */
+        terms[6]=-terms[3]*arguments[i+cp_v]; /* 1/(c6*x) */
+        terms[7]=-terms[4]*arguments[i+cp_v]; /* 1/(c7*y) */
+        LeastSquaresAddTerms(matrix,vectors,terms,&(arguments[i+cp_v]),
+            8UL,1UL);
+      }
+      /* Solve for LeastSquares Coefficients */
+      status=GaussJordanElimination(matrix,vectors,8UL,1UL);
+      matrix = RelinquishMagickMatrix(matrix, 8UL);
+      if ( status == MagickFalse ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument","%s : 'Unsolvable Matrix'",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      /*
+        Calculate 9'th coefficient! The ground-sky determination.
+        What is sign of the 'ground' in r() denominator affine function?
+        Just use any valid image coordinate (first control point) in
+        destination for determination of what part of view is 'ground'.
+      */
+      coeff[8] = coeff[6]*arguments[cp_x]
+                      + coeff[7]*arguments[cp_y] + 1.0;
+      coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0;
+
+      return(coeff);
+    }
+    case PerspectiveProjectionDistortion:
+    {
+      /*
+        Arguments: Perspective Coefficents (forward mapping)
+      */
+      if (number_arguments != 8) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument", "%s : 'Needs 8 coefficient values'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method));
+        return((double *) NULL);
+      }
+      /* FUTURE: trap test  c0*c4-c3*c1 == 0  (determinate = 0, no inverse) */
+      InvertPerspectiveCoefficients(arguments, coeff);
+      /*
+        Calculate 9'th coefficient! The ground-sky determination.
+        What is sign of the 'ground' in r() denominator affine function?
+        Just use any valid image cocodinate in destination for determination.
+        For a forward mapped perspective the images 0,0 coord will map to
+        c2,c5 in the distorted image, so set the sign of denominator of that.
+      */
+      coeff[8] = coeff[6]*arguments[2]
+                           + coeff[7]*arguments[5] + 1.0;
+      coeff[8] = (coeff[8] < 0.0) ? -1.0 : +1.0;
+      *method = PerspectiveDistortion;
+
+      return(coeff);
+    }
+    case BilinearForwardDistortion:
+    case BilinearReverseDistortion:
+    {
+      /* Bilinear Distortion (Forward mapping)
+            v = c0*x + c1*y + c2*x*y + c3;
+         for each 'value' given
+
+         This is actually a simple polynomial Distortion!  The difference
+         however is when we need to reverse the above equation to generate a
+         BilinearForwardDistortion (see below).
+
+         Input Arguments are sets of control points...
+         For Distort Images    u,v, x,y  ...
+         For Sparse Gradients  x,y, r,g,b  ...
+
+      */
+      double
+        **matrix,
+        **vectors,
+        terms[4];
+
+      MagickBooleanType
+        status;
+
+      /* check the number of arguments */
+      if ( number_arguments%cp_size != 0 ||
+           number_arguments < cp_size*4 ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument", "%s : 'require at least %.20g CPs'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method), 4.0);
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      /* create matrix, and a fake vectors matrix */
+      matrix = AcquireMagickMatrix(4UL,4UL);
+      vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
+      if (matrix == (double **) NULL || vectors == (double **) NULL)
+      {
+        matrix  = RelinquishMagickMatrix(matrix, 4UL);
+        vectors = (double **) RelinquishMagickMemory(vectors);
+        coeff   = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed",
+                "%s", "DistortCoefficients");
+        return((double *) NULL);
+      }
+      /* fake a number_values x4 vectors matrix from coefficients array */
+      for (i=0; i < number_values; i++)
+        vectors[i] = &(coeff[i*4]);
+      /* Add given control point pairs for least squares solving */
+      for (i=0; i < number_arguments; i+=cp_size) {
+        terms[0] = arguments[i+cp_x];   /*  x  */
+        terms[1] = arguments[i+cp_y];   /*  y  */
+        terms[2] = terms[0]*terms[1];   /* x*y */
+        terms[3] = 1;                   /*  1  */
+        LeastSquaresAddTerms(matrix,vectors,terms,
+             &(arguments[i+cp_values]),4UL,number_values);
+      }
+      /* Solve for LeastSquares Coefficients */
+      status=GaussJordanElimination(matrix,vectors,4UL,number_values);
+      matrix  = RelinquishMagickMatrix(matrix, 4UL);
+      vectors = (double **) RelinquishMagickMemory(vectors);
+      if ( status == MagickFalse ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument","%s : 'Unsolvable Matrix'",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      if ( *method == BilinearForwardDistortion ) {
+         /* Bilinear Forward Mapped Distortion
+
+         The above least-squares solved for coefficents but in the forward
+         direction, due to changes to indexing constants.
+
+            i = c0*x + c1*y + c2*x*y + c3;
+            j = c4*x + c5*y + c6*x*y + c7;
+
+         where i,j are in the destination image, NOT the source.
+
+         Reverse Pixel mapping however needs to use reverse of these
+         functions.  It required a full page of algbra to work out the
+         reversed mapping formula, but resolves down to the following...
+
+            c8 = c0*c5-c1*c4;
+            c9 = 2*(c2*c5-c1*c6);   // '2*a' in the quadratic formula
+
+            i = i - c3;   j = j - c7;
+            b = c6*i - c2*j + c8;   // So that   a*y^2 + b*y + c == 0
+            c = c4*i -  c0*j;       // y = ( -b +- sqrt(bb - 4ac) ) / (2*a)
+
+            r = b*b - c9*(c+c);
+            if ( c9 != 0 )
+              y = ( -b + sqrt(r) ) / c9;
+            else
+              y = -c/b;
+
+            x = ( i - c1*y) / ( c1 - c2*y );
+
+         NB: if 'r' is negative there is no solution!
+         NB: the sign of the sqrt() should be negative if image becomes
+             flipped or flopped, or crosses over itself.
+         NB: techniqually coefficient c5 is not needed, anymore,
+             but kept for completness.
+
+         See Anthony Thyssen <A.Thyssen@griffith.edu.au>
+         or  Fred Weinhaus <fmw@alink.net>  for more details.
+
+         */
+         coeff[8] = coeff[0]*coeff[5] - coeff[1]*coeff[4];
+         coeff[9] = 2*(coeff[2]*coeff[5] - coeff[1]*coeff[6]);
+      }
+      return(coeff);
+    }
+#if 0
+    case QuadrilateralDistortion:
+    {
+      /* Map a Quadrilateral to a unit square using BilinearReverse
+         Then map that unit square back to the final Quadrilateral
+         using BilinearForward.
+
+         Input Arguments are sets of control points...
+         For Distort Images    u,v, x,y  ...
+         For Sparse Gradients  x,y, r,g,b  ...
+
+      */
+      /* UNDER CONSTRUCTION */
+      return(coeff);
+    }
+#endif
+
+    case PolynomialDistortion:
+    {
+      /* Polynomial Distortion
+
+         First two coefficents are used to hole global polynomal information
+           c0 = Order of the polynimial being created
+           c1 = number_of_terms in one polynomial equation
+
+         Rest of the coefficients map to the equations....
+            v = c0 + c1*x + c2*y + c3*x*y + c4*x^2 + c5*y^2 + c6*x^3 + ...
+         for each 'value' (number_values of them) given.
+         As such total coefficients =  2 + number_terms * number_values
+
+         Input Arguments are sets of control points...
+         For Distort Images    order  [u,v, x,y] ...
+         For Sparse Gradients  order  [x,y, r,g,b] ...
+
+         Polynomial Distortion Notes...
+           + UNDER DEVELOPMENT -- Do not expect this to remain as is.
+           + Currently polynomial is a reversed mapped distortion.
+           + Order 1.5 is fudged to map into a bilinear distortion.
+             though it is not the same order as that distortion.
+      */
+      double
+        **matrix,
+        **vectors,
+        *terms;
+
+      size_t
+        nterms;   /* number of polynomial terms per number_values */
+
+      register ssize_t
+        j;
+
+      MagickBooleanType
+        status;
+
+      /* first two coefficients hold polynomial order information */
+      coeff[0] = arguments[0];
+      coeff[1] = (double) poly_number_terms(arguments[0]);
+      nterms = (size_t) coeff[1];
+
+      /* create matrix, a fake vectors matrix, and least sqs terms */
+      matrix = AcquireMagickMatrix(nterms,nterms);
+      vectors = (double **) AcquireQuantumMemory(number_values,sizeof(*vectors));
+      terms = (double *) AcquireQuantumMemory(nterms, sizeof(*terms));
+      if (matrix  == (double **) NULL ||
+          vectors == (double **) NULL ||
+          terms   == (double *) NULL )
+      {
+        matrix  = RelinquishMagickMatrix(matrix, nterms);
+        vectors = (double **) RelinquishMagickMemory(vectors);
+        terms   = (double *) RelinquishMagickMemory(terms);
+        coeff   = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed",
+                "%s", "DistortCoefficients");
+        return((double *) NULL);
+      }
+      /* fake a number_values x3 vectors matrix from coefficients array */
+      for (i=0; i < number_values; i++)
+        vectors[i] = &(coeff[2+i*nterms]);
+      /* Add given control point pairs for least squares solving */
+      for (i=1; i < number_arguments; i+=cp_size) { /* NB: start = 1 not 0 */
+        for (j=0; j < (ssize_t) nterms; j++)
+          terms[j] = poly_basis_fn(j,arguments[i+cp_x],arguments[i+cp_y]);
+        LeastSquaresAddTerms(matrix,vectors,terms,
+             &(arguments[i+cp_values]),nterms,number_values);
+      }
+      terms = (double *) RelinquishMagickMemory(terms);
+      /* Solve for LeastSquares Coefficients */
+      status=GaussJordanElimination(matrix,vectors,nterms,number_values);
+      matrix  = RelinquishMagickMatrix(matrix, nterms);
+      vectors = (double **) RelinquishMagickMemory(vectors);
+      if ( status == MagickFalse ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument","%s : 'Unsolvable Matrix'",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      return(coeff);
+    }
+    case ArcDistortion:
+    {
+      /* Arc Distortion
+         Args: arc_width  rotate  top_edge_radius  bottom_edge_radius
+         All but first argument are optional
+            arc_width      The angle over which to arc the image side-to-side
+            rotate         Angle to rotate image from vertical center
+            top_radius     Set top edge of source image at this radius
+            bottom_radius  Set bootom edge to this radius (radial scaling)
+
+         By default, if the radii arguments are nor provided the image radius
+         is calculated so the horizontal center-line is fits the given arc
+         without scaling.
+
+         The output image size is ALWAYS adjusted to contain the whole image,
+         and an offset is given to position image relative to the 0,0 point of
+         the origin, allowing users to use relative positioning onto larger
+         background (via -flatten).
+
+         The arguments are converted to these coefficients
+            c0: angle for center of source image
+            c1: angle scale for mapping to source image
+            c2: radius for top of source image
+            c3: radius scale for mapping source image
+            c4: centerline of arc within source image
+
+         Note the coefficients use a center angle, so asymptotic join is
+         furthest from both sides of the source image. This also means that
+         for arc angles greater than 360 the sides of the image will be
+         trimmed equally.
+
+         Arc Distortion Notes...
+           + Does not use a set of CPs
+           + Will only work with Image Distortion
+           + Can not be used for generating a sparse gradient (interpolation)
+      */
+      if ( number_arguments >= 1 && arguments[0] < MagickEpsilon ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument","%s : 'Arc Angle Too Small'",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      if ( number_arguments >= 3 && arguments[2] < MagickEpsilon ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument","%s : 'Outer Radius Too Small'",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        return((double *) NULL);
+      }
+      coeff[0] = -MagickPI2;   /* -90, place at top! */
+      if ( number_arguments >= 1 )
+        coeff[1] = DegreesToRadians(arguments[0]);
+      else
+        coeff[1] = MagickPI2;   /* zero arguments - center is at top */
+      if ( number_arguments >= 2 )
+        coeff[0] += DegreesToRadians(arguments[1]);
+      coeff[0] /= Magick2PI;  /* normalize radians */
+      coeff[0] -= MagickRound(coeff[0]);
+      coeff[0] *= Magick2PI;  /* de-normalize back to radians */
+      coeff[3] = (double)image->rows-1;
+      coeff[2] = (double)image->columns/coeff[1] + coeff[3]/2.0;
+      if ( number_arguments >= 3 ) {
+        if ( number_arguments >= 4 )
+          coeff[3] = arguments[2] - arguments[3];
+        else
+          coeff[3] *= arguments[2]/coeff[2];
+        coeff[2] = arguments[2];
+      }
+      coeff[4] = ((double)image->columns-1.0)/2.0;
+
+      return(coeff);
+    }
+    case PolarDistortion:
+    case DePolarDistortion:
+    {
+      /* (De)Polar Distortion   (same set of arguments)
+         Args:  Rmax, Rmin,  Xcenter,Ycenter,  Afrom,Ato
+         DePolar can also have the extra arguments of Width, Height
+
+         Coefficients 0 to 5 is the sanatized version first 6 input args
+         Coefficient 6  is the angle to coord ratio  and visa-versa
+         Coefficient 7  is the radius to coord ratio and visa-versa
+
+         WARNING: It is possible for  Radius max<min  and/or  Angle from>to
+      */
+      if ( number_arguments == 3
+          || ( number_arguments > 6 && *method == PolarDistortion )
+          || number_arguments > 8 ) {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            OptionError,"InvalidArgument", "%s : number of arguments",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      /* Rmax -  if 0 calculate appropriate value */
+      if ( number_arguments >= 1 )
+        coeff[0] = arguments[0];
+      else
+        coeff[0] = 0.0;
+      /* Rmin  - usally 0 */
+      coeff[1] = number_arguments >= 2 ? arguments[1] : 0.0;
+      /* Center X,Y */
+      if ( number_arguments >= 4 ) {
+        coeff[2] = arguments[2];
+        coeff[3] = arguments[3];
+      }
+      else { /* center of actual image */
+        coeff[2] = (double)(image->columns)/2.0+image->page.x;
+        coeff[3] = (double)(image->rows)/2.0+image->page.y;
+      }
+      /* Angle from,to - about polar center 0 is downward */
+      coeff[4] = -MagickPI;
+      if ( number_arguments >= 5 )
+        coeff[4] = DegreesToRadians(arguments[4]);
+      coeff[5] = coeff[4];
+      if ( number_arguments >= 6 )
+        coeff[5] = DegreesToRadians(arguments[5]);
+      if ( fabs(coeff[4]-coeff[5]) < MagickEpsilon )
+        coeff[5] += Magick2PI; /* same angle is a full circle */
+      /* if radius 0 or negative,  its a special value... */
+      if ( coeff[0] < MagickEpsilon ) {
+        /* Use closest edge  if radius == 0 */
+        if ( fabs(coeff[0]) < MagickEpsilon ) {
+          coeff[0]=MagickMin(fabs(coeff[2]-image->page.x),
+                             fabs(coeff[3]-image->page.y));
+          coeff[0]=MagickMin(coeff[0],
+                       fabs(coeff[2]-image->page.x-image->columns));
+          coeff[0]=MagickMin(coeff[0],
+                       fabs(coeff[3]-image->page.y-image->rows));
+        }
+        /* furthest diagonal if radius == -1 */
+        if ( fabs(-1.0-coeff[0]) < MagickEpsilon ) {
+          double rx,ry;
+          rx = coeff[2]-image->page.x;
+          ry = coeff[3]-image->page.y;
+          coeff[0] = rx*rx+ry*ry;
+          ry = coeff[3]-image->page.y-image->rows;
+          coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry);
+          rx = coeff[2]-image->page.x-image->columns;
+          coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry);
+          ry = coeff[3]-image->page.y;
+          coeff[0] = MagickMax(coeff[0],rx*rx+ry*ry);
+          coeff[0] = sqrt(coeff[0]);
+        }
+      }
+      /* IF Rmax <= 0 or Rmin < 0 OR Rmax < Rmin, THEN error */
+      if ( coeff[0] < MagickEpsilon || coeff[1] < -MagickEpsilon
+           || (coeff[0]-coeff[1]) < MagickEpsilon ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument", "%s : Invalid Radius",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      /* converstion ratios */
+      if ( *method == PolarDistortion ) {
+        coeff[6]=(double) image->columns/(coeff[5]-coeff[4]);
+        coeff[7]=(double) image->rows/(coeff[0]-coeff[1]);
+      }
+      else { /* *method == DePolarDistortion */
+        coeff[6]=(coeff[5]-coeff[4])/image->columns;
+        coeff[7]=(coeff[0]-coeff[1])/image->rows;
+      }
+      return(coeff);
+    }
+    case Cylinder2PlaneDistortion:
+    case Plane2CylinderDistortion:
+    {
+      /* 3D Cylinder to/from a Tangential Plane
+
+         Projection between a clinder and flat plain from a point on the
+         center line of the cylinder.
+
+         The two surfaces coincide in 3D space at the given centers of
+         distortion (perpendicular to projection point) on both images.
+
+         Args:  FOV_arc_width
+         Coefficents: FOV(radians), Radius, center_x,y, dest_center_x,y
+
+         FOV (Field Of View) the angular field of view of the distortion,
+         across the width of the image, in degrees.  The centers are the
+         points of least distortion in the input and resulting images.
+
+         These centers are however determined later.
+
+         Coeff 0 is the FOV angle of view of image width in radians
+         Coeff 1 is calculated radius of cylinder.
+         Coeff 2,3  center of distortion of input image
+         Coefficents 4,5 Center of Distortion of dest (determined later)
+      */
+      if ( arguments[0] < MagickEpsilon || arguments[0] > 160.0 ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+            "InvalidArgument", "%s : Invalid FOV Angle",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      coeff[0] = DegreesToRadians(arguments[0]);
+      if ( *method == Cylinder2PlaneDistortion )
+        /* image is curved around cylinder, so FOV angle (in radians)
+         * scales directly to image X coordinate, according to its radius.
+         */
+        coeff[1] = (double) image->columns/coeff[0];
+      else
+        /* radius is distance away from an image with this angular FOV */
+        coeff[1] = (double) image->columns / ( 2 * tan(coeff[0]/2) );
+
+      coeff[2] = (double)(image->columns)/2.0+image->page.x;
+      coeff[3] = (double)(image->rows)/2.0+image->page.y;
+      coeff[4] = coeff[2];
+      coeff[5] = coeff[3]; /* assuming image size is the same */
+      return(coeff);
+    }
+    case BarrelDistortion:
+    case BarrelInverseDistortion:
+    {
+      /* Barrel Distortion
+           Rs=(A*Rd^3 + B*Rd^2 + C*Rd + D)*Rd
+         BarrelInv Distortion
+           Rs=Rd/(A*Rd^3 + B*Rd^2 + C*Rd + D)
+
+        Where Rd is the normalized radius from corner to middle of image
+        Input Arguments are one of the following forms (number of arguments)...
+            3:  A,B,C
+            4:  A,B,C,D
+            5:  A,B,C    X,Y
+            6:  A,B,C,D  X,Y
+            8:  Ax,Bx,Cx,Dx  Ay,By,Cy,Dy
+           10:  Ax,Bx,Cx,Dx  Ay,By,Cy,Dy   X,Y
+
+        Returns 10 coefficent values, which are de-normalized (pixel scale)
+          Ax, Bx, Cx, Dx,   Ay, By, Cy, Dy,    Xc, Yc
+      */
+      /* Radius de-normalization scaling factor */
+      double
+        rscale = 2.0/MagickMin((double) image->columns,(double) image->rows);
+
+      /* sanity check  number of args must = 3,4,5,6,8,10 or error */
+      if ( (number_arguments  < 3) || (number_arguments == 7) ||
+           (number_arguments == 9) || (number_arguments > 10) )
+        {
+          coeff=(double *) RelinquishMagickMemory(coeff);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            OptionError,"InvalidArgument", "%s : number of arguments",
+            CommandOptionToMnemonic(MagickDistortOptions, *method) );
+          return((double *) NULL);
+        }
+      /* A,B,C,D coefficients */
+      coeff[0] = arguments[0];
+      coeff[1] = arguments[1];
+      coeff[2] = arguments[2];
+      if ((number_arguments == 3) || (number_arguments == 5) )
+        coeff[3] = 1.0 - coeff[0] - coeff[1] - coeff[2];
+      else
+        coeff[3] = arguments[3];
+      /* de-normalize the coefficients */
+      coeff[0] *= pow(rscale,3.0);
+      coeff[1] *= rscale*rscale;
+      coeff[2] *= rscale;
+      /* Y coefficients: as given OR same as X coefficients */
+      if ( number_arguments >= 8 ) {
+        coeff[4] = arguments[4] * pow(rscale,3.0);
+        coeff[5] = arguments[5] * rscale*rscale;
+        coeff[6] = arguments[6] * rscale;
+        coeff[7] = arguments[7];
+      }
+      else {
+        coeff[4] = coeff[0];
+        coeff[5] = coeff[1];
+        coeff[6] = coeff[2];
+        coeff[7] = coeff[3];
+      }
+      /* X,Y Center of Distortion (image coodinates) */
+      if ( number_arguments == 5 )  {
+        coeff[8] = arguments[3];
+        coeff[9] = arguments[4];
+      }
+      else if ( number_arguments == 6 ) {
+        coeff[8] = arguments[4];
+        coeff[9] = arguments[5];
+      }
+      else if ( number_arguments == 10 ) {
+        coeff[8] = arguments[8];
+        coeff[9] = arguments[9];
+      }
+      else {
+        /* center of the image provided (image coodinates) */
+        coeff[8] = (double)image->columns/2.0 + image->page.x;
+        coeff[9] = (double)image->rows/2.0    + image->page.y;
+      }
+      return(coeff);
+    }
+    case ShepardsDistortion:
+    {
+      /* Shepards Distortion  input arguments are the coefficents!
+         Just check the number of arguments is valid!
+         Args:  u1,v1, x1,y1, ...
+          OR :  u1,v1, r1,g1,c1, ...
+      */
+      if ( number_arguments%cp_size != 0 ||
+           number_arguments < cp_size ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+              "InvalidArgument", "%s : 'require at least %.20g CPs'",
+              CommandOptionToMnemonic(MagickDistortOptions, *method), 1.0);
+        coeff=(double *) RelinquishMagickMemory(coeff);
+        return((double *) NULL);
+      }
+      return(coeff);
+    }
+    default:
+      break;
+  }
+  /* you should never reach this point */
+  assert(! "No Method Handler"); /* just fail assertion */
+  return((double *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D i s t o r t R e s i z e I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DistortResizeImage() resize image using the equivalent but slower image
+%  distortion operator.  The filter is applied using a EWA cylindrical
+%  resampling. But like resize the final image size is limited to whole pixels
+%  with no effects by virtual-pixels on the result.
+%
+%  Note that images containing a transparency channel will be twice as slow to
+%  resize as images one without transparency.
+%
+%  The format of the DistortResizeImage method is:
+%
+%      Image *AdaptiveResizeImage(const Image *image,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the resized image.
+%
+%    o rows: the number of rows in the resized image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *DistortResizeImage(const Image *image,
+  const size_t columns,const size_t rows,ExceptionInfo *exception)
+{
+#define DistortResizeImageTag  "Distort/Image"
+
+  Image
+    *resize_image,
+    *tmp_image;
+
+  RectangleInfo
+    crop_area;
+
+  double
+    distort_args[12];
+
+  VirtualPixelMethod
+    vp_save;
+
+  /*
+    Distort resize image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((columns == 0) || (rows == 0))
+    return((Image *) NULL);
+  /* Do not short-circuit this resize if final image size is unchanged */
+
+  (void) SetImageVirtualPixelMethod(image,TransparentVirtualPixelMethod);
+
+  (void) ResetMagickMemory(distort_args,0,12*sizeof(double));
+  distort_args[4]=(double) image->columns;
+  distort_args[6]=(double) columns;
+  distort_args[9]=(double) image->rows;
+  distort_args[11]=(double) rows;
+
+  vp_save=GetImageVirtualPixelMethod(image);
+
+  tmp_image=CloneImage(image,0,0,MagickTrue,exception);
+  if ( tmp_image == (Image *) NULL )
+    return((Image *) NULL);
+  (void) SetImageVirtualPixelMethod(tmp_image,TransparentVirtualPixelMethod);
+
+  if (image->matte == MagickFalse)
+    {
+      /*
+        Image has not transparency channel, so we free to use it
+      */
+      (void) SetImageAlphaChannel(tmp_image,SetAlphaChannel);
+      resize_image=DistortImage(tmp_image,AffineDistortion,12,distort_args,
+            MagickTrue,exception),
+
+      tmp_image=DestroyImage(tmp_image);
+      if ( resize_image == (Image *) NULL )
+        return((Image *) NULL);
+
+      (void) SetImageAlphaChannel(resize_image,DeactivateAlphaChannel);
+      InheritException(exception,&image->exception);
+    }
+  else
+    {
+      /*
+        Image has transparency so handle colors and alpha separatly.
+        Basically we need to separate Virtual-Pixel alpha in the resized
+        image, so only the actual original images alpha channel is used.
+      */
+      Image
+        *resize_alpha;
+
+      /* distort alpha channel separately */
+      (void) SeparateImageChannel(tmp_image,TrueAlphaChannel);
+      (void) SetImageAlphaChannel(tmp_image,OpaqueAlphaChannel);
+      resize_alpha=DistortImage(tmp_image,AffineDistortion,12,distort_args,
+            MagickTrue,exception),
+      tmp_image=DestroyImage(tmp_image);
+      if ( resize_alpha == (Image *) NULL )
+        return((Image *) NULL);
+
+      /* distort the actual image containing alpha + VP alpha */
+      tmp_image=CloneImage(image,0,0,MagickTrue,exception);
+      if ( tmp_image == (Image *) NULL )
+        return((Image *) NULL);
+      (void) SetImageVirtualPixelMethod(tmp_image,
+                   TransparentVirtualPixelMethod);
+      resize_image=DistortImage(tmp_image,AffineDistortion,12,distort_args,
+            MagickTrue,exception),
+      tmp_image=DestroyImage(tmp_image);
+      if ( resize_image == (Image *) NULL)
+        {
+          resize_alpha=DestroyImage(resize_alpha);
+          return((Image *) NULL);
+        }
+
+      /* replace resize images alpha with the separally distorted alpha */
+      (void) SetImageAlphaChannel(resize_image,DeactivateAlphaChannel);
+      (void) SetImageAlphaChannel(resize_alpha,DeactivateAlphaChannel);
+      (void) CompositeImage(resize_image,CopyOpacityCompositeOp,resize_alpha,
+                    0,0);
+      InheritException(exception,&resize_image->exception);
+      resize_alpha=DestroyImage(resize_alpha);
+    }
+  (void) SetImageVirtualPixelMethod(resize_image,vp_save);
+
+  /*
+    Clean up the results of the Distortion
+  */
+  crop_area.width=columns;
+  crop_area.height=rows;
+  crop_area.x=0;
+  crop_area.y=0;
+
+  tmp_image=resize_image;
+  resize_image=CropImage(tmp_image,&crop_area,exception);
+  tmp_image=DestroyImage(tmp_image);
+
+  if ( resize_image == (Image *) NULL )
+    return((Image *) NULL);
+
+  return(resize_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D i s t o r t I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DistortImage() distorts an image using various distortion methods, by
+%  mapping color lookups of the source image to a new destination image
+%  usally of the same size as the source image, unless 'bestfit' is set to
+%  true.
+%
+%  If 'bestfit' is enabled, and distortion allows it, the destination image is
+%  adjusted to ensure the whole source 'image' will just fit within the final
+%  destination image, which will be sized and offset accordingly.  Also in
+%  many cases the virtual offset of the source image will be taken into
+%  account in the mapping.
+%
+%  If the '-verbose' control option has been set print to standard error the
+%  equicelent '-fx' formula with coefficients for the function, if practical.
+%
+%  The format of the DistortImage() method is:
+%
+%      Image *DistortImage(const Image *image,const DistortImageMethod method,
+%        const size_t number_arguments,const double *arguments,
+%        MagickBooleanType bestfit, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to be distorted.
+%
+%    o method: the method of image distortion.
+%
+%        ArcDistortion always ignores source image offset, and always
+%        'bestfit' the destination image with the top left corner offset
+%        relative to the polar mapping center.
+%
+%        Affine, Perspective, and Bilinear, do least squares fitting of the
+%        distrotion when more than the minimum number of control point pairs
+%        are provided.
+%
+%        Perspective, and Bilinear, fall back to a Affine distortion when less
+%        than 4 control point pairs are provided.  While Affine distortions
+%        let you use any number of control point pairs, that is Zero pairs is
+%        a No-Op (viewport only) distortion, one pair is a translation and
+%        two pairs of control points do a scale-rotate-translate, without any
+%        shearing.
+%
+%    o number_arguments: the number of arguments given.
+%
+%    o arguments: an array of floating point arguments for this method.
+%
+%    o bestfit: Attempt to 'bestfit' the size of the resulting image.
+%        This also forces the resulting image to be a 'layered' virtual
+%        canvas image.  Can be overridden using 'distort:viewport' setting.
+%
+%    o exception: return any errors or warnings in this structure
+%
+%  Extra Controls from Image meta-data (artifacts)...
+%
+%    o "verbose"
+%        Output to stderr alternatives, internal coefficents, and FX
+%        equivalents for the distortion operation (if feasible).
+%        This forms an extra check of the distortion method, and allows users
+%        access to the internal constants IM calculates for the distortion.
+%
+%    o "distort:viewport"
+%        Directly set the output image canvas area and offest to use for the
+%        resulting image, rather than use the original images canvas, or a
+%        calculated 'bestfit' canvas.
+%
+%    o "distort:scale"
+%        Scale the size of the output canvas by this amount to provide a
+%        method of Zooming, and for super-sampling the results.
+%
+%  Other settings that can effect results include
+%
+%    o 'interpolate' For source image lookups (scale enlargements)
+%
+%    o 'filter'      Set filter to use for area-resampling (scale shrinking).
+%                    Set to 'point' to turn off and use 'interpolate' lookup
+%                    instead
+%
+*/
+
+MagickExport Image *DistortImage(const Image *image,DistortImageMethod method,
+  const size_t number_arguments,const double *arguments,
+  MagickBooleanType bestfit,ExceptionInfo *exception)
+{
+#define DistortImageTag  "Distort/Image"
+
+  double
+    *coeff,
+    output_scaling;
+
+  Image
+    *distort_image;
+
+  RectangleInfo
+    geometry;  /* geometry of the distorted space viewport */
+
+  MagickBooleanType
+    viewport_given;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+
+  /*
+    Handle Special Compound Distortions
+  */
+  if ( method == ResizeDistortion )
+    {
+      if ( number_arguments != 2 )
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+                    "InvalidArgument","%s : '%s'","Resize",
+                    "Invalid number of args: 2 only");
+          return((Image *) NULL);
+        }
+      distort_image=DistortResizeImage(image,(size_t)arguments[0],
+         (size_t)arguments[1], exception);
+      return(distort_image);
+    }
+
+  /*
+    Convert input arguments (usually as control points for reverse mapping)
+    into mapping coefficients to apply the distortion.
+
+    Note that some distortions are mapped to other distortions,
+    and as such do not require specific code after this point.
+  */
+  coeff = GenerateCoefficients(image, &method, number_arguments,
+      arguments, 0, exception);
+  if ( coeff == (double *) NULL )
+    return((Image *) NULL);
+
+  /*
+    Determine the size and offset for a 'bestfit' destination.
+    Usally the four corners of the source image is enough.
+  */
+
+  /* default output image bounds, when no 'bestfit' is requested */
+  geometry.width=image->columns;
+  geometry.height=image->rows;
+  geometry.x=0;
+  geometry.y=0;
+
+  if ( method == ArcDistortion ) {
+    bestfit = MagickTrue;  /* always calculate a 'best fit' viewport */
+  }
+
+  /* Work out the 'best fit', (required for ArcDistortion) */
+  if ( bestfit ) {
+    PointInfo
+      s,d,min,max;  /* source, dest coords --mapping--> min, max coords */
+
+    MagickBooleanType
+      fix_bounds = MagickTrue;   /* enlarge bounds for VP handling */
+
+    s.x=s.y=min.x=max.x=min.y=max.y=0.0;   /* keep compiler happy */
+
+/* defines to figure out the bounds of the distorted image */
+#define InitalBounds(p) \
+{ \
+  /* printf("%lg,%lg -> %lg,%lg\n", s.x,s.y, d.x,d.y); */ \
+  min.x = max.x = p.x; \
+  min.y = max.y = p.y; \
+}
+#define ExpandBounds(p) \
+{ \
+  /* printf("%lg,%lg -> %lg,%lg\n", s.x,s.y, d.x,d.y); */ \
+  min.x = MagickMin(min.x,p.x); \
+  max.x = MagickMax(max.x,p.x); \
+  min.y = MagickMin(min.y,p.y); \
+  max.y = MagickMax(max.y,p.y); \
+}
+
+    switch (method)
+    {
+      case AffineDistortion:
+      { double inverse[6];
+        InvertAffineCoefficients(coeff, inverse);
+        s.x = (double) image->page.x;
+        s.y = (double) image->page.y;
+        d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
+        d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
+        InitalBounds(d);
+        s.x = (double) image->page.x+image->columns;
+        s.y = (double) image->page.y;
+        d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
+        d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
+        ExpandBounds(d);
+        s.x = (double) image->page.x;
+        s.y = (double) image->page.y+image->rows;
+        d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
+        d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
+        ExpandBounds(d);
+        s.x = (double) image->page.x+image->columns;
+        s.y = (double) image->page.y+image->rows;
+        d.x = inverse[0]*s.x+inverse[1]*s.y+inverse[2];
+        d.y = inverse[3]*s.x+inverse[4]*s.y+inverse[5];
+        ExpandBounds(d);
+        break;
+      }
+      case PerspectiveDistortion:
+      { double inverse[8], scale;
+        InvertPerspectiveCoefficients(coeff, inverse);
+        s.x = (double) image->page.x;
+        s.y = (double) image->page.y;
+        scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
+        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
+        d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
+        d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
+        InitalBounds(d);
+        s.x = (double) image->page.x+image->columns;
+        s.y = (double) image->page.y;
+        scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
+        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
+        d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
+        d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
+        ExpandBounds(d);
+        s.x = (double) image->page.x;
+        s.y = (double) image->page.y+image->rows;
+        scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
+        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
+        d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
+        d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
+        ExpandBounds(d);
+        s.x = (double) image->page.x+image->columns;
+        s.y = (double) image->page.y+image->rows;
+        scale=inverse[6]*s.x+inverse[7]*s.y+1.0;
+        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
+        d.x = scale*(inverse[0]*s.x+inverse[1]*s.y+inverse[2]);
+        d.y = scale*(inverse[3]*s.x+inverse[4]*s.y+inverse[5]);
+        ExpandBounds(d);
+        break;
+      }
+      case ArcDistortion:
+      { double a, ca, sa;
+        /* Forward Map Corners */
+        a = coeff[0]-coeff[1]/2; ca = cos(a); sa = sin(a);
+        d.x = coeff[2]*ca;
+        d.y = coeff[2]*sa;
+        InitalBounds(d);
+        d.x = (coeff[2]-coeff[3])*ca;
+        d.y = (coeff[2]-coeff[3])*sa;
+        ExpandBounds(d);
+        a = coeff[0]+coeff[1]/2; ca = cos(a); sa = sin(a);
+        d.x = coeff[2]*ca;
+        d.y = coeff[2]*sa;
+        ExpandBounds(d);
+        d.x = (coeff[2]-coeff[3])*ca;
+        d.y = (coeff[2]-coeff[3])*sa;
+        ExpandBounds(d);
+        /* Orthogonal points along top of arc */
+        for( a=(double) (ceil((double) ((coeff[0]-coeff[1]/2.0)/MagickPI2))*MagickPI2);
+               a<(coeff[0]+coeff[1]/2.0); a+=MagickPI2 ) {
+          ca = cos(a); sa = sin(a);
+          d.x = coeff[2]*ca;
+          d.y = coeff[2]*sa;
+          ExpandBounds(d);
+        }
+        /*
+          Convert the angle_to_width and radius_to_height
+          to appropriate scaling factors, to allow faster processing
+          in the mapping function.
+        */
+        coeff[1] = (double) (Magick2PI*image->columns/coeff[1]);
+        coeff[3] = (double)image->rows/coeff[3];
+        break;
+      }
+      case PolarDistortion:
+      {
+        if (number_arguments < 2)
+          coeff[2] = coeff[3] = 0.0;
+        min.x = coeff[2]-coeff[0];
+        max.x = coeff[2]+coeff[0];
+        min.y = coeff[3]-coeff[0];
+        max.y = coeff[3]+coeff[0];
+        /* should be about 1.0 if Rmin = 0 */
+        coeff[7]=(double) geometry.height/(coeff[0]-coeff[1]);
+        break;
+      }
+      case DePolarDistortion:
+      {
+        /* direct calculation as it needs to tile correctly
+         * for reversibility in a DePolar-Polar cycle */
+        fix_bounds = MagickFalse;
+        geometry.x = geometry.y = 0;
+        geometry.height = (size_t) ceil(coeff[0]-coeff[1]);
+        geometry.width = (size_t)
+                  ceil((coeff[0]-coeff[1])*(coeff[5]-coeff[4])*0.5);
+        /* correct scaling factors relative to new size */
+        coeff[6]=(coeff[5]-coeff[4])/geometry.width; /* changed width */
+        coeff[7]=(coeff[0]-coeff[1])/geometry.height; /* should be about 1.0 */
+        break;
+      }
+      case Cylinder2PlaneDistortion:
+      {
+        /* direct calculation so center of distortion is either a pixel
+         * center, or pixel edge. This allows for reversibility of the
+         * distortion */
+        geometry.x = geometry.y = 0;
+        geometry.width = (size_t) ceil( 2.0*coeff[1]*tan(coeff[0]/2.0) );
+        geometry.height = (size_t) ceil( 2.0*coeff[3]/cos(coeff[0]/2.0) );
+        /* correct center of distortion relative to new size */
+        coeff[4] = (double) geometry.width/2.0;
+        coeff[5] = (double) geometry.height/2.0;
+        fix_bounds = MagickFalse;
+        break;
+      }
+      case Plane2CylinderDistortion:
+      {
+        /* direct calculation center is either pixel center, or pixel edge
+         * so as to allow reversibility of the image distortion */
+        geometry.x = geometry.y = 0;
+        geometry.width = (size_t) ceil(coeff[0]*coeff[1]);  /* FOV * radius */
+        geometry.height = (size_t) (2*coeff[3]);              /* input image height */
+        /* correct center of distortion relative to new size */
+        coeff[4] = (double) geometry.width/2.0;
+        coeff[5] = (double) geometry.height/2.0;
+        fix_bounds = MagickFalse;
+        break;
+      }
+      case ShepardsDistortion:
+      case BilinearForwardDistortion:
+      case BilinearReverseDistortion:
+#if 0
+      case QuadrilateralDistortion:
+#endif
+      case PolynomialDistortion:
+      case BarrelDistortion:
+      case BarrelInverseDistortion:
+      default:
+        /* no calculated bestfit available for these distortions */
+        bestfit = MagickFalse;
+        fix_bounds = MagickFalse;
+        break;
+    }
+
+    /* Set the output image geometry to calculated 'bestfit'.
+       Yes this tends to 'over do' the file image size, ON PURPOSE!
+       Do not do this for DePolar which needs to be exact for virtual tiling.
+    */
+    if ( fix_bounds ) {
+      geometry.x = (ssize_t) floor(min.x-0.5);
+      geometry.y = (ssize_t) floor(min.y-0.5);
+      geometry.width=(size_t) ceil(max.x-geometry.x+0.5);
+      geometry.height=(size_t) ceil(max.y-geometry.y+0.5);
+    }
+
+  }  /* end bestfit destination image calculations */
+
+  /* The user provided a 'viewport' expert option which may
+     overrides some parts of the current output image geometry.
+     This also overrides its default 'bestfit' setting.
+  */
+  { const char *artifact=GetImageArtifact(image,"distort:viewport");
+    viewport_given = MagickFalse;
+    if ( artifact != (const char *) NULL ) {
+      (void) ParseAbsoluteGeometry(artifact,&geometry);
+      viewport_given = MagickTrue;
+    }
+  }
+
+  /* Verbose output */
+  if ( GetImageArtifact(image,"verbose") != (const char *) NULL ) {
+    register ssize_t
+       i;
+    char image_gen[MaxTextExtent];
+    const char *lookup;
+
+    /* Set destination image size and virtual offset */
+    if ( bestfit || viewport_given ) {
+      (void) FormatLocaleString(image_gen, MaxTextExtent,"  -size %.20gx%.20g "
+        "-page %+.20g%+.20g xc: +insert \\\n",(double) geometry.width,
+        (double) geometry.height,(double) geometry.x,(double) geometry.y);
+      lookup="v.p{ xx-v.page.x-.5, yy-v.page.y-.5 }";
+    }
+    else {
+      image_gen[0] = '\0';             /* no destination to generate */
+      lookup = "p{ xx-page.x-.5, yy-page.y-.5 }"; /* simplify lookup */
+    }
+
+    switch (method) {
+      case AffineDistortion:
+      {
+        double *inverse;
+
+        inverse = (double *) AcquireQuantumMemory(6,sizeof(*inverse));
+        if (inverse == (double *) NULL) {
+          coeff = (double *) RelinquishMagickMemory(coeff);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed",
+                  "%s", "DistortImages");
+          return((Image *) NULL);
+        }
+        InvertAffineCoefficients(coeff, inverse);
+        CoefficientsToAffineArgs(inverse);
+        (void) FormatLocaleFile(stderr, "Affine Projection:\n");
+        (void) FormatLocaleFile(stderr, "  -distort AffineProjection \\\n      '");
+        for (i=0; i < 5; i++)
+          (void) FormatLocaleFile(stderr, "%lf,", inverse[i]);
+        (void) FormatLocaleFile(stderr, "%lf'\n", inverse[5]);
+        inverse = (double *) RelinquishMagickMemory(inverse);
+
+        (void) FormatLocaleFile(stderr, "Affine Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        (void) FormatLocaleFile(stderr, "       xx=%+lf*ii %+lf*jj %+lf;\n",
+            coeff[0], coeff[1], coeff[2]);
+        (void) FormatLocaleFile(stderr, "       yy=%+lf*ii %+lf*jj %+lf;\n",
+            coeff[3], coeff[4], coeff[5]);
+        (void) FormatLocaleFile(stderr, "       %s' \\\n", lookup);
+
+        break;
+      }
+
+      case PerspectiveDistortion:
+      {
+        double *inverse;
+
+        inverse = (double *) AcquireQuantumMemory(8,sizeof(*inverse));
+        if (inverse == (double *) NULL) {
+          coeff = (double *) RelinquishMagickMemory(coeff);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed",
+                  "%s", "DistortCoefficients");
+          return((Image *) NULL);
+        }
+        InvertPerspectiveCoefficients(coeff, inverse);
+        (void) FormatLocaleFile(stderr, "Perspective Projection:\n");
+        (void) FormatLocaleFile(stderr, "  -distort PerspectiveProjection \\\n      '");
+        for (i=0; i<4; i++)
+          (void) FormatLocaleFile(stderr, "%lf, ", inverse[i]);
+        (void) FormatLocaleFile(stderr, "\n       ");
+        for (; i<7; i++)
+          (void) FormatLocaleFile(stderr, "%lf, ", inverse[i]);
+        (void) FormatLocaleFile(stderr, "%lf'\n", inverse[7]);
+        inverse = (double *) RelinquishMagickMemory(inverse);
+
+        (void) FormatLocaleFile(stderr, "Perspective Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        (void) FormatLocaleFile(stderr, "       rr=%+lf*ii %+lf*jj + 1;\n",
+            coeff[6], coeff[7]);
+        (void) FormatLocaleFile(stderr, "       xx=(%+lf*ii %+lf*jj %+lf)/rr;\n",
+            coeff[0], coeff[1], coeff[2]);
+        (void) FormatLocaleFile(stderr, "       yy=(%+lf*ii %+lf*jj %+lf)/rr;\n",
+            coeff[3], coeff[4], coeff[5]);
+        (void) FormatLocaleFile(stderr, "       rr%s0 ? %s : blue' \\\n",
+            coeff[8] < 0 ? "<" : ">", lookup);
+        break;
+      }
+
+      case BilinearForwardDistortion:
+        (void) FormatLocaleFile(stderr, "BilinearForward Mapping Equations:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "    i = %+lf*x %+lf*y %+lf*x*y %+lf;\n",
+            coeff[0], coeff[1], coeff[2], coeff[3]);
+        (void) FormatLocaleFile(stderr, "    j = %+lf*x %+lf*y %+lf*x*y %+lf;\n",
+            coeff[4], coeff[5], coeff[6], coeff[7]);
+#if 0
+        /* for debugging */
+        (void) FormatLocaleFile(stderr, "   c8 = %+lf  c9 = 2*a = %+lf;\n",
+            coeff[8], coeff[9]);
+#endif
+        (void) FormatLocaleFile(stderr, "BilinearForward Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
+            0.5-coeff[3], 0.5-coeff[7]);
+        (void) FormatLocaleFile(stderr, "       bb=%lf*ii %+lf*jj %+lf;\n",
+            coeff[6], -coeff[2], coeff[8]);
+        /* Handle Special degenerate (non-quadratic) or trapezoidal case */
+        if ( coeff[9] != 0 ) {
+          (void) FormatLocaleFile(stderr, "       rt=bb*bb %+lf*(%lf*ii%+lf*jj);\n",
+              -2*coeff[9],  coeff[4], -coeff[0]);
+          (void) FormatLocaleFile(stderr, "       yy=( -bb + sqrt(rt) ) / %lf;\n",
+               coeff[9]);
+        } else
+          (void) FormatLocaleFile(stderr, "       yy=(%lf*ii%+lf*jj)/bb;\n",
+                -coeff[4], coeff[0]);
+        (void) FormatLocaleFile(stderr, "       xx=(ii %+lf*yy)/(%lf %+lf*yy);\n",
+             -coeff[1], coeff[0], coeff[2]);
+        if ( coeff[9] != 0 )
+          (void) FormatLocaleFile(stderr, "       (rt < 0 ) ? red : %s'\n", lookup);
+        else
+          (void) FormatLocaleFile(stderr, "       %s' \\\n", lookup);
+        break;
+
+      case BilinearReverseDistortion:
+#if 0
+        (void) FormatLocaleFile(stderr, "Polynomial Projection Distort:\n");
+        (void) FormatLocaleFile(stderr, "  -distort PolynomialProjection \\\n");
+        (void) FormatLocaleFile(stderr, "      '1.5, %lf, %lf, %lf, %lf,\n",
+            coeff[3], coeff[0], coeff[1], coeff[2]);
+        (void) FormatLocaleFile(stderr, "            %lf, %lf, %lf, %lf'\n",
+            coeff[7], coeff[4], coeff[5], coeff[6]);
+#endif
+        (void) FormatLocaleFile(stderr, "BilinearReverse Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        (void) FormatLocaleFile(stderr, "       xx=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n",
+            coeff[0], coeff[1], coeff[2], coeff[3]);
+        (void) FormatLocaleFile(stderr, "       yy=%+lf*ii %+lf*jj %+lf*ii*jj %+lf;\n",
+            coeff[4], coeff[5], coeff[6], coeff[7]);
+        (void) FormatLocaleFile(stderr, "       %s' \\\n", lookup);
+        break;
+
+      case PolynomialDistortion:
+      {
+        size_t nterms = (size_t) coeff[1];
+        (void) FormatLocaleFile(stderr, "Polynomial (order %lg, terms %lu), FX Equivelent\n",
+          coeff[0],(unsigned long) nterms);
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x+0.5; jj=j+page.y+0.5;\n");
+        (void) FormatLocaleFile(stderr, "       xx =");
+        for (i=0; i<(ssize_t) nterms; i++) {
+          if ( i != 0 && i%4 == 0 ) (void) FormatLocaleFile(stderr, "\n         ");
+          (void) FormatLocaleFile(stderr, " %+lf%s", coeff[2+i],
+               poly_basis_str(i));
+        }
+        (void) FormatLocaleFile(stderr, ";\n       yy =");
+        for (i=0; i<(ssize_t) nterms; i++) {
+          if ( i != 0 && i%4 == 0 ) (void) FormatLocaleFile(stderr, "\n         ");
+          (void) FormatLocaleFile(stderr, " %+lf%s", coeff[2+i+nterms],
+               poly_basis_str(i));
+        }
+        (void) FormatLocaleFile(stderr, ";\n       %s' \\\n", lookup);
+        break;
+      }
+      case ArcDistortion:
+      {
+        (void) FormatLocaleFile(stderr, "Arc Distort, Internal Coefficients:\n");
+        for ( i=0; i<5; i++ )
+          (void) FormatLocaleFile(stderr, "  c%.20g = %+lf\n", (double) i, coeff[i]);
+        (void) FormatLocaleFile(stderr, "Arc Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x; jj=j+page.y;\n");
+        (void) FormatLocaleFile(stderr, "       xx=(atan2(jj,ii)%+lf)/(2*pi);\n",
+                                  -coeff[0]);
+        (void) FormatLocaleFile(stderr, "       xx=xx-round(xx);\n");
+        (void) FormatLocaleFile(stderr, "       xx=xx*%lf %+lf;\n",
+                            coeff[1], coeff[4]);
+        (void) FormatLocaleFile(stderr, "       yy=(%lf - hypot(ii,jj)) * %lf;\n",
+                            coeff[2], coeff[3]);
+        (void) FormatLocaleFile(stderr, "       v.p{xx-.5,yy-.5}' \\\n");
+        break;
+      }
+      case PolarDistortion:
+      {
+        (void) FormatLocaleFile(stderr, "Polar Distort, Internal Coefficents\n");
+        for ( i=0; i<8; i++ )
+          (void) FormatLocaleFile(stderr, "  c%.20g = %+lf\n", (double) i, coeff[i]);
+        (void) FormatLocaleFile(stderr, "Polar Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x%+lf; jj=j+page.y%+lf;\n",
+                         -coeff[2], -coeff[3]);
+        (void) FormatLocaleFile(stderr, "       xx=(atan2(ii,jj)%+lf)/(2*pi);\n",
+                         -(coeff[4]+coeff[5])/2 );
+        (void) FormatLocaleFile(stderr, "       xx=xx-round(xx);\n");
+        (void) FormatLocaleFile(stderr, "       xx=xx*2*pi*%lf + v.w/2;\n",
+                         coeff[6] );
+        (void) FormatLocaleFile(stderr, "       yy=(hypot(ii,jj)%+lf)*%lf;\n",
+                         -coeff[1], coeff[7] );
+        (void) FormatLocaleFile(stderr, "       v.p{xx-.5,yy-.5}' \\\n");
+        break;
+      }
+      case DePolarDistortion:
+      {
+        (void) FormatLocaleFile(stderr, "DePolar Distort, Internal Coefficents\n");
+        for ( i=0; i<8; i++ )
+          (void) FormatLocaleFile(stderr, "  c%.20g = %+lf\n", (double) i, coeff[i]);
+        (void) FormatLocaleFile(stderr, "DePolar Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'aa=(i+.5)*%lf %+lf;\n", coeff[6], -coeff[4] );
+        (void) FormatLocaleFile(stderr, "       rr=(j+.5)*%lf %+lf;\n", coeff[7], +coeff[1] );
+        (void) FormatLocaleFile(stderr, "       xx=rr*sin(aa) %+lf;\n", coeff[2] );
+        (void) FormatLocaleFile(stderr, "       yy=rr*cos(aa) %+lf;\n", coeff[3] );
+        (void) FormatLocaleFile(stderr, "       v.p{xx-.5,yy-.5}' \\\n");
+        break;
+      }
+      case Cylinder2PlaneDistortion:
+      {
+        (void) FormatLocaleFile(stderr, "Cylinder to Plane Distort, Internal Coefficents\n");
+        (void) FormatLocaleFile(stderr, "  cylinder_radius = %+lf\n", coeff[1]);
+        (void) FormatLocaleFile(stderr, "Cylinder to Plane Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x%+lf+0.5; jj=j+page.y%+lf+0.5;\n",
+                         -coeff[4], -coeff[5]);
+        (void) FormatLocaleFile(stderr, "       aa=atan(ii/%+lf);\n", coeff[1] );
+        (void) FormatLocaleFile(stderr, "       xx=%lf*aa%+lf;\n",
+                         coeff[1], coeff[2] );
+        (void) FormatLocaleFile(stderr, "       yy=jj*cos(aa)%+lf;\n", coeff[3] );
+        (void) FormatLocaleFile(stderr, "       %s' \\\n", lookup);
+        break;
+      }
+      case Plane2CylinderDistortion:
+      {
+        (void) FormatLocaleFile(stderr, "Plane to Cylinder Distort, Internal Coefficents\n");
+        (void) FormatLocaleFile(stderr, "  cylinder_radius = %+lf\n", coeff[1]);
+        (void) FormatLocaleFile(stderr, "Plane to Cylinder Distort, FX Equivelent:\n");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        (void) FormatLocaleFile(stderr, "  -fx 'ii=i+page.x%+lf+0.5; jj=j+page.y%+lf+0.5;\n",
+                         -coeff[4], -coeff[5]);
+        (void) FormatLocaleFile(stderr, "       ii=ii/%+lf;\n", coeff[1] );
+        (void) FormatLocaleFile(stderr, "       xx=%lf*tan(ii)%+lf;\n",
+                         coeff[1], coeff[2] );
+        (void) FormatLocaleFile(stderr, "       yy=jj/cos(ii)%+lf;\n",
+                         coeff[3] );
+        (void) FormatLocaleFile(stderr, "       %s' \\\n", lookup);
+        break;
+      }
+      case BarrelDistortion:
+      case BarrelInverseDistortion:
+      { double xc,yc;
+        /* NOTE: This does the barrel roll in pixel coords not image coords
+        ** The internal distortion must do it in image coordinates,
+        ** so that is what the center coeff (8,9) is given in.
+        */
+        xc = ((double)image->columns-1.0)/2.0 + image->page.x;
+        yc = ((double)image->rows-1.0)/2.0    + image->page.y;
+        (void) FormatLocaleFile(stderr, "Barrel%s Distort, FX Equivelent:\n",
+             method == BarrelDistortion ? "" : "Inv");
+        (void) FormatLocaleFile(stderr, "%s", image_gen);
+        if ( fabs(coeff[8]-xc-0.5) < 0.1 && fabs(coeff[9]-yc-0.5) < 0.1 )
+          (void) FormatLocaleFile(stderr, "  -fx 'xc=(w-1)/2;  yc=(h-1)/2;\n");
+        else
+          (void) FormatLocaleFile(stderr, "  -fx 'xc=%lf;  yc=%lf;\n",
+               coeff[8]-0.5, coeff[9]-0.5);
+        (void) FormatLocaleFile(stderr,
+             "       ii=i-xc;  jj=j-yc;  rr=hypot(ii,jj);\n");
+        (void) FormatLocaleFile(stderr, "       ii=ii%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n",
+             method == BarrelDistortion ? "*" : "/",
+             coeff[0],coeff[1],coeff[2],coeff[3]);
+        (void) FormatLocaleFile(stderr, "       jj=jj%s(%lf*rr*rr*rr %+lf*rr*rr %+lf*rr %+lf);\n",
+             method == BarrelDistortion ? "*" : "/",
+             coeff[4],coeff[5],coeff[6],coeff[7]);
+        (void) FormatLocaleFile(stderr, "       v.p{fx*ii+xc,fy*jj+yc}' \\\n");
+      }
+      default:
+        break;
+    }
+  }
+
+  /* The user provided a 'scale' expert option will scale the
+     output image size, by the factor given allowing for super-sampling
+     of the distorted image space.  Any scaling factors must naturally
+     be halved as a result.
+  */
+  { const char *artifact;
+    artifact=GetImageArtifact(image,"distort:scale");
+    output_scaling = 1.0;
+    if (artifact != (const char *) NULL) {
+      output_scaling = fabs(InterpretLocaleValue(artifact,(char **) NULL));
+      geometry.width  *= output_scaling;
+      geometry.height *= output_scaling;
+      geometry.x      *= output_scaling;
+      geometry.y      *= output_scaling;
+      if ( output_scaling < 0.1 ) {
+        coeff = (double *) RelinquishMagickMemory(coeff);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+                "InvalidArgument","%s", "-set option:distort:scale" );
+        return((Image *) NULL);
+      }
+      output_scaling = 1/output_scaling;
+    }
+  }
+#define ScaleFilter(F,A,B,C,D) \
+    ScaleResampleFilter( (F), \
+      output_scaling*(A), output_scaling*(B), \
+      output_scaling*(C), output_scaling*(D) )
+
+  /*
+    Initialize the distort image attributes.
+  */
+  distort_image=CloneImage(image,geometry.width,geometry.height,MagickTrue,
+    exception);
+  if (distort_image == (Image *) NULL)
+    return((Image *) NULL);
+  /* if image is ColorMapped - change it to DirectClass */
+  if (SetImageStorageClass(distort_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&distort_image->exception);
+      distort_image=DestroyImage(distort_image);
+      return((Image *) NULL);
+    }
+  distort_image->page.x=geometry.x;
+  distort_image->page.y=geometry.y;
+  if (distort_image->background_color.alpha != OpaqueAlpha)
+    distort_image->matte=MagickTrue;
+
+  { /* ----- MAIN CODE -----
+       Sample the source image to each pixel in the distort image.
+     */
+    CacheView
+      *distort_view;
+
+    MagickBooleanType
+      status;
+
+    MagickOffsetType
+      progress;
+
+    PixelInfo
+      zero;
+
+    ResampleFilter
+      **restrict resample_filter;
+
+    ssize_t
+      j;
+
+    status=MagickTrue;
+    progress=0;
+    GetPixelInfo(distort_image,&zero);
+    resample_filter=AcquireResampleFilterThreadSet(image,
+      UndefinedVirtualPixelMethod,MagickFalse,exception);
+    distort_view=AcquireCacheView(distort_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (j=0; j < (ssize_t) distort_image->rows; j++)
+    {
+      const int
+        id = GetOpenMPThreadId();
+
+      double
+        validity;  /* how mathematically valid is this the mapping */
+
+      MagickBooleanType
+        sync;
+
+      PixelInfo
+        pixel,    /* pixel color to assign to distorted image */
+        invalid;  /* the color to assign when distort result is invalid */
+
+      PointInfo
+        d,
+        s;  /* transform destination image x,y  to source image x,y */
+
+      register ssize_t
+        i;
+
+      register Quantum
+        *restrict q;
+
+      q=QueueCacheViewAuthenticPixels(distort_view,0,j,distort_image->columns,1,
+        exception);
+      if (q == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      pixel=zero;
+
+      /* Define constant scaling vectors for Affine Distortions
+        Other methods are either variable, or use interpolated lookup
+      */
+      switch (method)
+      {
+        case AffineDistortion:
+          ScaleFilter( resample_filter[id],
+            coeff[0], coeff[1],
+            coeff[3], coeff[4] );
+          break;
+        default:
+          break;
+      }
+
+      /* Initialize default pixel validity
+      *    negative:         pixel is invalid  output 'matte_color'
+      *    0.0 to 1.0:       antialiased, mix with resample output
+      *    1.0 or greater:   use resampled output.
+      */
+      validity = 1.0;
+
+      GetPixelInfo(distort_image,&invalid);
+      SetPixelInfoPacket(distort_image,&distort_image->matte_color,&invalid);
+      if (distort_image->colorspace == CMYKColorspace)
+        ConvertRGBToCMYK(&invalid);   /* what about other color spaces? */
+
+      for (i=0; i < (ssize_t) distort_image->columns; i++)
+      {
+        /* map pixel coordinate to distortion space coordinate */
+        d.x = (double) (geometry.x+i+0.5)*output_scaling;
+        d.y = (double) (geometry.y+j+0.5)*output_scaling;
+        s = d;  /* default is a no-op mapping */
+        switch (method)
+        {
+          case AffineDistortion:
+          {
+            s.x=coeff[0]*d.x+coeff[1]*d.y+coeff[2];
+            s.y=coeff[3]*d.x+coeff[4]*d.y+coeff[5];
+            /* Affine partial derivitives are constant -- set above */
+            break;
+          }
+          case PerspectiveDistortion:
+          {
+            double
+              p,q,r,abs_r,abs_c6,abs_c7,scale;
+            /* perspective is a ratio of affines */
+            p=coeff[0]*d.x+coeff[1]*d.y+coeff[2];
+            q=coeff[3]*d.x+coeff[4]*d.y+coeff[5];
+            r=coeff[6]*d.x+coeff[7]*d.y+1.0;
+            /* Pixel Validity -- is it a 'sky' or 'ground' pixel */
+            validity = (r*coeff[8] < 0.0) ? 0.0 : 1.0;
+            /* Determine horizon anti-alias blending */
+            abs_r = fabs(r)*2;
+            abs_c6 = fabs(coeff[6]);
+            abs_c7 = fabs(coeff[7]);
+            if ( abs_c6 > abs_c7 ) {
+              if ( abs_r < abs_c6*output_scaling )
+                validity = 0.5 - coeff[8]*r/(coeff[6]*output_scaling);
+            }
+            else if ( abs_r < abs_c7*output_scaling )
+              validity = 0.5 - coeff[8]*r/(coeff[7]*output_scaling);
+            /* Perspective Sampling Point (if valid) */
+            if ( validity > 0.0 ) {
+              /* divide by r affine, for perspective scaling */
+              scale = 1.0/r;
+              s.x = p*scale;
+              s.y = q*scale;
+              /* Perspective Partial Derivatives or Scaling Vectors */
+              scale *= scale;
+              ScaleFilter( resample_filter[id],
+                (r*coeff[0] - p*coeff[6])*scale,
+                (r*coeff[1] - p*coeff[7])*scale,
+                (r*coeff[3] - q*coeff[6])*scale,
+                (r*coeff[4] - q*coeff[7])*scale );
+            }
+            break;
+          }
+          case BilinearReverseDistortion:
+          {
+            /* Reversed Mapped is just a simple polynomial */
+            s.x=coeff[0]*d.x+coeff[1]*d.y+coeff[2]*d.x*d.y+coeff[3];
+            s.y=coeff[4]*d.x+coeff[5]*d.y
+                    +coeff[6]*d.x*d.y+coeff[7];
+            /* Bilinear partial derivitives of scaling vectors */
+            ScaleFilter( resample_filter[id],
+                coeff[0] + coeff[2]*d.y,
+                coeff[1] + coeff[2]*d.x,
+                coeff[4] + coeff[6]*d.y,
+                coeff[5] + coeff[6]*d.x );
+            break;
+          }
+          case BilinearForwardDistortion:
+          {
+            /* Forward mapped needs reversed polynomial equations
+             * which unfortunatally requires a square root!  */
+            double b,c;
+            d.x -= coeff[3];  d.y -= coeff[7];
+            b = coeff[6]*d.x - coeff[2]*d.y + coeff[8];
+            c = coeff[4]*d.x - coeff[0]*d.y;
+
+            validity = 1.0;
+            /* Handle Special degenerate (non-quadratic) case
+             * Currently without horizon anti-alising */
+            if ( fabs(coeff[9]) < MagickEpsilon )
+              s.y =  -c/b;
+            else {
+              c = b*b - 2*coeff[9]*c;
+              if ( c < 0.0 )
+                validity = 0.0;
+              else
+                s.y = ( -b + sqrt(c) )/coeff[9];
+            }
+            if ( validity > 0.0 )
+              s.x = ( d.x - coeff[1]*s.y) / ( coeff[0] + coeff[2]*s.y );
+
+            /* NOTE: the sign of the square root should be -ve for parts
+                     where the source image becomes 'flipped' or 'mirrored'.
+               FUTURE: Horizon handling
+               FUTURE: Scaling factors or Deritives (how?)
+            */
+            break;
+          }
+#if 0
+          case BilinearDistortion:
+            /* Bilinear mapping of any Quadrilateral to any Quadrilateral */
+            /* UNDER DEVELOPMENT */
+            break;
+#endif
+          case PolynomialDistortion:
+          {
+            /* multi-ordered polynomial */
+            register ssize_t
+              k;
+
+            ssize_t
+              nterms=(ssize_t)coeff[1];
+
+            PointInfo
+              du,dv; /* the du,dv vectors from unit dx,dy -- derivatives */
+
+            s.x=s.y=du.x=du.y=dv.x=dv.y=0.0;
+            for(k=0; k < nterms; k++) {
+              s.x  += poly_basis_fn(k,d.x,d.y)*coeff[2+k];
+              du.x += poly_basis_dx(k,d.x,d.y)*coeff[2+k];
+              du.y += poly_basis_dy(k,d.x,d.y)*coeff[2+k];
+              s.y  += poly_basis_fn(k,d.x,d.y)*coeff[2+k+nterms];
+              dv.x += poly_basis_dx(k,d.x,d.y)*coeff[2+k+nterms];
+              dv.y += poly_basis_dy(k,d.x,d.y)*coeff[2+k+nterms];
+            }
+            ScaleFilter( resample_filter[id], du.x,du.y,dv.x,dv.y );
+            break;
+          }
+          case ArcDistortion:
+          {
+            /* what is the angle and radius in the destination image */
+            s.x  = (double) ((atan2(d.y,d.x) - coeff[0])/Magick2PI);
+            s.x -= MagickRound(s.x);     /* angle */
+            s.y  = hypot(d.x,d.y);       /* radius */
+
+            /* Arc Distortion Partial Scaling Vectors
+              Are derived by mapping the perpendicular unit vectors
+              dR  and  dA*R*2PI  rather than trying to map dx and dy
+              The results is a very simple orthogonal aligned ellipse.
+            */
+            if ( s.y > MagickEpsilon )
+              ScaleFilter( resample_filter[id],
+                  (double) (coeff[1]/(Magick2PI*s.y)), 0, 0, coeff[3] );
+            else
+              ScaleFilter( resample_filter[id],
+                  distort_image->columns*2, 0, 0, coeff[3] );
+
+            /* now scale the angle and radius for source image lookup point */
+            s.x = s.x*coeff[1] + coeff[4] + image->page.x +0.5;
+            s.y = (coeff[2] - s.y) * coeff[3] + image->page.y;
+            break;
+          }
+          case PolarDistortion:
+          { /* 2D Cartesain to Polar View */
+            d.x -= coeff[2];
+            d.y -= coeff[3];
+            s.x  = atan2(d.x,d.y) - (coeff[4]+coeff[5])/2;
+            s.x /= Magick2PI;
+            s.x -= MagickRound(s.x);
+            s.x *= Magick2PI;       /* angle - relative to centerline */
+            s.y  = hypot(d.x,d.y);  /* radius */
+
+            /* Polar Scaling vectors are based on mapping dR and dA vectors
+               This results in very simple orthogonal scaling vectors
+            */
+            if ( s.y > MagickEpsilon )
+              ScaleFilter( resample_filter[id],
+                (double) (coeff[6]/(Magick2PI*s.y)), 0, 0, coeff[7] );
+            else
+              ScaleFilter( resample_filter[id],
+                  distort_image->columns*2, 0, 0, coeff[7] );
+
+            /* now finish mapping radius/angle to source x,y coords */
+            s.x = s.x*coeff[6] + (double)image->columns/2.0 + image->page.x;
+            s.y = (s.y-coeff[1])*coeff[7] + image->page.y;
+            break;
+          }
+          case DePolarDistortion:
+          { /* @D Polar to Carteasain  */
+            /* ignore all destination virtual offsets */
+            d.x = ((double)i+0.5)*output_scaling*coeff[6]-coeff[4];
+            d.y = ((double)j+0.5)*output_scaling*coeff[7]+coeff[1];
+            s.x = d.y*sin(d.x) + coeff[2];
+            s.y = d.y*cos(d.x) + coeff[3];
+            /* derivatives are usless - better to use SuperSampling */
+            break;
+          }
+          case Cylinder2PlaneDistortion:
+          { /* 3D Cylinder to Tangential Plane */
+            double ax, cx;
+            /* relative to center of distortion */
+            d.x -= coeff[4]; d.y -= coeff[5];
+            d.x /= coeff[1];        /* x' = x/r */
+            ax=atan(d.x);           /* aa = atan(x/r) = u/r  */
+            cx=cos(ax);             /* cx = cos(atan(x/r)) = 1/sqrt(x^2+u^2) */
+            s.x = coeff[1]*ax;      /* u  = r*atan(x/r) */
+            s.y = d.y*cx;           /* v  = y*cos(u/r) */
+            /* derivatives... (see personnal notes) */
+            ScaleFilter( resample_filter[id],
+                  1.0/(1.0+d.x*d.x), 0.0, -d.x*s.y*cx*cx/coeff[1], s.y/d.y );
+#if 0
+if ( i == 0 && j == 0 ) {
+  fprintf(stderr, "x=%lf  y=%lf  u=%lf  v=%lf\n", d.x*coeff[1], d.y, s.x, s.y);
+  fprintf(stderr, "phi = %lf\n", (double)(ax * 180.0/MagickPI) );
+  fprintf(stderr, "du/dx=%lf  du/dx=%lf  dv/dx=%lf  dv/dy=%lf\n",
+                1.0/(1.0+d.x*d.x), 0.0, -d.x*s.y*cx*cx/coeff[1], s.y/d.y );
+  fflush(stderr); }
+#endif
+            /* add center of distortion in source */
+            s.x += coeff[2]; s.y += coeff[3];
+            break;
+          }
+          case Plane2CylinderDistortion:
+          { /* 3D Cylinder to Tangential Plane */
+            /* relative to center of distortion */
+            d.x -= coeff[4]; d.y -= coeff[5];
+
+            /* is pixel valid - horizon of a infinite Virtual-Pixel Plane
+             * (see Anthony Thyssen's personal note) */
+            validity = (double) (coeff[1]*MagickPI2 - fabs(d.x))/output_scaling + 0.5;
+
+            if ( validity > 0.0 ) {
+              double cx,tx;
+              d.x /= coeff[1];           /* x'= x/r */
+              cx = 1/cos(d.x);           /* cx = 1/cos(x/r) */
+              tx = tan(d.x);             /* tx = tan(x/r) */
+              s.x = coeff[1]*tx;         /* u = r * tan(x/r) */
+              s.y = d.y*cx;              /* v = y / cos(x/r) */
+              /* derivatives...  (see Anthony Thyssen's personal notes) */
+              ScaleFilter( resample_filter[id],
+                    cx*cx, 0.0, s.y*cx/coeff[1], cx );
+#if 1
+/*if ( i == 0 && j == 0 )*/
+if ( d.x == 0.5 && d.y == 0.5 ) {
+  fprintf(stderr, "x=%lf  y=%lf  u=%lf  v=%lf\n", d.x*coeff[1], d.y, s.x, s.y);
+  fprintf(stderr, "radius = %lf  phi = %lf  validity = %lf\n",
+      coeff[1],  (double)(d.x * 180.0/MagickPI), validity );
+  fprintf(stderr, "du/dx=%lf  du/dx=%lf  dv/dx=%lf  dv/dy=%lf\n",
+      cx*cx, 0.0, s.y*cx/coeff[1], cx);
+  fflush(stderr); }
+#endif
+            }
+            /* add center of distortion in source */
+            s.x += coeff[2]; s.y += coeff[3];
+            break;
+          }
+          case BarrelDistortion:
+          case BarrelInverseDistortion:
+          { /* Lens Barrel Distionion Correction */
+            double r,fx,fy,gx,gy;
+            /* Radial Polynomial Distortion (de-normalized) */
+            d.x -= coeff[8];
+            d.y -= coeff[9];
+            r = sqrt(d.x*d.x+d.y*d.y);
+            if ( r > MagickEpsilon ) {
+              fx = ((coeff[0]*r + coeff[1])*r + coeff[2])*r + coeff[3];
+              fy = ((coeff[4]*r + coeff[5])*r + coeff[6])*r + coeff[7];
+              gx = ((3*coeff[0]*r + 2*coeff[1])*r + coeff[2])/r;
+              gy = ((3*coeff[4]*r + 2*coeff[5])*r + coeff[6])/r;
+              /* adjust functions and scaling for 'inverse' form */
+              if ( method == BarrelInverseDistortion ) {
+                fx = 1/fx;  fy = 1/fy;
+                gx *= -fx*fx;  gy *= -fy*fy;
+              }
+              /* Set the source pixel to lookup and EWA derivative vectors */
+              s.x = d.x*fx + coeff[8];
+              s.y = d.y*fy + coeff[9];
+              ScaleFilter( resample_filter[id],
+                  gx*d.x*d.x + fx, gx*d.x*d.y,
+                  gy*d.x*d.y,      gy*d.y*d.y + fy );
+            }
+            else {
+              /* Special handling to avoid divide by zero when r==0
+              **
+              ** The source and destination pixels match in this case
+              ** which was set at the top of the loop using  s = d;
+              ** otherwise...   s.x=coeff[8]; s.y=coeff[9];
+              */
+              if ( method == BarrelDistortion )
+                ScaleFilter( resample_filter[id],
+                     coeff[3], 0, 0, coeff[7] );
+              else /* method == BarrelInverseDistortion */
+                /* FUTURE, trap for D==0 causing division by zero */
+                ScaleFilter( resample_filter[id],
+                     1.0/coeff[3], 0, 0, 1.0/coeff[7] );
+            }
+            break;
+          }
+          case ShepardsDistortion:
+          { /* Shepards Method, or Inverse Weighted Distance for
+              displacement around the destination image control points
+              The input arguments are the coefficents to the function.
+              This is more of a 'displacement' function rather than an
+              absolute distortion function.
+            */
+            size_t
+              i;
+            double
+              denominator;
+
+            denominator = s.x = s.y = 0;
+            for(i=0; i<number_arguments; i+=4) {
+              double weight =
+                  ((double)d.x-arguments[i+2])*((double)d.x-arguments[i+2])
+                + ((double)d.y-arguments[i+3])*((double)d.y-arguments[i+3]);
+              if ( weight != 0 )
+                weight = 1/weight;
+              else
+                weight = 1;
+
+              s.x += (arguments[ i ]-arguments[i+2])*weight;
+              s.y += (arguments[i+1]-arguments[i+3])*weight;
+              denominator += weight;
+            }
+            s.x /= denominator;
+            s.y /= denominator;
+            s.x += d.x;
+            s.y += d.y;
+
+            /* We can not determine derivatives using shepards method
+               only color interpolatation, not area-resampling */
+            break;
+          }
+          default:
+            break; /* use the default no-op given above */
+        }
+        /* map virtual canvas location back to real image coordinate */
+        if ( bestfit && method != ArcDistortion ) {
+          s.x -= image->page.x;
+          s.y -= image->page.y;
+        }
+        s.x -= 0.5;
+        s.y -= 0.5;
+
+        if ( validity <= 0.0 ) {
+          /* result of distortion is an invalid pixel - don't resample */
+          SetPixelPixelInfo(distort_image,&invalid,q);
+        }
+        else {
+          /* resample the source image to find its correct color */
+          (void) ResamplePixelColor(resample_filter[id],s.x,s.y,&pixel);
+          /* if validity between 0.0 and 1.0 mix result with invalid pixel */
+          if ( validity < 1.0 ) {
+            /* Do a blend of sample color and invalid pixel */
+            /* should this be a 'Blend', or an 'Over' compose */
+            CompositePixelInfoBlend(&pixel,validity,&invalid,(1.0-validity),
+              &pixel);
+          }
+          SetPixelPixelInfo(distort_image,&pixel,q);
+        }
+        q+=GetPixelChannels(distort_image);
+      }
+      sync=SyncCacheViewAuthenticPixels(distort_view,exception);
+      if (sync == MagickFalse)
+        status=MagickFalse;
+      if (image->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_DistortImage)
+#endif
+          proceed=SetImageProgress(image,DistortImageTag,progress++,
+            image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+    }
+    distort_view=DestroyCacheView(distort_view);
+    resample_filter=DestroyResampleFilterThreadSet(resample_filter);
+
+    if (status == MagickFalse)
+      distort_image=DestroyImage(distort_image);
+  }
+
+  /* Arc does not return an offset unless 'bestfit' is in effect
+     And the user has not provided an overriding 'viewport'.
+   */
+  if ( method == ArcDistortion && !bestfit && !viewport_given ) {
+    distort_image->page.x = 0;
+    distort_image->page.y = 0;
+  }
+  coeff = (double *) RelinquishMagickMemory(coeff);
+  return(distort_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p a r s e C o l o r I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SparseColorImage(), given a set of coordinates, interpolates the colors
+%  found at those coordinates, across the whole image, using various methods.
+%
+%  The format of the SparseColorImage() method is:
+%
+%      Image *SparseColorImage(const Image *image,const ChannelType channel,
+%        const SparseColorMethod method,const size_t number_arguments,
+%        const double *arguments,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to be filled in.
+%
+%    o channel: Specify which color values (in RGBKA sequence) are being set.
+%        This also determines the number of color_values in above.
+%
+%    o method: the method to fill in the gradient between the control points.
+%
+%        The methods used for SparseColor() are often simular to methods
+%        used for DistortImage(), and even share the same code for determination
+%        of the function coefficents, though with more dimensions (or resulting
+%        values).
+%
+%    o number_arguments: the number of arguments given.
+%
+%    o arguments: array of floating point arguments for this method--
+%        x,y,color_values-- with color_values given as normalized values.
+%
+%    o exception: return any errors or warnings in this structure
+%
+*/
+MagickExport Image *SparseColorImage(const Image *image,
+  const ChannelType channel,const SparseColorMethod method,
+  const size_t number_arguments,const double *arguments,
+  ExceptionInfo *exception)
+{
+#define SparseColorTag  "Distort/SparseColor"
+
+  SparseColorMethod
+    sparse_method;
+
+  double
+    *coeff;
+
+  Image
+    *sparse_image;
+
+  size_t
+    number_colors;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  /* Determine number of color values needed per control point */
+  number_colors=0;
+  if ( channel & RedChannel     ) number_colors++;
+  if ( channel & GreenChannel   ) number_colors++;
+  if ( channel & BlueChannel    ) number_colors++;
+  if ( channel & AlphaChannel ) number_colors++;
+  if ( channel & BlackChannel   ) number_colors++;
+
+  /*
+    Convert input arguments into mapping coefficients, this this case
+    we are mapping (distorting) colors, rather than coordinates.
+  */
+  { DistortImageMethod
+      distort_method;
+
+    distort_method=(DistortImageMethod) method;
+    if ( distort_method >= SentinelDistortion )
+      distort_method = ShepardsDistortion; /* Pretend to be Shepards */
+    coeff = GenerateCoefficients(image, &distort_method, number_arguments,
+                arguments, number_colors, exception);
+    if ( coeff == (double *) NULL )
+      return((Image *) NULL);
+    /*
+      Note some Distort Methods may fall back to other simpler methods,
+      Currently the only fallback of concern is Bilinear to Affine
+      (Barycentric), which is alaso sparse_colr method.  This also ensures
+      correct two and one color Barycentric handling.
+    */
+    sparse_method = (SparseColorMethod) distort_method;
+    if ( distort_method == ShepardsDistortion )
+      sparse_method = method;   /* return non-distiort methods to normal */
+  }
+
+  /* Verbose output */
+  if ( GetImageArtifact(image,"verbose") != (const char *) NULL ) {
+
+    switch (sparse_method) {
+      case BarycentricColorInterpolate:
+      {
+        register ssize_t x=0;
+        (void) FormatLocaleFile(stderr, "Barycentric Sparse Color:\n");
+        if ( channel & RedChannel )
+          (void) FormatLocaleFile(stderr, "  -channel R -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & GreenChannel )
+          (void) FormatLocaleFile(stderr, "  -channel G -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & BlueChannel )
+          (void) FormatLocaleFile(stderr, "  -channel B -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & BlackChannel )
+          (void) FormatLocaleFile(stderr, "  -channel K -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        if ( channel & AlphaChannel )
+          (void) FormatLocaleFile(stderr, "  -channel A -fx '%+lf*i %+lf*j %+lf' \\\n",
+              coeff[x], coeff[x+1], coeff[x+2]),x+=3;
+        break;
+      }
+      case BilinearColorInterpolate:
+      {
+        register ssize_t x=0;
+        (void) FormatLocaleFile(stderr, "Bilinear Sparse Color\n");
+        if ( channel & RedChannel )
+          (void) FormatLocaleFile(stderr, "   -channel R -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
+              coeff[ x ], coeff[x+1],
+              coeff[x+2], coeff[x+3]),x+=4;
+        if ( channel & GreenChannel )
+          (void) FormatLocaleFile(stderr, "   -channel G -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
+              coeff[ x ], coeff[x+1],
+              coeff[x+2], coeff[x+3]),x+=4;
+        if ( channel & BlueChannel )
+          (void) FormatLocaleFile(stderr, "   -channel B -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
+              coeff[ x ], coeff[x+1],
+              coeff[x+2], coeff[x+3]),x+=4;
+        if ( channel & BlackChannel )
+          (void) FormatLocaleFile(stderr, "   -channel K -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
+              coeff[ x ], coeff[x+1],
+              coeff[x+2], coeff[x+3]),x+=4;
+        if ( channel & AlphaChannel )
+          (void) FormatLocaleFile(stderr, "   -channel A -fx '%+lf*i %+lf*j %+lf*i*j %+lf;\n",
+              coeff[ x ], coeff[x+1],
+              coeff[x+2], coeff[x+3]),x+=4;
+        break;
+      }
+      default:
+        /* sparse color method is too complex for FX emulation */
+        break;
+    }
+  }
+
+  /* Generate new image for generated interpolated gradient.
+   * ASIDE: Actually we could have just replaced the colors of the original
+   * image, but IM Core policy, is if storage class could change then clone
+   * the image.
+   */
+
+  sparse_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (sparse_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(sparse_image,DirectClass) == MagickFalse)
+    { /* if image is ColorMapped - change it to DirectClass */
+      InheritException(exception,&image->exception);
+      sparse_image=DestroyImage(sparse_image);
+      return((Image *) NULL);
+    }
+  { /* ----- MAIN CODE ----- */
+    CacheView
+      *sparse_view;
+
+    MagickBooleanType
+      status;
+
+    MagickOffsetType
+      progress;
+
+    ssize_t
+      j;
+
+    status=MagickTrue;
+    progress=0;
+    sparse_view=AcquireCacheView(sparse_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (j=0; j < (ssize_t) sparse_image->rows; j++)
+    {
+      MagickBooleanType
+        sync;
+
+      PixelInfo
+        pixel;    /* pixel to assign to distorted image */
+
+      register ssize_t
+        i;
+
+      register Quantum
+        *restrict q;
+
+      q=GetCacheViewAuthenticPixels(sparse_view,0,j,sparse_image->columns,
+        1,exception);
+      if (q == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      GetPixelInfo(sparse_image,&pixel);
+      for (i=0; i < (ssize_t) image->columns; i++)
+      {
+        SetPixelInfo(image,q,&pixel);
+        switch (sparse_method)
+        {
+          case BarycentricColorInterpolate:
+          {
+            register ssize_t x=0;
+            if ( channel & RedChannel )
+              pixel.red     = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            if ( channel & GreenChannel )
+              pixel.green   = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            if ( channel & BlueChannel )
+              pixel.blue    = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            if ( channel & AlphaChannel )
+              pixel.alpha = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            if ( channel & BlackChannel )
+              pixel.black   = coeff[x]*i +coeff[x+1]*j
+                              +coeff[x+2], x+=3;
+            break;
+          }
+          case BilinearColorInterpolate:
+          {
+            register ssize_t x=0;
+            if ( channel & RedChannel )
+              pixel.red     = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            if ( channel & GreenChannel )
+              pixel.green   = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            if ( channel & BlueChannel )
+              pixel.blue    = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            if ( channel & AlphaChannel )
+              pixel.alpha = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            if ( channel & BlackChannel )
+              pixel.black   = coeff[x]*i     + coeff[x+1]*j +
+                              coeff[x+2]*i*j + coeff[x+3], x+=4;
+            break;
+          }
+          case InverseColorInterpolate:
+          case ShepardsColorInterpolate:
+          { /* Inverse (Squared) Distance weights average (IDW) */
+            size_t
+              k;
+            double
+              denominator;
+
+            if ( channel & RedChannel     ) pixel.red     = 0.0;
+            if ( channel & GreenChannel   ) pixel.green   = 0.0;
+            if ( channel & BlueChannel    ) pixel.blue    = 0.0;
+            if ( channel & BlackChannel   ) pixel.black   = 0.0;
+            if ( channel & AlphaChannel ) pixel.alpha = 0.0;
+            denominator = 0.0;
+            for(k=0; k<number_arguments; k+=2+number_colors) {
+              register ssize_t x=(ssize_t) k+2;
+              double weight =
+                  ((double)i-arguments[ k ])*((double)i-arguments[ k ])
+                + ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
+              if ( method == InverseColorInterpolate )
+                weight = sqrt(weight);  /* inverse, not inverse squared */
+              weight = ( weight < 1.0 ) ? 1.0 : 1.0/weight;
+              if ( channel & RedChannel )
+                pixel.red     += arguments[x++]*weight;
+              if ( channel & GreenChannel )
+                pixel.green   += arguments[x++]*weight;
+              if ( channel & BlueChannel )
+                pixel.blue    += arguments[x++]*weight;
+              if ( channel & AlphaChannel )
+                pixel.alpha += arguments[x++]*weight;
+              if ( channel & BlackChannel )
+                pixel.black   += arguments[x++]*weight;
+              denominator += weight;
+            }
+            if ( channel & RedChannel     ) pixel.red     /= denominator;
+            if ( channel & GreenChannel   ) pixel.green   /= denominator;
+            if ( channel & BlueChannel    ) pixel.blue    /= denominator;
+            if ( channel & AlphaChannel ) pixel.alpha /= denominator;
+            if ( channel & BlackChannel   ) pixel.black   /= denominator;
+            break;
+          }
+          case VoronoiColorInterpolate:
+          default:
+          { /* Just use the closest control point you can find! */
+            size_t
+              k;
+            double
+              minimum = MagickHuge;
+
+            for(k=0; k<number_arguments; k+=2+number_colors) {
+              double distance =
+                  ((double)i-arguments[ k ])*((double)i-arguments[ k ])
+                + ((double)j-arguments[k+1])*((double)j-arguments[k+1]);
+              if ( distance < minimum ) {
+                register ssize_t x=(ssize_t) k+2;
+                if ( channel & RedChannel     ) pixel.red     = arguments[x++];
+                if ( channel & GreenChannel   ) pixel.green   = arguments[x++];
+                if ( channel & BlueChannel    ) pixel.blue    = arguments[x++];
+                if ( channel & AlphaChannel ) pixel.alpha = arguments[x++];
+                if ( channel & BlackChannel   ) pixel.black   = arguments[x++];
+                minimum = distance;
+              }
+            }
+            break;
+          }
+        }
+        /* set the color directly back into the source image */
+        if ( channel & RedChannel     ) pixel.red     *= QuantumRange;
+        if ( channel & GreenChannel   ) pixel.green   *= QuantumRange;
+        if ( channel & BlueChannel    ) pixel.blue    *= QuantumRange;
+        if ( channel & BlackChannel   ) pixel.black   *= QuantumRange;
+        if ( channel & AlphaChannel ) pixel.alpha *= QuantumRange;
+        SetPixelPixelInfo(sparse_image,&pixel,q);
+        q+=GetPixelChannels(sparse_image);
+      }
+      sync=SyncCacheViewAuthenticPixels(sparse_view,exception);
+      if (sync == MagickFalse)
+        status=MagickFalse;
+      if (image->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SparseColorImage)
+#endif
+          proceed=SetImageProgress(image,SparseColorTag,progress++,image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+    }
+    sparse_view=DestroyCacheView(sparse_view);
+    if (status == MagickFalse)
+      sparse_image=DestroyImage(sparse_image);
+  }
+  coeff = (double *) RelinquishMagickMemory(coeff);
+  return(sparse_image);
+}
diff --git a/MagickCore/distort.h b/MagickCore/distort.h
new file mode 100644
index 0000000..731be90
--- /dev/null
+++ b/MagickCore/distort.h
@@ -0,0 +1,83 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image distortion methods.
+*/
+#ifndef _MAGICKCORE_DISTORT_H
+#define _MAGICKCORE_DISTORT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+  These two enum are linked, with common enumerated values.  Both
+  DistortImages() and SparseColor() often share code to determine functional
+  coefficients for common methods.
+
+  Caution should be taken to ensure that only the common methods contain the
+  same enumerated value, while all others remain unique across both
+  enumerations.
+*/
+typedef enum
+{
+  UndefinedDistortion,
+  AffineDistortion,
+  AffineProjectionDistortion,
+  ScaleRotateTranslateDistortion,
+  PerspectiveDistortion,
+  PerspectiveProjectionDistortion,
+  BilinearForwardDistortion,
+  BilinearDistortion = BilinearForwardDistortion,
+  BilinearReverseDistortion,
+  PolynomialDistortion,
+  ArcDistortion,
+  PolarDistortion,
+  DePolarDistortion,
+  Cylinder2PlaneDistortion,
+  Plane2CylinderDistortion,
+  BarrelDistortion,
+  BarrelInverseDistortion,
+  ShepardsDistortion,
+  ResizeDistortion,
+  SentinelDistortion
+} DistortImageMethod;
+
+typedef enum
+{
+  UndefinedColorInterpolate = UndefinedDistortion,
+  BarycentricColorInterpolate = AffineDistortion,
+  BilinearColorInterpolate = BilinearReverseDistortion,
+  PolynomialColorInterpolate = PolynomialDistortion,
+  ShepardsColorInterpolate = ShepardsDistortion,
+  /*
+    Methods unique to SparseColor().
+  */
+  VoronoiColorInterpolate = SentinelDistortion,
+  InverseColorInterpolate
+} SparseColorMethod;
+
+extern MagickExport Image
+  *DistortImage(const Image *,const DistortImageMethod,const size_t,
+    const double *,MagickBooleanType,ExceptionInfo *exception),
+  *DistortResizeImage(const Image *,const size_t,const size_t,ExceptionInfo *),
+  *SparseColorImage(const Image *,const ChannelType,const SparseColorMethod,
+    const size_t,const double *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/draw-private.h b/MagickCore/draw-private.h
new file mode 100644
index 0000000..1489e25
--- /dev/null
+++ b/MagickCore/draw-private.h
@@ -0,0 +1,85 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private image drawing methods.
+*/
+#ifndef _MAGICKCORE_DRAW_PRIVATE_H
+#define _MAGICKCORE_DRAW_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/cache.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+
+static inline MagickBooleanType GetFillColor(const DrawInfo *draw_info,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel)
+{
+  Image
+    *pattern;
+
+  MagickBooleanType
+    status;
+
+  pattern=draw_info->fill_pattern;
+  if (pattern == (Image *) NULL)
+    {
+      *pixel=draw_info->fill;
+      return(MagickTrue);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+  #pragma omp critical
+#endif
+  status=GetOneVirtualMethodPixel(pattern,TileVirtualPixelMethod,
+    x+pattern->tile_offset.x,y+pattern->tile_offset.y,pixel,
+    &pattern->exception);
+  if (pattern->matte == MagickFalse)
+    pixel->alpha=OpaqueAlpha;
+  return(status);
+}
+
+static inline MagickBooleanType GetStrokeColor(const DrawInfo *draw_info,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel)
+{
+  Image
+    *pattern;
+
+  MagickBooleanType
+    status;
+
+  pattern=draw_info->stroke_pattern;
+  if (pattern == (Image *) NULL)
+    {
+      *pixel=draw_info->stroke;
+      return(MagickTrue);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+  #pragma omp critical
+#endif
+  status=GetOneVirtualMethodPixel(pattern,TileVirtualPixelMethod,
+    x+pattern->tile_offset.x,y+pattern->tile_offset.y,pixel,
+    &pattern->exception);
+  if (pattern->matte == MagickFalse)
+    pixel->alpha=OpaqueAlpha;
+  return(status);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/draw.c b/MagickCore/draw.c
new file mode 100644
index 0000000..7cf06c6
--- /dev/null
+++ b/MagickCore/draw.c
@@ -0,0 +1,6135 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                        DDDD   RRRR    AAA   W   W                           %
+%                        D   D  R   R  A   A  W   W                           %
+%                        D   D  RRRR   AAAAA  W W W                           %
+%                        D   D  R RN   A   A  WW WW                           %
+%                        DDDD   R  R   A   A  W   W                           %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Drawing Methods                        %
+%                                                                             %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1998                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Bill Radcliffe of Corbis (www.corbis.com) contributed the polygon
+% rendering code based on Paul Heckbert's "Concave Polygon Scan Conversion",
+% Graphics Gems, 1990.  Leonard Rosenthal and David Harr of Appligent
+% (www.appligent.com) contributed the dash pattern, linecap stroking
+% algorithm, and minor rendering improvements.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/draw-private.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resample-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+
+/*
+  Define declarations.
+*/
+#define BezierQuantum  200
+
+/*
+  Typedef declarations.
+*/
+typedef struct _EdgeInfo
+{
+  SegmentInfo
+    bounds;
+
+  MagickRealType
+    scanline;
+
+  PointInfo
+    *points;
+
+  size_t
+    number_points;
+
+  ssize_t
+    direction;
+
+  MagickBooleanType
+    ghostline;
+
+  size_t
+    highwater;
+} EdgeInfo;
+
+typedef struct _ElementInfo
+{
+  MagickRealType
+    cx,
+    cy,
+    major,
+    minor,
+    angle;
+} ElementInfo;
+
+typedef struct _PolygonInfo
+{
+  EdgeInfo
+    *edges;
+
+  size_t
+    number_edges;
+} PolygonInfo;
+
+typedef enum
+{
+  MoveToCode,
+  OpenCode,
+  GhostlineCode,
+  LineToCode,
+  EndCode
+} PathInfoCode;
+
+typedef struct _PathInfo
+{
+  PointInfo
+    point;
+
+  PathInfoCode
+    code;
+} PathInfo;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *);
+
+static PrimitiveInfo
+  *TraceStrokePolygon(const DrawInfo *,const PrimitiveInfo *);
+
+static size_t
+  TracePath(PrimitiveInfo *,const char *);
+
+static void
+  TraceArc(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
+  TraceArcPath(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo,
+    const MagickRealType,const MagickBooleanType,const MagickBooleanType),
+  TraceBezier(PrimitiveInfo *,const size_t),
+  TraceCircle(PrimitiveInfo *,const PointInfo,const PointInfo),
+  TraceEllipse(PrimitiveInfo *,const PointInfo,const PointInfo,const PointInfo),
+  TraceLine(PrimitiveInfo *,const PointInfo,const PointInfo),
+  TraceRectangle(PrimitiveInfo *,const PointInfo,const PointInfo),
+  TraceRoundRectangle(PrimitiveInfo *,const PointInfo,const PointInfo,
+    PointInfo),
+  TraceSquareLinecap(PrimitiveInfo *,const size_t,const MagickRealType);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e D r a w I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireDrawInfo() returns a DrawInfo structure properly initialized.
+%
+%  The format of the AcquireDrawInfo method is:
+%
+%      DrawInfo *AcquireDrawInfo(void)
+%
+*/
+MagickExport DrawInfo *AcquireDrawInfo(void)
+{
+  DrawInfo
+    *draw_info;
+
+  draw_info=(DrawInfo *) AcquireMagickMemory(sizeof(*draw_info));
+  if (draw_info == (DrawInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetDrawInfo((ImageInfo *) NULL,draw_info);
+  return(draw_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e D r a w I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneDrawInfo() makes a copy of the given draw info structure.  If NULL
+%  is specified, a new image info structure is created initialized to
+%  default values.
+%
+%  The format of the CloneDrawInfo method is:
+%
+%      DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
+%        const DrawInfo *draw_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o draw_info: the draw info.
+%
+*/
+MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
+  const DrawInfo *draw_info)
+{
+  DrawInfo
+    *clone_info;
+
+  clone_info=(DrawInfo *) AcquireMagickMemory(sizeof(*clone_info));
+  if (clone_info == (DrawInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetDrawInfo(image_info,clone_info);
+  if (draw_info == (DrawInfo *) NULL)
+    return(clone_info);
+  if (clone_info->primitive != (char *) NULL)
+    (void) CloneString(&clone_info->primitive,draw_info->primitive);
+  if (draw_info->geometry != (char *) NULL)
+    (void) CloneString(&clone_info->geometry,draw_info->geometry);
+  clone_info->viewbox=draw_info->viewbox;
+  clone_info->affine=draw_info->affine;
+  clone_info->gravity=draw_info->gravity;
+  clone_info->fill=draw_info->fill;
+  clone_info->stroke=draw_info->stroke;
+  clone_info->stroke_width=draw_info->stroke_width;
+  if (draw_info->fill_pattern != (Image *) NULL)
+    clone_info->fill_pattern=CloneImage(draw_info->fill_pattern,0,0,MagickTrue,
+      &draw_info->fill_pattern->exception);
+  if (draw_info->stroke_pattern != (Image *) NULL)
+    clone_info->stroke_pattern=CloneImage(draw_info->stroke_pattern,0,0,
+      MagickTrue,&draw_info->stroke_pattern->exception);
+  clone_info->stroke_antialias=draw_info->stroke_antialias;
+  clone_info->text_antialias=draw_info->text_antialias;
+  clone_info->fill_rule=draw_info->fill_rule;
+  clone_info->linecap=draw_info->linecap;
+  clone_info->linejoin=draw_info->linejoin;
+  clone_info->miterlimit=draw_info->miterlimit;
+  clone_info->dash_offset=draw_info->dash_offset;
+  clone_info->decorate=draw_info->decorate;
+  clone_info->compose=draw_info->compose;
+  if (draw_info->text != (char *) NULL)
+    (void) CloneString(&clone_info->text,draw_info->text);
+  if (draw_info->font != (char *) NULL)
+    (void) CloneString(&clone_info->font,draw_info->font);
+  if (draw_info->metrics != (char *) NULL)
+    (void) CloneString(&clone_info->metrics,draw_info->metrics);
+  if (draw_info->family != (char *) NULL)
+    (void) CloneString(&clone_info->family,draw_info->family);
+  clone_info->style=draw_info->style;
+  clone_info->stretch=draw_info->stretch;
+  clone_info->weight=draw_info->weight;
+  if (draw_info->encoding != (char *) NULL)
+    (void) CloneString(&clone_info->encoding,draw_info->encoding);
+  clone_info->pointsize=draw_info->pointsize;
+  clone_info->kerning=draw_info->kerning;
+  clone_info->interline_spacing=draw_info->interline_spacing;
+  clone_info->interword_spacing=draw_info->interword_spacing;
+  clone_info->direction=draw_info->direction;
+  if (draw_info->density != (char *) NULL)
+    (void) CloneString(&clone_info->density,draw_info->density);
+  clone_info->align=draw_info->align;
+  clone_info->undercolor=draw_info->undercolor;
+  clone_info->border_color=draw_info->border_color;
+  if (draw_info->server_name != (char *) NULL)
+    (void) CloneString(&clone_info->server_name,draw_info->server_name);
+  if (draw_info->dash_pattern != (double *) NULL)
+    {
+      register ssize_t
+        x;
+
+      for (x=0; draw_info->dash_pattern[x] != 0.0; x++) ;
+      clone_info->dash_pattern=(double *) AcquireQuantumMemory((size_t) x+1UL,
+        sizeof(*clone_info->dash_pattern));
+      if (clone_info->dash_pattern == (double *) NULL)
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToAllocateDashPattern");
+      (void) CopyMagickMemory(clone_info->dash_pattern,draw_info->dash_pattern,
+        (size_t) (x+1)*sizeof(*clone_info->dash_pattern));
+    }
+  clone_info->gradient=draw_info->gradient;
+  if (draw_info->gradient.stops != (StopInfo *) NULL)
+    {
+      size_t
+        number_stops;
+
+      number_stops=clone_info->gradient.number_stops;
+      clone_info->gradient.stops=(StopInfo *) AcquireQuantumMemory((size_t)
+        number_stops,sizeof(*clone_info->gradient.stops));
+      if (clone_info->gradient.stops == (StopInfo *) NULL)
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToAllocateDashPattern");
+      (void) CopyMagickMemory(clone_info->gradient.stops,
+        draw_info->gradient.stops,(size_t) number_stops*
+        sizeof(*clone_info->gradient.stops));
+    }
+  if (draw_info->clip_mask != (char *) NULL)
+    (void) CloneString(&clone_info->clip_mask,draw_info->clip_mask);
+  clone_info->bounds=draw_info->bounds;
+  clone_info->clip_units=draw_info->clip_units;
+  clone_info->render=draw_info->render;
+  clone_info->alpha=draw_info->alpha;
+  clone_info->element_reference=draw_info->element_reference;
+  clone_info->debug=IsEventLogging();
+  return(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n v e r t P a t h T o P o l y g o n                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertPathToPolygon() converts a path to the more efficient sorted
+%  rendering form.
+%
+%  The format of the ConvertPathToPolygon method is:
+%
+%      PolygonInfo *ConvertPathToPolygon(const DrawInfo *draw_info,
+%        const PathInfo *path_info)
+%
+%  A description of each parameter follows:
+%
+%    o Method ConvertPathToPolygon returns the path in a more efficient sorted
+%      rendering form of type PolygonInfo.
+%
+%    o draw_info: Specifies a pointer to an DrawInfo structure.
+%
+%    o path_info: Specifies a pointer to an PathInfo structure.
+%
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int CompareEdges(const void *x,const void *y)
+{
+  register const EdgeInfo
+    *p,
+    *q;
+
+  /*
+    Compare two edges.
+  */
+  p=(const EdgeInfo *) x;
+  q=(const EdgeInfo *) y;
+  if ((p->points[0].y-MagickEpsilon) > q->points[0].y)
+    return(1);
+  if ((p->points[0].y+MagickEpsilon) < q->points[0].y)
+    return(-1);
+  if ((p->points[0].x-MagickEpsilon) > q->points[0].x)
+    return(1);
+  if ((p->points[0].x+MagickEpsilon) < q->points[0].x)
+    return(-1);
+  if (((p->points[1].x-p->points[0].x)*(q->points[1].y-q->points[0].y)-
+       (p->points[1].y-p->points[0].y)*(q->points[1].x-q->points[0].x)) > 0.0)
+    return(1);
+  return(-1);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static void LogPolygonInfo(const PolygonInfo *polygon_info)
+{
+  register EdgeInfo
+    *p;
+
+  register ssize_t
+    i,
+    j;
+
+  (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin active-edge");
+  p=polygon_info->edges;
+  for (i=0; i < (ssize_t) polygon_info->number_edges; i++)
+  {
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      edge %.20g:",
+      (double) i);
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      direction: %s",
+      p->direction != MagickFalse ? "down" : "up");
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"      ghostline: %s",
+      p->ghostline != MagickFalse ? "transparent" : "opaque");
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+      "      bounds: %g %g - %g %g",p->bounds.x1,p->bounds.y1,
+      p->bounds.x2,p->bounds.y2);
+    for (j=0; j < (ssize_t) p->number_points; j++)
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),"        %g %g",
+        p->points[j].x,p->points[j].y);
+    p++;
+  }
+  (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end active-edge");
+}
+
+static void ReversePoints(PointInfo *points,const size_t number_points)
+{
+  PointInfo
+    point;
+
+  register ssize_t
+    i;
+
+  for (i=0; i < (ssize_t) (number_points >> 1); i++)
+  {
+    point=points[i];
+    points[i]=points[number_points-(i+1)];
+    points[number_points-(i+1)]=point;
+  }
+}
+
+static PolygonInfo *ConvertPathToPolygon(
+  const DrawInfo *magick_unused(draw_info),const PathInfo *path_info)
+{
+  long
+    direction,
+    next_direction;
+
+  PointInfo
+    point,
+    *points;
+
+  PolygonInfo
+    *polygon_info;
+
+  SegmentInfo
+    bounds;
+
+  register ssize_t
+    i,
+    n;
+
+  MagickBooleanType
+    ghostline;
+
+  size_t
+    edge,
+    number_edges,
+    number_points;
+
+  /*
+    Convert a path to the more efficient sorted rendering form.
+  */
+  polygon_info=(PolygonInfo *) AcquireMagickMemory(sizeof(*polygon_info));
+  if (polygon_info == (PolygonInfo *) NULL)
+    return((PolygonInfo *) NULL);
+  number_edges=16;
+  polygon_info->edges=(EdgeInfo *) AcquireQuantumMemory((size_t) number_edges,
+    sizeof(*polygon_info->edges));
+  if (polygon_info->edges == (EdgeInfo *) NULL)
+    return((PolygonInfo *) NULL);
+  direction=0;
+  edge=0;
+  ghostline=MagickFalse;
+  n=0;
+  number_points=0;
+  points=(PointInfo *) NULL;
+  (void) ResetMagickMemory(&point,0,sizeof(point));
+  (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
+  for (i=0; path_info[i].code != EndCode; i++)
+  {
+    if ((path_info[i].code == MoveToCode) || (path_info[i].code == OpenCode) ||
+        (path_info[i].code == GhostlineCode))
+      {
+        /*
+          Move to.
+        */
+        if ((points != (PointInfo *) NULL) && (n >= 2))
+          {
+            if (edge == number_edges)
+              {
+                number_edges<<=1;
+                polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
+                  polygon_info->edges,(size_t) number_edges,
+                  sizeof(*polygon_info->edges));
+                if (polygon_info->edges == (EdgeInfo *) NULL)
+                  return((PolygonInfo *) NULL);
+              }
+            polygon_info->edges[edge].number_points=(size_t) n;
+            polygon_info->edges[edge].scanline=(-1.0);
+            polygon_info->edges[edge].highwater=0;
+            polygon_info->edges[edge].ghostline=ghostline;
+            polygon_info->edges[edge].direction=(ssize_t) (direction > 0);
+            if (direction < 0)
+              ReversePoints(points,(size_t) n);
+            polygon_info->edges[edge].points=points;
+            polygon_info->edges[edge].bounds=bounds;
+            polygon_info->edges[edge].bounds.y1=points[0].y;
+            polygon_info->edges[edge].bounds.y2=points[n-1].y;
+            points=(PointInfo *) NULL;
+            ghostline=MagickFalse;
+            edge++;
+          }
+        if (points == (PointInfo *) NULL)
+          {
+            number_points=16;
+            points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
+              sizeof(*points));
+            if (points == (PointInfo *) NULL)
+              return((PolygonInfo *) NULL);
+          }
+        ghostline=path_info[i].code == GhostlineCode ? MagickTrue : MagickFalse;
+        point=path_info[i].point;
+        points[0]=point;
+        bounds.x1=point.x;
+        bounds.x2=point.x;
+        direction=0;
+        n=1;
+        continue;
+      }
+    /*
+      Line to.
+    */
+    next_direction=((path_info[i].point.y > point.y) ||
+      ((path_info[i].point.y == point.y) &&
+       (path_info[i].point.x > point.x))) ? 1 : -1;
+    if ((direction != 0) && (direction != next_direction))
+      {
+        /*
+          New edge.
+        */
+        point=points[n-1];
+        if (edge == number_edges)
+          {
+            number_edges<<=1;
+            polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
+              polygon_info->edges,(size_t) number_edges,
+              sizeof(*polygon_info->edges));
+            if (polygon_info->edges == (EdgeInfo *) NULL)
+              return((PolygonInfo *) NULL);
+          }
+        polygon_info->edges[edge].number_points=(size_t) n;
+        polygon_info->edges[edge].scanline=(-1.0);
+        polygon_info->edges[edge].highwater=0;
+        polygon_info->edges[edge].ghostline=ghostline;
+        polygon_info->edges[edge].direction=(ssize_t) (direction > 0);
+        if (direction < 0)
+          ReversePoints(points,(size_t) n);
+        polygon_info->edges[edge].points=points;
+        polygon_info->edges[edge].bounds=bounds;
+        polygon_info->edges[edge].bounds.y1=points[0].y;
+        polygon_info->edges[edge].bounds.y2=points[n-1].y;
+        number_points=16;
+        points=(PointInfo *) AcquireQuantumMemory((size_t) number_points,
+          sizeof(*points));
+        if (points == (PointInfo *) NULL)
+          return((PolygonInfo *) NULL);
+        n=1;
+        ghostline=MagickFalse;
+        points[0]=point;
+        bounds.x1=point.x;
+        bounds.x2=point.x;
+        edge++;
+      }
+    direction=next_direction;
+    if (points == (PointInfo *) NULL)
+      continue;
+    if (n == (ssize_t) number_points)
+      {
+        number_points<<=1;
+        points=(PointInfo *) ResizeQuantumMemory(points,(size_t) number_points,
+          sizeof(*points));
+        if (points == (PointInfo *) NULL)
+          return((PolygonInfo *) NULL);
+      }
+    point=path_info[i].point;
+    points[n]=point;
+    if (point.x < bounds.x1)
+      bounds.x1=point.x;
+    if (point.x > bounds.x2)
+      bounds.x2=point.x;
+    n++;
+  }
+  if (points != (PointInfo *) NULL)
+    {
+      if (n < 2)
+        points=(PointInfo *) RelinquishMagickMemory(points);
+      else
+        {
+          if (edge == number_edges)
+            {
+              number_edges<<=1;
+              polygon_info->edges=(EdgeInfo *) ResizeQuantumMemory(
+                polygon_info->edges,(size_t) number_edges,
+                sizeof(*polygon_info->edges));
+              if (polygon_info->edges == (EdgeInfo *) NULL)
+                return((PolygonInfo *) NULL);
+            }
+          polygon_info->edges[edge].number_points=(size_t) n;
+          polygon_info->edges[edge].scanline=(-1.0);
+          polygon_info->edges[edge].highwater=0;
+          polygon_info->edges[edge].ghostline=ghostline;
+          polygon_info->edges[edge].direction=(ssize_t) (direction > 0);
+          if (direction < 0)
+            ReversePoints(points,(size_t) n);
+          polygon_info->edges[edge].points=points;
+          polygon_info->edges[edge].bounds=bounds;
+          polygon_info->edges[edge].bounds.y1=points[0].y;
+          polygon_info->edges[edge].bounds.y2=points[n-1].y;
+          ghostline=MagickFalse;
+          edge++;
+        }
+    }
+  polygon_info->number_edges=edge;
+  qsort(polygon_info->edges,(size_t) polygon_info->number_edges,
+    sizeof(*polygon_info->edges),CompareEdges);
+  if (IsEventLogging() != MagickFalse)
+    LogPolygonInfo(polygon_info);
+  return(polygon_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n v e r t P r i m i t i v e T o P a t h                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertPrimitiveToPath() converts a PrimitiveInfo structure into a vector
+%  path structure.
+%
+%  The format of the ConvertPrimitiveToPath method is:
+%
+%      PathInfo *ConvertPrimitiveToPath(const DrawInfo *draw_info,
+%        const PrimitiveInfo *primitive_info)
+%
+%  A description of each parameter follows:
+%
+%    o Method ConvertPrimitiveToPath returns a vector path structure of type
+%      PathInfo.
+%
+%    o draw_info: a structure of type DrawInfo.
+%
+%    o primitive_info: Specifies a pointer to an PrimitiveInfo structure.
+%
+%
+*/
+
+static void LogPathInfo(const PathInfo *path_info)
+{
+  register const PathInfo
+    *p;
+
+  (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin vector-path");
+  for (p=path_info; p->code != EndCode; p++)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+      "      %g %g %s",p->point.x,p->point.y,p->code == GhostlineCode ?
+      "moveto ghostline" : p->code == OpenCode ? "moveto open" :
+      p->code == MoveToCode ? "moveto" : p->code == LineToCode ? "lineto" :
+      "?");
+  (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end vector-path");
+}
+
+static PathInfo *ConvertPrimitiveToPath(
+  const DrawInfo *magick_unused(draw_info),const PrimitiveInfo *primitive_info)
+{
+  PathInfo
+    *path_info;
+
+  PathInfoCode
+    code;
+
+  PointInfo
+    p,
+    q;
+
+  register ssize_t
+    i,
+    n;
+
+  ssize_t
+    coordinates,
+    start;
+
+  /*
+    Converts a PrimitiveInfo structure into a vector path structure.
+  */
+  switch (primitive_info->primitive)
+  {
+    case PointPrimitive:
+    case ColorPrimitive:
+    case MattePrimitive:
+    case TextPrimitive:
+    case ImagePrimitive:
+      return((PathInfo *) NULL);
+    default:
+      break;
+  }
+  for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
+  path_info=(PathInfo *) AcquireQuantumMemory((size_t) (2UL*i+3UL),
+    sizeof(*path_info));
+  if (path_info == (PathInfo *) NULL)
+    return((PathInfo *) NULL);
+  coordinates=0;
+  n=0;
+  p.x=(-1.0);
+  p.y=(-1.0);
+  q.x=(-1.0);
+  q.y=(-1.0);
+  start=0;
+  for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
+  {
+    code=LineToCode;
+    if (coordinates <= 0)
+      {
+        coordinates=(ssize_t) primitive_info[i].coordinates;
+        p=primitive_info[i].point;
+        start=n;
+        code=MoveToCode;
+      }
+    coordinates--;
+    /*
+      Eliminate duplicate points.
+    */
+    if ((i == 0) || (fabs(q.x-primitive_info[i].point.x) > MagickEpsilon) ||
+        (fabs(q.y-primitive_info[i].point.y) > MagickEpsilon))
+      {
+        path_info[n].code=code;
+        path_info[n].point=primitive_info[i].point;
+        q=primitive_info[i].point;
+        n++;
+      }
+    if (coordinates > 0)
+      continue;
+    if ((fabs(p.x-primitive_info[i].point.x) <= MagickEpsilon) &&
+        (fabs(p.y-primitive_info[i].point.y) <= MagickEpsilon))
+      continue;
+    /*
+      Mark the p point as open if it does not match the q.
+    */
+    path_info[start].code=OpenCode;
+    path_info[n].code=GhostlineCode;
+    path_info[n].point=primitive_info[i].point;
+    n++;
+    path_info[n].code=LineToCode;
+    path_info[n].point=p;
+    n++;
+  }
+  path_info[n].code=EndCode;
+  path_info[n].point.x=0.0;
+  path_info[n].point.y=0.0;
+  if (IsEventLogging() != MagickFalse)
+    LogPathInfo(path_info);
+  return(path_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y D r a w I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyDrawInfo() deallocates memory associated with an DrawInfo
+%  structure.
+%
+%  The format of the DestroyDrawInfo method is:
+%
+%      DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
+%
+%  A description of each parameter follows:
+%
+%    o draw_info: the draw info.
+%
+*/
+MagickExport DrawInfo *DestroyDrawInfo(DrawInfo *draw_info)
+{
+  if (draw_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  if (draw_info->primitive != (char *) NULL)
+    draw_info->primitive=DestroyString(draw_info->primitive);
+  if (draw_info->text != (char *) NULL)
+    draw_info->text=DestroyString(draw_info->text);
+  if (draw_info->geometry != (char *) NULL)
+    draw_info->geometry=DestroyString(draw_info->geometry);
+  if (draw_info->fill_pattern != (Image *) NULL)
+    draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
+  if (draw_info->stroke_pattern != (Image *) NULL)
+    draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
+  if (draw_info->font != (char *) NULL)
+    draw_info->font=DestroyString(draw_info->font);
+  if (draw_info->metrics != (char *) NULL)
+    draw_info->metrics=DestroyString(draw_info->metrics);
+  if (draw_info->family != (char *) NULL)
+    draw_info->family=DestroyString(draw_info->family);
+  if (draw_info->encoding != (char *) NULL)
+    draw_info->encoding=DestroyString(draw_info->encoding);
+  if (draw_info->density != (char *) NULL)
+    draw_info->density=DestroyString(draw_info->density);
+  if (draw_info->server_name != (char *) NULL)
+    draw_info->server_name=(char *)
+     RelinquishMagickMemory(draw_info->server_name);
+  if (draw_info->dash_pattern != (double *) NULL)
+    draw_info->dash_pattern=(double *) RelinquishMagickMemory(
+      draw_info->dash_pattern);
+  if (draw_info->gradient.stops != (StopInfo *) NULL)
+    draw_info->gradient.stops=(StopInfo *) RelinquishMagickMemory(
+      draw_info->gradient.stops);
+  if (draw_info->clip_mask != (char *) NULL)
+    draw_info->clip_mask=DestroyString(draw_info->clip_mask);
+  draw_info->signature=(~MagickSignature);
+  draw_info=(DrawInfo *) RelinquishMagickMemory(draw_info);
+  return(draw_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y E d g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyEdge() destroys the specified polygon edge.
+%
+%  The format of the DestroyEdge method is:
+%
+%      ssize_t DestroyEdge(PolygonInfo *polygon_info,const int edge)
+%
+%  A description of each parameter follows:
+%
+%    o polygon_info: Specifies a pointer to an PolygonInfo structure.
+%
+%    o edge: the polygon edge number to destroy.
+%
+*/
+static size_t DestroyEdge(PolygonInfo *polygon_info,
+  const size_t edge)
+{
+  assert(edge < polygon_info->number_edges);
+  polygon_info->edges[edge].points=(PointInfo *) RelinquishMagickMemory(
+    polygon_info->edges[edge].points);
+  polygon_info->number_edges--;
+  if (edge < polygon_info->number_edges)
+    (void) CopyMagickMemory(polygon_info->edges+edge,polygon_info->edges+edge+1,
+      (size_t) (polygon_info->number_edges-edge)*sizeof(*polygon_info->edges));
+  return(polygon_info->number_edges);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P o l y g o n I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPolygonInfo() destroys the PolygonInfo data structure.
+%
+%  The format of the DestroyPolygonInfo method is:
+%
+%      PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
+%
+%  A description of each parameter follows:
+%
+%    o polygon_info: Specifies a pointer to an PolygonInfo structure.
+%
+*/
+static PolygonInfo *DestroyPolygonInfo(PolygonInfo *polygon_info)
+{
+  register ssize_t
+    i;
+
+  for (i=0; i < (ssize_t) polygon_info->number_edges; i++)
+    polygon_info->edges[i].points=(PointInfo *)
+      RelinquishMagickMemory(polygon_info->edges[i].points);
+  polygon_info->edges=(EdgeInfo *) RelinquishMagickMemory(polygon_info->edges);
+  return((PolygonInfo *) RelinquishMagickMemory(polygon_info));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D r a w A f f i n e I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawAffineImage() composites the source over the destination image as
+%  dictated by the affine transform.
+%
+%  The format of the DrawAffineImage method is:
+%
+%      MagickBooleanType DrawAffineImage(Image *image,const Image *source,
+%        const AffineMatrix *affine)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o source: the source image.
+%
+%    o affine: the affine transform.
+%
+*/
+static SegmentInfo AffineEdge(const Image *image,const AffineMatrix *affine,
+  const double y,const SegmentInfo *edge)
+{
+  double
+    intercept,
+    z;
+
+  register double
+    x;
+
+  SegmentInfo
+    inverse_edge;
+
+  /*
+    Determine left and right edges.
+  */
+  inverse_edge.x1=edge->x1;
+  inverse_edge.y1=edge->y1;
+  inverse_edge.x2=edge->x2;
+  inverse_edge.y2=edge->y2;
+  z=affine->ry*y+affine->tx;
+  if (affine->sx > MagickEpsilon)
+    {
+      intercept=(-z/affine->sx);
+      x=intercept+MagickEpsilon;
+      if (x > inverse_edge.x1)
+        inverse_edge.x1=x;
+      intercept=(-z+(double) image->columns)/affine->sx;
+      x=intercept-MagickEpsilon;
+      if (x < inverse_edge.x2)
+        inverse_edge.x2=x;
+    }
+  else
+    if (affine->sx < -MagickEpsilon)
+      {
+        intercept=(-z+(double) image->columns)/affine->sx;
+        x=intercept+MagickEpsilon;
+        if (x > inverse_edge.x1)
+          inverse_edge.x1=x;
+        intercept=(-z/affine->sx);
+        x=intercept-MagickEpsilon;
+        if (x < inverse_edge.x2)
+          inverse_edge.x2=x;
+      }
+    else
+      if ((z < 0.0) || ((size_t) floor(z+0.5) >= image->columns))
+        {
+          inverse_edge.x2=edge->x1;
+          return(inverse_edge);
+        }
+  /*
+    Determine top and bottom edges.
+  */
+  z=affine->sy*y+affine->ty;
+  if (affine->rx > MagickEpsilon)
+    {
+      intercept=(-z/affine->rx);
+      x=intercept+MagickEpsilon;
+      if (x > inverse_edge.x1)
+        inverse_edge.x1=x;
+      intercept=(-z+(double) image->rows)/affine->rx;
+      x=intercept-MagickEpsilon;
+      if (x < inverse_edge.x2)
+        inverse_edge.x2=x;
+    }
+  else
+    if (affine->rx < -MagickEpsilon)
+      {
+        intercept=(-z+(double) image->rows)/affine->rx;
+        x=intercept+MagickEpsilon;
+        if (x > inverse_edge.x1)
+          inverse_edge.x1=x;
+        intercept=(-z/affine->rx);
+        x=intercept-MagickEpsilon;
+        if (x < inverse_edge.x2)
+          inverse_edge.x2=x;
+      }
+    else
+      if ((z < 0.0) || ((size_t) floor(z+0.5) >= image->rows))
+        {
+          inverse_edge.x2=edge->x2;
+          return(inverse_edge);
+        }
+  return(inverse_edge);
+}
+
+static AffineMatrix InverseAffineMatrix(const AffineMatrix *affine)
+{
+  AffineMatrix
+    inverse_affine;
+
+  double
+    determinant;
+
+  determinant=1.0/(affine->sx*affine->sy-affine->rx*affine->ry);
+  inverse_affine.sx=determinant*affine->sy;
+  inverse_affine.rx=determinant*(-affine->rx);
+  inverse_affine.ry=determinant*(-affine->ry);
+  inverse_affine.sy=determinant*affine->sx;
+  inverse_affine.tx=(-affine->tx)*inverse_affine.sx-affine->ty*
+    inverse_affine.ry;
+  inverse_affine.ty=(-affine->tx)*inverse_affine.rx-affine->ty*
+    inverse_affine.sy;
+  return(inverse_affine);
+}
+
+static inline ssize_t MagickAbsoluteValue(const ssize_t x)
+{
+  if (x < 0)
+    return(-x);
+  return(x);
+}
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType DrawAffineImage(Image *image,
+  const Image *source,const AffineMatrix *affine)
+{
+  AffineMatrix
+    inverse_affine;
+
+  CacheView
+    *image_view,
+    *source_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  PointInfo
+    extent[4],
+    min,
+    max,
+    point;
+
+  register ssize_t
+    i;
+
+  SegmentInfo
+    edge;
+
+  ssize_t
+    y;
+
+  /*
+    Determine bounding box.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(source != (const Image *) NULL);
+  assert(source->signature == MagickSignature);
+  assert(affine != (AffineMatrix *) NULL);
+  extent[0].x=0.0;
+  extent[0].y=0.0;
+  extent[1].x=(double) source->columns-1.0;
+  extent[1].y=0.0;
+  extent[2].x=(double) source->columns-1.0;
+  extent[2].y=(double) source->rows-1.0;
+  extent[3].x=0.0;
+  extent[3].y=(double) source->rows-1.0;
+  for (i=0; i < 4; i++)
+  {
+    point=extent[i];
+    extent[i].x=point.x*affine->sx+point.y*affine->ry+affine->tx;
+    extent[i].y=point.x*affine->rx+point.y*affine->sy+affine->ty;
+  }
+  min=extent[0];
+  max=extent[0];
+  for (i=1; i < 4; i++)
+  {
+    if (min.x > extent[i].x)
+      min.x=extent[i].x;
+    if (min.y > extent[i].y)
+      min.y=extent[i].y;
+    if (max.x < extent[i].x)
+      max.x=extent[i].x;
+    if (max.y < extent[i].y)
+      max.y=extent[i].y;
+  }
+  /*
+    Affine transform image.
+  */
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  edge.x1=MagickMax(min.x,0.0);
+  edge.y1=MagickMax(min.y,0.0);
+  edge.x2=MagickMin(max.x,(double) image->columns-1.0);
+  edge.y2=MagickMin(max.y,(double) image->rows-1.0);
+  inverse_affine=InverseAffineMatrix(affine);
+  GetPixelInfo(image,&zero);
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  source_view=AcquireCacheView(source);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=(ssize_t) ceil(edge.y1-0.5); y <= (ssize_t) floor(edge.y2+0.5); y++)
+  {
+    PixelInfo
+      composite,
+      pixel;
+
+    PointInfo
+      point;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    SegmentInfo
+      inverse_edge;
+
+    ssize_t
+      x_offset;
+
+    inverse_edge=AffineEdge(source,&inverse_affine,(double) y,&edge);
+    if (inverse_edge.x2 < inverse_edge.x1)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,(ssize_t) ceil(inverse_edge.x1-
+      0.5),y,(size_t) ((ssize_t) floor(inverse_edge.x2+0.5)-(ssize_t) floor(
+      inverse_edge.x1+0.5)+1),1,exception);
+    if (q == (Quantum *) NULL)
+      continue;
+    pixel=zero;
+    composite=zero;
+    x_offset=0;
+    for (x=(ssize_t) ceil(inverse_edge.x1-0.5); x <= (ssize_t) floor(inverse_edge.x2+0.5); x++)
+    {
+      point.x=(double) x*inverse_affine.sx+y*inverse_affine.ry+
+        inverse_affine.tx;
+      point.y=(double) x*inverse_affine.rx+y*inverse_affine.sy+
+        inverse_affine.ty;
+      (void) InterpolatePixelInfo(source,source_view,UndefinedInterpolatePixel,
+        point.x,point.y,&pixel,exception);
+      SetPixelInfo(image,q,&composite);
+      CompositePixelInfoOver(&pixel,pixel.alpha,&composite,composite.alpha,
+        &composite);
+      SetPixelPixelInfo(image,&composite,q);
+      x_offset++;
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  source_view=DestroyCacheView(source_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D r a w B o u n d i n g R e c t a n g l e s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawBoundingRectangles() draws the bounding rectangles on the image.  This
+%  is only useful for developers debugging the rendering algorithm.
+%
+%  The format of the DrawBoundingRectangles method is:
+%
+%      void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
+%        PolygonInfo *polygon_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o polygon_info: Specifies a pointer to a PolygonInfo structure.
+%
+*/
+static void DrawBoundingRectangles(Image *image,const DrawInfo *draw_info,
+  const PolygonInfo *polygon_info)
+{
+  DrawInfo
+    *clone_info;
+
+  MagickRealType
+    mid;
+
+  PointInfo
+    end,
+    resolution,
+    start;
+
+  PrimitiveInfo
+    primitive_info[6];
+
+  register ssize_t
+    i;
+
+  SegmentInfo
+    bounds;
+
+  ssize_t
+    coordinates;
+
+  clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  (void) QueryColorDatabase("#0000",&clone_info->fill,&image->exception);
+  resolution.x=DefaultResolution;
+  resolution.y=DefaultResolution;
+  if (clone_info->density != (char *) NULL)
+    {
+      GeometryInfo
+        geometry_info;
+
+      MagickStatusType
+        flags;
+
+      flags=ParseGeometry(clone_info->density,&geometry_info);
+      resolution.x=geometry_info.rho;
+      resolution.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == MagickFalse)
+        resolution.y=resolution.x;
+    }
+  mid=(resolution.x/72.0)*ExpandAffine(&clone_info->affine)*
+    clone_info->stroke_width/2.0;
+  bounds.x1=0.0;
+  bounds.y1=0.0;
+  bounds.x2=0.0;
+  bounds.y2=0.0;
+  if (polygon_info != (PolygonInfo *) NULL)
+    {
+      bounds=polygon_info->edges[0].bounds;
+      for (i=1; i < (ssize_t) polygon_info->number_edges; i++)
+      {
+        if (polygon_info->edges[i].bounds.x1 < (double) bounds.x1)
+          bounds.x1=polygon_info->edges[i].bounds.x1;
+        if (polygon_info->edges[i].bounds.y1 < (double) bounds.y1)
+          bounds.y1=polygon_info->edges[i].bounds.y1;
+        if (polygon_info->edges[i].bounds.x2 > (double) bounds.x2)
+          bounds.x2=polygon_info->edges[i].bounds.x2;
+        if (polygon_info->edges[i].bounds.y2 > (double) bounds.y2)
+          bounds.y2=polygon_info->edges[i].bounds.y2;
+      }
+      bounds.x1-=mid;
+      bounds.x1=bounds.x1 < 0.0 ? 0.0 : bounds.x1 >= (double)
+        image->columns ? (double) image->columns-1 : bounds.x1;
+      bounds.y1-=mid;
+      bounds.y1=bounds.y1 < 0.0 ? 0.0 : bounds.y1 >= (double)
+        image->rows ? (double) image->rows-1 : bounds.y1;
+      bounds.x2+=mid;
+      bounds.x2=bounds.x2 < 0.0 ? 0.0 : bounds.x2 >= (double)
+        image->columns ? (double) image->columns-1 : bounds.x2;
+      bounds.y2+=mid;
+      bounds.y2=bounds.y2 < 0.0 ? 0.0 : bounds.y2 >= (double)
+        image->rows ? (double) image->rows-1 : bounds.y2;
+      for (i=0; i < (ssize_t) polygon_info->number_edges; i++)
+      {
+        if (polygon_info->edges[i].direction != 0)
+          (void) QueryColorDatabase("red",&clone_info->stroke,
+            &image->exception);
+        else
+          (void) QueryColorDatabase("green",&clone_info->stroke,
+            &image->exception);
+        start.x=(double) (polygon_info->edges[i].bounds.x1-mid);
+        start.y=(double) (polygon_info->edges[i].bounds.y1-mid);
+        end.x=(double) (polygon_info->edges[i].bounds.x2+mid);
+        end.y=(double) (polygon_info->edges[i].bounds.y2+mid);
+        primitive_info[0].primitive=RectanglePrimitive;
+        TraceRectangle(primitive_info,start,end);
+        primitive_info[0].method=ReplaceMethod;
+        coordinates=(ssize_t) primitive_info[0].coordinates;
+        primitive_info[coordinates].primitive=UndefinedPrimitive;
+        (void) DrawPrimitive(image,clone_info,primitive_info);
+      }
+    }
+  (void) QueryColorDatabase("blue",&clone_info->stroke,&image->exception);
+  start.x=(double) (bounds.x1-mid);
+  start.y=(double) (bounds.y1-mid);
+  end.x=(double) (bounds.x2+mid);
+  end.y=(double) (bounds.y2+mid);
+  primitive_info[0].primitive=RectanglePrimitive;
+  TraceRectangle(primitive_info,start,end);
+  primitive_info[0].method=ReplaceMethod;
+  coordinates=(ssize_t) primitive_info[0].coordinates;
+  primitive_info[coordinates].primitive=UndefinedPrimitive;
+  (void) DrawPrimitive(image,clone_info,primitive_info);
+  clone_info=DestroyDrawInfo(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D r a w C l i p P a t h                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawClipPath() draws the clip path on the image mask.
+%
+%  The format of the DrawClipPath method is:
+%
+%      MagickBooleanType DrawClipPath(Image *image,const DrawInfo *draw_info,
+%        const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o name: the name of the clip path.
+%
+*/
+MagickExport MagickBooleanType DrawClipPath(Image *image,
+  const DrawInfo *draw_info,const char *name)
+{
+  char
+    clip_mask[MaxTextExtent];
+
+  const char
+    *value;
+
+  DrawInfo
+    *clone_info;
+
+  MagickStatusType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (const DrawInfo *) NULL);
+  (void) FormatLocaleString(clip_mask,MaxTextExtent,"%s",name);
+  value=GetImageArtifact(image,clip_mask);
+  if (value == (const char *) NULL)
+    return(MagickFalse);
+  if (image->clip_mask == (Image *) NULL)
+    {
+      Image
+        *clip_mask;
+
+      clip_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
+        &image->exception);
+      if (clip_mask == (Image *) NULL)
+        return(MagickFalse);
+      (void) SetImageClipMask(image,clip_mask);
+      clip_mask=DestroyImage(clip_mask);
+    }
+  (void) QueryColorDatabase("#00000000",&image->clip_mask->background_color,
+    &image->exception);
+  image->clip_mask->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(image->clip_mask);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"\nbegin clip-path %s",
+      draw_info->clip_mask);
+  clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  (void) CloneString(&clone_info->primitive,value);
+  (void) QueryColorDatabase("#ffffff",&clone_info->fill,&image->exception);
+  clone_info->clip_mask=(char *) NULL;
+  status=DrawImage(image->clip_mask,clone_info);
+  status|=NegateImage(image->clip_mask,MagickFalse);
+  clone_info=DestroyDrawInfo(clone_info);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end clip-path");
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D r a w D a s h P o l y g o n                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawDashPolygon() draws a dashed polygon (line, rectangle, ellipse) on the
+%  image while respecting the dash offset and dash pattern attributes.
+%
+%  The format of the DrawDashPolygon method is:
+%
+%      MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
+%        const PrimitiveInfo *primitive_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o draw_info: the draw info.
+%
+%    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
+%
+%    o image: the image.
+%
+%
+*/
+static MagickBooleanType DrawDashPolygon(const DrawInfo *draw_info,
+  const PrimitiveInfo *primitive_info,Image *image)
+{
+  DrawInfo
+    *clone_info;
+
+  MagickRealType
+    length,
+    maximum_length,
+    offset,
+    scale,
+    total_length;
+
+  MagickStatusType
+    status;
+
+  PrimitiveInfo
+    *dash_polygon;
+
+  register ssize_t
+    i;
+
+  register MagickRealType
+    dx,
+    dy;
+
+  size_t
+    number_vertices;
+
+  ssize_t
+    j,
+    n;
+
+  assert(draw_info != (const DrawInfo *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin draw-dash");
+  clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  clone_info->miterlimit=0;
+  for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
+  number_vertices=(size_t) i;
+  dash_polygon=(PrimitiveInfo *) AcquireQuantumMemory((size_t)
+    (2UL*number_vertices+1UL),sizeof(*dash_polygon));
+  if (dash_polygon == (PrimitiveInfo *) NULL)
+    return(MagickFalse);
+  dash_polygon[0]=primitive_info[0];
+  scale=ExpandAffine(&draw_info->affine);
+  length=scale*(draw_info->dash_pattern[0]-0.5);
+  offset=draw_info->dash_offset != 0.0 ? scale*draw_info->dash_offset : 0.0;
+  j=1;
+  for (n=0; offset > 0.0; j=0)
+  {
+    if (draw_info->dash_pattern[n] <= 0.0)
+      break;
+    length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
+    if (offset > length)
+      {
+        offset-=length;
+        n++;
+        length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
+        continue;
+      }
+    if (offset < length)
+      {
+        length-=offset;
+        offset=0.0;
+        break;
+      }
+    offset=0.0;
+    n++;
+  }
+  status=MagickTrue;
+  maximum_length=0.0;
+  total_length=0.0;
+  for (i=1; i < (ssize_t) number_vertices; i++)
+  {
+    dx=primitive_info[i].point.x-primitive_info[i-1].point.x;
+    dy=primitive_info[i].point.y-primitive_info[i-1].point.y;
+    maximum_length=hypot((double) dx,dy);
+    if (length == 0.0)
+      {
+        n++;
+        if (draw_info->dash_pattern[n] == 0.0)
+          n=0;
+        length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
+      }
+    for (total_length=0.0; (total_length+length) < maximum_length; )
+    {
+      total_length+=length;
+      if ((n & 0x01) != 0)
+        {
+          dash_polygon[0]=primitive_info[0];
+          dash_polygon[0].point.x=(double) (primitive_info[i-1].point.x+dx*
+            total_length/maximum_length);
+          dash_polygon[0].point.y=(double) (primitive_info[i-1].point.y+dy*
+            total_length/maximum_length);
+          j=1;
+        }
+      else
+        {
+          if ((j+1) > (ssize_t) (2*number_vertices))
+            break;
+          dash_polygon[j]=primitive_info[i-1];
+          dash_polygon[j].point.x=(double) (primitive_info[i-1].point.x+dx*
+            total_length/maximum_length);
+          dash_polygon[j].point.y=(double) (primitive_info[i-1].point.y+dy*
+            total_length/maximum_length);
+          dash_polygon[j].coordinates=1;
+          j++;
+          dash_polygon[0].coordinates=(size_t) j;
+          dash_polygon[j].primitive=UndefinedPrimitive;
+          status|=DrawStrokePolygon(image,clone_info,dash_polygon);
+        }
+      n++;
+      if (draw_info->dash_pattern[n] == 0.0)
+        n=0;
+      length=scale*(draw_info->dash_pattern[n]+(n == 0 ? -0.5 : 0.5));
+    }
+    length-=(maximum_length-total_length);
+    if ((n & 0x01) != 0)
+      continue;
+    dash_polygon[j]=primitive_info[i];
+    dash_polygon[j].coordinates=1;
+    j++;
+  }
+  if ((total_length < maximum_length) && ((n & 0x01) == 0) && (j > 1))
+    {
+      dash_polygon[j]=primitive_info[i-1];
+      dash_polygon[j].point.x+=MagickEpsilon;
+      dash_polygon[j].point.y+=MagickEpsilon;
+      dash_polygon[j].coordinates=1;
+      j++;
+      dash_polygon[0].coordinates=(size_t) j;
+      dash_polygon[j].primitive=UndefinedPrimitive;
+      status|=DrawStrokePolygon(image,clone_info,dash_polygon);
+    }
+  dash_polygon=(PrimitiveInfo *) RelinquishMagickMemory(dash_polygon);
+  clone_info=DestroyDrawInfo(clone_info);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end draw-dash");
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D r a w I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawImage() draws a graphic primitive on your image.  The primitive
+%  may be represented as a string or filename.  Precede the filename with an
+%  "at" sign (@) and the contents of the file are drawn on the image.  You
+%  can affect how text is drawn by setting one or more members of the draw
+%  info structure.
+%
+%  The format of the DrawImage method is:
+%
+%      MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+*/
+
+static inline MagickBooleanType IsPoint(const char *point)
+{
+  char
+    *p;
+
+  double
+    value;
+
+  value=InterpretLocaleValue(point,&p);
+  return((value == 0.0) && (p == point) ? MagickFalse : MagickTrue);
+}
+
+static inline void TracePoint(PrimitiveInfo *primitive_info,
+  const PointInfo point)
+{
+  primitive_info->coordinates=1;
+  primitive_info->point=point;
+}
+
+MagickExport MagickBooleanType DrawImage(Image *image,const DrawInfo *draw_info)
+{
+#define RenderImageTag  "Render/Image"
+
+  AffineMatrix
+    affine,
+    current;
+
+  char
+    key[2*MaxTextExtent],
+    keyword[MaxTextExtent],
+    geometry[MaxTextExtent],
+    name[MaxTextExtent],
+    pattern[MaxTextExtent],
+    *primitive,
+    *token;
+
+  const char
+    *q;
+
+  DrawInfo
+    **graphic_context;
+
+  MagickBooleanType
+    proceed,
+    status;
+
+  MagickRealType
+    angle,
+    factor,
+    primitive_extent;
+
+  PointInfo
+    point;
+
+  PixelPacket
+    start_color;
+
+  PrimitiveInfo
+    *primitive_info;
+
+  PrimitiveType
+    primitive_type;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  SegmentInfo
+    bounds;
+
+  size_t
+    length,
+    number_points;
+
+  ssize_t
+    j,
+    k,
+    n;
+
+  /*
+    Ensure the annotation info is valid.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if ((draw_info->primitive == (char *) NULL) ||
+      (*draw_info->primitive == '\0'))
+    return(MagickFalse);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"begin draw-image");
+  if (*draw_info->primitive != '@')
+    primitive=AcquireString(draw_info->primitive);
+  else
+    primitive=FileToString(draw_info->primitive+1,~0,&image->exception);
+  if (primitive == (char *) NULL)
+    return(MagickFalse);
+  primitive_extent=(MagickRealType) strlen(primitive);
+  (void) SetImageArtifact(image,"MVG",primitive);
+  n=0;
+  /*
+    Allocate primitive info memory.
+  */
+  graphic_context=(DrawInfo **) AcquireMagickMemory(
+    sizeof(*graphic_context));
+  if (graphic_context == (DrawInfo **) NULL)
+    {
+      primitive=DestroyString(primitive);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  number_points=2047;
+  primitive_info=(PrimitiveInfo *) AcquireQuantumMemory((size_t) number_points,
+    sizeof(*primitive_info));
+  if (primitive_info == (PrimitiveInfo *) NULL)
+    {
+      primitive=DestroyString(primitive);
+      for ( ; n >= 0; n--)
+        graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
+      graphic_context=(DrawInfo **) RelinquishMagickMemory(graphic_context);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  graphic_context[n]=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  graphic_context[n]->viewbox=image->page;
+  if ((image->page.width == 0) || (image->page.height == 0))
+    {
+      graphic_context[n]->viewbox.width=image->columns;
+      graphic_context[n]->viewbox.height=image->rows;
+    }
+  token=AcquireString(primitive);
+  (void) QueryColorDatabase("#000000",&start_color,&image->exception);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  for (q=primitive; *q != '\0'; )
+  {
+    /*
+      Interpret graphic primitive.
+    */
+    GetMagickToken(q,&q,keyword);
+    if (*keyword == '\0')
+      break;
+    if (*keyword == '#')
+      {
+        /*
+          Comment.
+        */
+        while ((*q != '\n') && (*q != '\0'))
+          q++;
+        continue;
+      }
+    p=q-strlen(keyword)-1;
+    primitive_type=UndefinedPrimitive;
+    current=graphic_context[n]->affine;
+    GetAffineMatrix(&affine);
+    switch (*keyword)
+    {
+      case ';':
+        break;
+      case 'a':
+      case 'A':
+      {
+        if (LocaleCompare("affine",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            affine.sx=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.rx=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.ry=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.sy=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.tx=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.ty=InterpretLocaleValue(token,(char **) NULL);
+            break;
+          }
+        if (LocaleCompare("arc",keyword) == 0)
+          {
+            primitive_type=ArcPrimitive;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'b':
+      case 'B':
+      {
+        if (LocaleCompare("bezier",keyword) == 0)
+          {
+            primitive_type=BezierPrimitive;
+            break;
+          }
+        if (LocaleCompare("border-color",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) QueryColorDatabase(token,&graphic_context[n]->border_color,
+              &image->exception);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'c':
+      case 'C':
+      {
+        if (LocaleCompare("clip-path",keyword) == 0)
+          {
+            /*
+              Create clip mask.
+            */
+            GetMagickToken(q,&q,token);
+            (void) CloneString(&graphic_context[n]->clip_mask,token);
+            (void) DrawClipPath(image,graphic_context[n],
+              graphic_context[n]->clip_mask);
+            break;
+          }
+        if (LocaleCompare("clip-rule",keyword) == 0)
+          {
+            ssize_t
+              fill_rule;
+
+            GetMagickToken(q,&q,token);
+            fill_rule=ParseCommandOption(MagickFillRuleOptions,MagickFalse,
+              token);
+            if (fill_rule == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->fill_rule=(FillRule) fill_rule;
+            break;
+          }
+        if (LocaleCompare("clip-units",keyword) == 0)
+          {
+            ssize_t
+              clip_units;
+
+            GetMagickToken(q,&q,token);
+            clip_units=ParseCommandOption(MagickClipPathOptions,MagickFalse,
+              token);
+            if (clip_units == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->clip_units=(ClipPathUnits) clip_units;
+            if (clip_units == ObjectBoundingBox)
+              {
+                GetAffineMatrix(&current);
+                affine.sx=draw_info->bounds.x2;
+                affine.sy=draw_info->bounds.y2;
+                affine.tx=draw_info->bounds.x1;
+                affine.ty=draw_info->bounds.y1;
+                break;
+              }
+            break;
+          }
+        if (LocaleCompare("circle",keyword) == 0)
+          {
+            primitive_type=CirclePrimitive;
+            break;
+          }
+        if (LocaleCompare("color",keyword) == 0)
+          {
+            primitive_type=ColorPrimitive;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'd':
+      case 'D':
+      {
+        if (LocaleCompare("decorate",keyword) == 0)
+          {
+            ssize_t
+              decorate;
+
+            GetMagickToken(q,&q,token);
+            decorate=ParseCommandOption(MagickDecorateOptions,MagickFalse,
+              token);
+            if (decorate == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->decorate=(DecorationType) decorate;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'e':
+      case 'E':
+      {
+        if (LocaleCompare("ellipse",keyword) == 0)
+          {
+            primitive_type=EllipsePrimitive;
+            break;
+          }
+        if (LocaleCompare("encoding",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) CloneString(&graphic_context[n]->encoding,token);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'f':
+      case 'F':
+      {
+        if (LocaleCompare("fill",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) FormatLocaleString(pattern,MaxTextExtent,"%s",token);
+            if (GetImageArtifact(image,pattern) != (const char *) NULL)
+              (void) DrawPatternPath(image,draw_info,token,
+                &graphic_context[n]->fill_pattern);
+            else
+              {
+                status=QueryColorDatabase(token,&graphic_context[n]->fill,
+                  &image->exception);
+                if (status == MagickFalse)
+                  {
+                    ImageInfo
+                      *pattern_info;
+
+                    pattern_info=AcquireImageInfo();
+                    (void) CopyMagickString(pattern_info->filename,token,
+                      MaxTextExtent);
+                    graphic_context[n]->fill_pattern=
+                      ReadImage(pattern_info,&image->exception);
+                    CatchException(&image->exception);
+                    pattern_info=DestroyImageInfo(pattern_info);
+                  }
+              }
+            break;
+          }
+        if (LocaleCompare("fill-opacity",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
+            graphic_context[n]->fill.alpha=ClampToQuantum((MagickRealType)
+              QuantumRange*(1.0-factor*InterpretLocaleValue(token,
+              (char **) NULL)));
+            break;
+          }
+        if (LocaleCompare("fill-rule",keyword) == 0)
+          {
+            ssize_t
+              fill_rule;
+
+            GetMagickToken(q,&q,token);
+            fill_rule=ParseCommandOption(MagickFillRuleOptions,MagickFalse,
+              token);
+            if (fill_rule == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->fill_rule=(FillRule) fill_rule;
+            break;
+          }
+        if (LocaleCompare("font",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) CloneString(&graphic_context[n]->font,token);
+            if (LocaleCompare("none",token) == 0)
+              graphic_context[n]->font=(char *)
+                RelinquishMagickMemory(graphic_context[n]->font);
+            break;
+          }
+        if (LocaleCompare("font-family",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) CloneString(&graphic_context[n]->family,token);
+            break;
+          }
+        if (LocaleCompare("font-size",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->pointsize=InterpretLocaleValue(token,
+              (char **) NULL);
+            break;
+          }
+        if (LocaleCompare("font-stretch",keyword) == 0)
+          {
+            ssize_t
+              stretch;
+
+            GetMagickToken(q,&q,token);
+            stretch=ParseCommandOption(MagickStretchOptions,MagickFalse,token);
+            if (stretch == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->stretch=(StretchType) stretch;
+            break;
+          }
+        if (LocaleCompare("font-style",keyword) == 0)
+          {
+            ssize_t
+              style;
+
+            GetMagickToken(q,&q,token);
+            style=ParseCommandOption(MagickStyleOptions,MagickFalse,token);
+            if (style == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->style=(StyleType) style;
+            break;
+          }
+        if (LocaleCompare("font-weight",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->weight=StringToUnsignedLong(token);
+            if (LocaleCompare(token,"all") == 0)
+              graphic_context[n]->weight=0;
+            if (LocaleCompare(token,"bold") == 0)
+              graphic_context[n]->weight=700;
+            if (LocaleCompare(token,"bolder") == 0)
+              if (graphic_context[n]->weight <= 800)
+                graphic_context[n]->weight+=100;
+            if (LocaleCompare(token,"lighter") == 0)
+              if (graphic_context[n]->weight >= 100)
+                graphic_context[n]->weight-=100;
+            if (LocaleCompare(token,"normal") == 0)
+              graphic_context[n]->weight=400;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'g':
+      case 'G':
+      {
+        if (LocaleCompare("gradient-units",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            break;
+          }
+        if (LocaleCompare("gravity",keyword) == 0)
+          {
+            ssize_t
+              gravity;
+
+            GetMagickToken(q,&q,token);
+            gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,token);
+            if (gravity == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->gravity=(GravityType) gravity;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'i':
+      case 'I':
+      {
+        if (LocaleCompare("image",keyword) == 0)
+          {
+            ssize_t
+              compose;
+
+            primitive_type=ImagePrimitive;
+            GetMagickToken(q,&q,token);
+            compose=ParseCommandOption(MagickComposeOptions,MagickFalse,token);
+            if (compose == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->compose=(CompositeOperator) compose;
+            break;
+          }
+        if (LocaleCompare("interline-spacing",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->interline_spacing=InterpretLocaleValue(token,
+              (char **) NULL);
+            break;
+          }
+        if (LocaleCompare("interword-spacing",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->interword_spacing=InterpretLocaleValue(token,
+              (char **) NULL);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'k':
+      case 'K':
+      {
+        if (LocaleCompare("kerning",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->kerning=InterpretLocaleValue(token,
+              (char **) NULL);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'l':
+      case 'L':
+      {
+        if (LocaleCompare("line",keyword) == 0)
+          {
+            primitive_type=LinePrimitive;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'm':
+      case 'M':
+      {
+        if (LocaleCompare("matte",keyword) == 0)
+          {
+            primitive_type=MattePrimitive;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'o':
+      case 'O':
+      {
+        if (LocaleCompare("offset",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            break;
+          }
+        if (LocaleCompare("opacity",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
+            graphic_context[n]->alpha=ClampToQuantum((MagickRealType)
+              QuantumRange*(1.0-((1.0-QuantumScale*graphic_context[n]->alpha)*
+              factor*InterpretLocaleValue(token,(char **) NULL))));
+            graphic_context[n]->fill.alpha=graphic_context[n]->alpha;
+            graphic_context[n]->stroke.alpha=graphic_context[n]->alpha;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'p':
+      case 'P':
+      {
+        if (LocaleCompare("path",keyword) == 0)
+          {
+            primitive_type=PathPrimitive;
+            break;
+          }
+        if (LocaleCompare("point",keyword) == 0)
+          {
+            primitive_type=PointPrimitive;
+            break;
+          }
+        if (LocaleCompare("polyline",keyword) == 0)
+          {
+            primitive_type=PolylinePrimitive;
+            break;
+          }
+        if (LocaleCompare("polygon",keyword) == 0)
+          {
+            primitive_type=PolygonPrimitive;
+            break;
+          }
+        if (LocaleCompare("pop",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            if (LocaleCompare("clip-path",token) == 0)
+              break;
+            if (LocaleCompare("defs",token) == 0)
+              break;
+            if (LocaleCompare("gradient",token) == 0)
+              break;
+            if (LocaleCompare("graphic-context",token) == 0)
+              {
+                if (n <= 0)
+                  {
+                    (void) ThrowMagickException(&image->exception,
+                      GetMagickModule(),DrawError,
+                      "UnbalancedGraphicContextPushPop","`%s'",token);
+                    n=0;
+                    break;
+                  }
+                if (graphic_context[n]->clip_mask != (char *) NULL)
+                  if (LocaleCompare(graphic_context[n]->clip_mask,
+                      graphic_context[n-1]->clip_mask) != 0)
+                    (void) SetImageClipMask(image,(Image *) NULL);
+                graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
+                n--;
+                break;
+              }
+            if (LocaleCompare("pattern",token) == 0)
+              break;
+            status=MagickFalse;
+            break;
+          }
+        if (LocaleCompare("push",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            if (LocaleCompare("clip-path",token) == 0)
+              {
+                char
+                  name[MaxTextExtent];
+
+                GetMagickToken(q,&q,token);
+                (void) FormatLocaleString(name,MaxTextExtent,"%s",token);
+                for (p=q; *q != '\0'; )
+                {
+                  GetMagickToken(q,&q,token);
+                  if (LocaleCompare(token,"pop") != 0)
+                    continue;
+                  GetMagickToken(q,(const char **) NULL,token);
+                  if (LocaleCompare(token,"clip-path") != 0)
+                    continue;
+                  break;
+                }
+                (void) CopyMagickString(token,p,(size_t) (q-p-4+1));
+                (void) SetImageArtifact(image,name,token);
+                GetMagickToken(q,&q,token);
+                break;
+              }
+            if (LocaleCompare("gradient",token) == 0)
+              {
+                char
+                  key[2*MaxTextExtent],
+                  name[MaxTextExtent],
+                  type[MaxTextExtent];
+
+                SegmentInfo
+                  segment;
+
+                GetMagickToken(q,&q,token);
+                (void) CopyMagickString(name,token,MaxTextExtent);
+                GetMagickToken(q,&q,token);
+                (void) CopyMagickString(type,token,MaxTextExtent);
+                GetMagickToken(q,&q,token);
+                segment.x1=InterpretLocaleValue(token,(char **) NULL);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                segment.y1=InterpretLocaleValue(token,(char **) NULL);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                segment.x2=InterpretLocaleValue(token,(char **) NULL);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                segment.y2=InterpretLocaleValue(token,(char **) NULL);
+                if (LocaleCompare(type,"radial") == 0)
+                  {
+                    GetMagickToken(q,&q,token);
+                    if (*token == ',')
+                      GetMagickToken(q,&q,token);
+                  }
+                for (p=q; *q != '\0'; )
+                {
+                  GetMagickToken(q,&q,token);
+                  if (LocaleCompare(token,"pop") != 0)
+                    continue;
+                  GetMagickToken(q,(const char **) NULL,token);
+                  if (LocaleCompare(token,"gradient") != 0)
+                    continue;
+                  break;
+                }
+                (void) CopyMagickString(token,p,(size_t) (q-p-4+1));
+                bounds.x1=graphic_context[n]->affine.sx*segment.x1+
+                  graphic_context[n]->affine.ry*segment.y1+
+                  graphic_context[n]->affine.tx;
+                bounds.y1=graphic_context[n]->affine.rx*segment.x1+
+                  graphic_context[n]->affine.sy*segment.y1+
+                  graphic_context[n]->affine.ty;
+                bounds.x2=graphic_context[n]->affine.sx*segment.x2+
+                  graphic_context[n]->affine.ry*segment.y2+
+                  graphic_context[n]->affine.tx;
+                bounds.y2=graphic_context[n]->affine.rx*segment.x2+
+                  graphic_context[n]->affine.sy*segment.y2+
+                  graphic_context[n]->affine.ty;
+                (void) FormatLocaleString(key,MaxTextExtent,"%s",name);
+                (void) SetImageArtifact(image,key,token);
+                (void) FormatLocaleString(key,MaxTextExtent,"%s-geometry",name);
+                (void) FormatLocaleString(geometry,MaxTextExtent,
+                  "%gx%g%+.15g%+.15g",
+                  MagickMax(fabs(bounds.x2-bounds.x1+1.0),1.0),
+                  MagickMax(fabs(bounds.y2-bounds.y1+1.0),1.0),
+                  bounds.x1,bounds.y1);
+                (void) SetImageArtifact(image,key,geometry);
+                GetMagickToken(q,&q,token);
+                break;
+              }
+            if (LocaleCompare("pattern",token) == 0)
+              {
+                RectangleInfo
+                  bounds;
+
+                GetMagickToken(q,&q,token);
+                (void) CopyMagickString(name,token,MaxTextExtent);
+                GetMagickToken(q,&q,token);
+                bounds.x=(ssize_t) ceil(InterpretLocaleValue(token,
+                  (char **) NULL)-0.5);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                bounds.y=(ssize_t) ceil(InterpretLocaleValue(token,
+                  (char **) NULL)-0.5);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                bounds.width=(size_t) floor(InterpretLocaleValue(token,
+                  (char **) NULL)+0.5);
+                GetMagickToken(q,&q,token);
+                if (*token == ',')
+                  GetMagickToken(q,&q,token);
+                bounds.height=(size_t) floor(InterpretLocaleValue(token,
+                  (char **) NULL)+0.5);
+                for (p=q; *q != '\0'; )
+                {
+                  GetMagickToken(q,&q,token);
+                  if (LocaleCompare(token,"pop") != 0)
+                    continue;
+                  GetMagickToken(q,(const char **) NULL,token);
+                  if (LocaleCompare(token,"pattern") != 0)
+                    continue;
+                  break;
+                }
+                (void) CopyMagickString(token,p,(size_t) (q-p-4+1));
+                (void) FormatLocaleString(key,MaxTextExtent,"%s",name);
+                (void) SetImageArtifact(image,key,token);
+                (void) FormatLocaleString(key,MaxTextExtent,"%s-geometry",name);
+                (void) FormatLocaleString(geometry,MaxTextExtent,
+                  "%.20gx%.20g%+.20g%+.20g",(double) bounds.width,(double)
+                  bounds.height,(double) bounds.x,(double) bounds.y);
+                (void) SetImageArtifact(image,key,geometry);
+                GetMagickToken(q,&q,token);
+                break;
+              }
+            if (LocaleCompare("graphic-context",token) == 0)
+              {
+                n++;
+                graphic_context=(DrawInfo **) ResizeQuantumMemory(
+                  graphic_context,(size_t) (n+1),sizeof(*graphic_context));
+                if (graphic_context == (DrawInfo **) NULL)
+                  {
+                    (void) ThrowMagickException(&image->exception,
+                      GetMagickModule(),ResourceLimitError,
+                      "MemoryAllocationFailed","`%s'",image->filename);
+                    break;
+                  }
+                graphic_context[n]=CloneDrawInfo((ImageInfo *) NULL,
+                  graphic_context[n-1]);
+                break;
+              }
+            if (LocaleCompare("defs",token) == 0)
+              break;
+            status=MagickFalse;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'r':
+      case 'R':
+      {
+        if (LocaleCompare("rectangle",keyword) == 0)
+          {
+            primitive_type=RectanglePrimitive;
+            break;
+          }
+        if (LocaleCompare("rotate",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            angle=InterpretLocaleValue(token,(char **) NULL);
+            affine.sx=cos(DegreesToRadians(fmod((double) angle,360.0)));
+            affine.rx=sin(DegreesToRadians(fmod((double) angle,360.0)));
+            affine.ry=(-sin(DegreesToRadians(fmod((double) angle,360.0))));
+            affine.sy=cos(DegreesToRadians(fmod((double) angle,360.0)));
+            break;
+          }
+        if (LocaleCompare("roundRectangle",keyword) == 0)
+          {
+            primitive_type=RoundRectanglePrimitive;
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 's':
+      case 'S':
+      {
+        if (LocaleCompare("scale",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            affine.sx=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.sy=InterpretLocaleValue(token,(char **) NULL);
+            break;
+          }
+        if (LocaleCompare("skewX",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            angle=InterpretLocaleValue(token,(char **) NULL);
+            affine.ry=sin(DegreesToRadians(angle));
+            break;
+          }
+        if (LocaleCompare("skewY",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            angle=InterpretLocaleValue(token,(char **) NULL);
+            affine.rx=(-tan(DegreesToRadians(angle)/2.0));
+            break;
+          }
+        if (LocaleCompare("stop-color",keyword) == 0)
+          {
+            PixelPacket
+              stop_color;
+
+            GetMagickToken(q,&q,token);
+            (void) QueryColorDatabase(token,&stop_color,&image->exception);
+            (void) GradientImage(image,LinearGradient,ReflectSpread,
+              &start_color,&stop_color);
+            start_color=stop_color;
+            GetMagickToken(q,&q,token);
+            break;
+          }
+        if (LocaleCompare("stroke",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) FormatLocaleString(pattern,MaxTextExtent,"%s",token);
+            if (GetImageArtifact(image,pattern) != (const char *) NULL)
+              (void) DrawPatternPath(image,draw_info,token,
+                &graphic_context[n]->stroke_pattern);
+            else
+              {
+                status=QueryColorDatabase(token,&graphic_context[n]->stroke,
+                  &image->exception);
+                if (status == MagickFalse)
+                  {
+                    ImageInfo
+                      *pattern_info;
+
+                    pattern_info=AcquireImageInfo();
+                    (void) CopyMagickString(pattern_info->filename,token,
+                      MaxTextExtent);
+                    graphic_context[n]->stroke_pattern=
+                      ReadImage(pattern_info,&image->exception);
+                    CatchException(&image->exception);
+                    pattern_info=DestroyImageInfo(pattern_info);
+                  }
+              }
+            break;
+          }
+        if (LocaleCompare("stroke-antialias",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->stroke_antialias=
+              StringToLong(token) != 0 ? MagickTrue : MagickFalse;
+            break;
+          }
+        if (LocaleCompare("stroke-dasharray",keyword) == 0)
+          {
+            if (graphic_context[n]->dash_pattern != (double *) NULL)
+              graphic_context[n]->dash_pattern=(double *)
+                RelinquishMagickMemory(graphic_context[n]->dash_pattern);
+            if (IsPoint(q) != MagickFalse)
+              {
+                const char
+                  *p;
+
+                p=q;
+                GetMagickToken(p,&p,token);
+                if (*token == ',')
+                  GetMagickToken(p,&p,token);
+                for (x=0; IsPoint(token) != MagickFalse; x++)
+                {
+                  GetMagickToken(p,&p,token);
+                  if (*token == ',')
+                    GetMagickToken(p,&p,token);
+                }
+                graphic_context[n]->dash_pattern=(double *)
+                  AcquireQuantumMemory((size_t) (2UL*x+1UL),
+                  sizeof(*graphic_context[n]->dash_pattern));
+                if (graphic_context[n]->dash_pattern == (double *) NULL)
+                  {
+                    (void) ThrowMagickException(&image->exception,
+                      GetMagickModule(),ResourceLimitError,
+                      "MemoryAllocationFailed","`%s'",image->filename);
+                    break;
+                  }
+                for (j=0; j < x; j++)
+                {
+                  GetMagickToken(q,&q,token);
+                  if (*token == ',')
+                    GetMagickToken(q,&q,token);
+                  graphic_context[n]->dash_pattern[j]=InterpretLocaleValue(
+                    token,(char **) NULL);
+                }
+                if ((x & 0x01) != 0)
+                  for ( ; j < (2*x); j++)
+                    graphic_context[n]->dash_pattern[j]=
+                      graphic_context[n]->dash_pattern[j-x];
+                graphic_context[n]->dash_pattern[j]=0.0;
+                break;
+              }
+            GetMagickToken(q,&q,token);
+            break;
+          }
+        if (LocaleCompare("stroke-dashoffset",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->dash_offset=InterpretLocaleValue(token,
+              (char **) NULL);
+            break;
+          }
+        if (LocaleCompare("stroke-linecap",keyword) == 0)
+          {
+            ssize_t
+              linecap;
+
+            GetMagickToken(q,&q,token);
+            linecap=ParseCommandOption(MagickLineCapOptions,MagickFalse,token);
+            if (linecap == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->linecap=(LineCap) linecap;
+            break;
+          }
+        if (LocaleCompare("stroke-linejoin",keyword) == 0)
+          {
+            ssize_t
+              linejoin;
+
+            GetMagickToken(q,&q,token);
+            linejoin=ParseCommandOption(MagickLineJoinOptions,MagickFalse,token);
+            if (linejoin == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->linejoin=(LineJoin) linejoin;
+            break;
+          }
+        if (LocaleCompare("stroke-miterlimit",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->miterlimit=StringToUnsignedLong(token);
+            break;
+          }
+        if (LocaleCompare("stroke-opacity",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            factor=strchr(token,'%') != (char *) NULL ? 0.01 : 1.0;
+            graphic_context[n]->stroke.alpha=ClampToQuantum((MagickRealType)
+              QuantumRange*(1.0-factor*InterpretLocaleValue(token,
+              (char **) NULL)));
+            break;
+          }
+        if (LocaleCompare("stroke-width",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->stroke_width=InterpretLocaleValue(token,
+              (char **) NULL);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 't':
+      case 'T':
+      {
+        if (LocaleCompare("text",keyword) == 0)
+          {
+            primitive_type=TextPrimitive;
+            break;
+          }
+        if (LocaleCompare("text-align",keyword) == 0)
+          {
+            ssize_t
+              align;
+
+            GetMagickToken(q,&q,token);
+            align=ParseCommandOption(MagickAlignOptions,MagickFalse,token);
+            if (align == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->align=(AlignType) align;
+            break;
+          }
+        if (LocaleCompare("text-anchor",keyword) == 0)
+          {
+            ssize_t
+              align;
+
+            GetMagickToken(q,&q,token);
+            align=ParseCommandOption(MagickAlignOptions,MagickFalse,token);
+            if (align == -1)
+              {
+                status=MagickFalse;
+                break;
+              }
+            graphic_context[n]->align=(AlignType) align;
+            break;
+          }
+        if (LocaleCompare("text-antialias",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->text_antialias=
+              StringToLong(token) != 0 ? MagickTrue : MagickFalse;
+            break;
+          }
+        if (LocaleCompare("text-undercolor",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            (void) QueryColorDatabase(token,&graphic_context[n]->undercolor,
+              &image->exception);
+            break;
+          }
+        if (LocaleCompare("translate",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            affine.tx=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            affine.ty=InterpretLocaleValue(token,(char **) NULL);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      case 'v':
+      case 'V':
+      {
+        if (LocaleCompare("viewbox",keyword) == 0)
+          {
+            GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.x=(ssize_t) ceil(InterpretLocaleValue(
+              token,(char **) NULL)-0.5);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.y=(ssize_t) ceil(InterpretLocaleValue(
+              token,(char **) NULL)-0.5);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.width=(size_t) floor(
+              InterpretLocaleValue(token,(char **) NULL)+0.5);
+            GetMagickToken(q,&q,token);
+            if (*token == ',')
+              GetMagickToken(q,&q,token);
+            graphic_context[n]->viewbox.height=(size_t) floor(
+              InterpretLocaleValue(token,(char **) NULL)+0.5);
+            break;
+          }
+        status=MagickFalse;
+        break;
+      }
+      default:
+      {
+        status=MagickFalse;
+        break;
+      }
+    }
+    if (status == MagickFalse)
+      break;
+    if ((affine.sx != 1.0) || (affine.rx != 0.0) || (affine.ry != 0.0) ||
+        (affine.sy != 1.0) || (affine.tx != 0.0) || (affine.ty != 0.0))
+      {
+        graphic_context[n]->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
+        graphic_context[n]->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
+        graphic_context[n]->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
+        graphic_context[n]->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
+        graphic_context[n]->affine.tx=current.sx*affine.tx+current.ry*affine.ty+
+          current.tx;
+        graphic_context[n]->affine.ty=current.rx*affine.tx+current.sy*affine.ty+
+          current.ty;
+      }
+    if (primitive_type == UndefinedPrimitive)
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(DrawEvent,GetMagickModule(),"  %.*s",
+            (int) (q-p),p);
+        continue;
+      }
+    /*
+      Parse the primitive attributes.
+    */
+    i=0;
+    j=0;
+    primitive_info[0].point.x=0.0;
+    primitive_info[0].point.y=0.0;
+    for (x=0; *q != '\0'; x++)
+    {
+      /*
+        Define points.
+      */
+      if (IsPoint(q) == MagickFalse)
+        break;
+      GetMagickToken(q,&q,token);
+      point.x=InterpretLocaleValue(token,(char **) NULL);
+      GetMagickToken(q,&q,token);
+      if (*token == ',')
+        GetMagickToken(q,&q,token);
+      point.y=InterpretLocaleValue(token,(char **) NULL);
+      GetMagickToken(q,(const char **) NULL,token);
+      if (*token == ',')
+        GetMagickToken(q,&q,token);
+      primitive_info[i].primitive=primitive_type;
+      primitive_info[i].point=point;
+      primitive_info[i].coordinates=0;
+      primitive_info[i].method=FloodfillMethod;
+      i++;
+      if (i < (ssize_t) number_points)
+        continue;
+      number_points<<=1;
+      primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
+        (size_t) number_points,sizeof(*primitive_info));
+      if (primitive_info == (PrimitiveInfo *) NULL)
+        {
+          (void) ThrowMagickException(&image->exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+          break;
+        }
+    }
+    primitive_info[j].primitive=primitive_type;
+    primitive_info[j].coordinates=(size_t) x;
+    primitive_info[j].method=FloodfillMethod;
+    primitive_info[j].text=(char *) NULL;
+    /*
+      Circumscribe primitive within a circle.
+    */
+    bounds.x1=primitive_info[j].point.x;
+    bounds.y1=primitive_info[j].point.y;
+    bounds.x2=primitive_info[j].point.x;
+    bounds.y2=primitive_info[j].point.y;
+    for (k=1; k < (ssize_t) primitive_info[j].coordinates; k++)
+    {
+      point=primitive_info[j+k].point;
+      if (point.x < bounds.x1)
+        bounds.x1=point.x;
+      if (point.y < bounds.y1)
+        bounds.y1=point.y;
+      if (point.x > bounds.x2)
+        bounds.x2=point.x;
+      if (point.y > bounds.y2)
+        bounds.y2=point.y;
+    }
+    /*
+      Speculate how many points our primitive might consume.
+    */
+    length=primitive_info[j].coordinates;
+    switch (primitive_type)
+    {
+      case RectanglePrimitive:
+      {
+        length*=5;
+        break;
+      }
+      case RoundRectanglePrimitive:
+      {
+        length*=5+8*BezierQuantum;
+        break;
+      }
+      case BezierPrimitive:
+      {
+        if (primitive_info[j].coordinates > 107)
+          (void) ThrowMagickException(&image->exception,GetMagickModule(),
+            DrawError,"TooManyBezierCoordinates","`%s'",token);
+        length=BezierQuantum*primitive_info[j].coordinates;
+        break;
+      }
+      case PathPrimitive:
+      {
+        char
+          *s,
+          *t;
+
+        GetMagickToken(q,&q,token);
+        length=1;
+        t=token;
+        for (s=token; *s != '\0'; s=t)
+        {
+          double
+            value;
+
+          value=InterpretLocaleValue(s,&t);
+          (void) value;
+          if (s == t)
+            {
+              t++;
+              continue;
+            }
+          length++;
+        }
+        length=length*BezierQuantum/2;
+        break;
+      }
+      case CirclePrimitive:
+      case ArcPrimitive:
+      case EllipsePrimitive:
+      {
+        MagickRealType
+          alpha,
+          beta,
+          radius;
+
+        alpha=bounds.x2-bounds.x1;
+        beta=bounds.y2-bounds.y1;
+        radius=hypot((double) alpha,(double) beta);
+        length=2*((size_t) ceil((double) MagickPI*radius))+6*BezierQuantum+360;
+        break;
+      }
+      default:
+        break;
+    }
+    if ((size_t) (i+length) >= number_points)
+      {
+        /*
+          Resize based on speculative points required by primitive.
+        */
+        number_points+=length+1;
+        primitive_info=(PrimitiveInfo *) ResizeQuantumMemory(primitive_info,
+          (size_t) number_points,sizeof(*primitive_info));
+        if (primitive_info == (PrimitiveInfo *) NULL)
+          {
+            (void) ThrowMagickException(&image->exception,GetMagickModule(),
+              ResourceLimitError,"MemoryAllocationFailed","`%s'",
+              image->filename);
+            break;
+          }
+      }
+    switch (primitive_type)
+    {
+      case PointPrimitive:
+      default:
+      {
+        if (primitive_info[j].coordinates != 1)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TracePoint(primitive_info+j,primitive_info[j].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case LinePrimitive:
+      {
+        if (primitive_info[j].coordinates != 2)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TraceLine(primitive_info+j,primitive_info[j].point,
+          primitive_info[j+1].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case RectanglePrimitive:
+      {
+        if (primitive_info[j].coordinates != 2)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TraceRectangle(primitive_info+j,primitive_info[j].point,
+          primitive_info[j+1].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case RoundRectanglePrimitive:
+      {
+        if (primitive_info[j].coordinates != 3)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TraceRoundRectangle(primitive_info+j,primitive_info[j].point,
+          primitive_info[j+1].point,primitive_info[j+2].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case ArcPrimitive:
+      {
+        if (primitive_info[j].coordinates != 3)
+          {
+            primitive_type=UndefinedPrimitive;
+            break;
+          }
+        TraceArc(primitive_info+j,primitive_info[j].point,
+          primitive_info[j+1].point,primitive_info[j+2].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case EllipsePrimitive:
+      {
+        if (primitive_info[j].coordinates != 3)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TraceEllipse(primitive_info+j,primitive_info[j].point,
+          primitive_info[j+1].point,primitive_info[j+2].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case CirclePrimitive:
+      {
+        if (primitive_info[j].coordinates != 2)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TraceCircle(primitive_info+j,primitive_info[j].point,
+          primitive_info[j+1].point);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case PolylinePrimitive:
+        break;
+      case PolygonPrimitive:
+      {
+        primitive_info[i]=primitive_info[j];
+        primitive_info[i].coordinates=0;
+        primitive_info[j].coordinates++;
+        i++;
+        break;
+      }
+      case BezierPrimitive:
+      {
+        if (primitive_info[j].coordinates < 3)
+          {
+            status=MagickFalse;
+            break;
+          }
+        TraceBezier(primitive_info+j,primitive_info[j].coordinates);
+        i=(ssize_t) (j+primitive_info[j].coordinates);
+        break;
+      }
+      case PathPrimitive:
+      {
+        i=(ssize_t) (j+TracePath(primitive_info+j,token));
+        break;
+      }
+      case ColorPrimitive:
+      case MattePrimitive:
+      {
+        ssize_t
+          method;
+
+        if (primitive_info[j].coordinates != 1)
+          {
+            status=MagickFalse;
+            break;
+          }
+        GetMagickToken(q,&q,token);
+        method=ParseCommandOption(MagickMethodOptions,MagickFalse,token);
+        if (method == -1)
+          {
+            status=MagickFalse;
+            break;
+          }
+        primitive_info[j].method=(PaintMethod) method;
+        break;
+      }
+      case TextPrimitive:
+      {
+        if (primitive_info[j].coordinates != 1)
+          {
+            status=MagickFalse;
+            break;
+          }
+        if (*token != ',')
+          GetMagickToken(q,&q,token);
+        primitive_info[j].text=AcquireString(token);
+        break;
+      }
+      case ImagePrimitive:
+      {
+        if (primitive_info[j].coordinates != 2)
+          {
+            status=MagickFalse;
+            break;
+          }
+        GetMagickToken(q,&q,token);
+        primitive_info[j].text=AcquireString(token);
+        break;
+      }
+    }
+    if (primitive_info == (PrimitiveInfo *) NULL)
+      break;
+    if (image->debug != MagickFalse)
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),"  %.*s",(int) (q-p),p);
+    if (status == MagickFalse)
+      break;
+    primitive_info[i].primitive=UndefinedPrimitive;
+    if (i == 0)
+      continue;
+    /*
+      Transform points.
+    */
+    for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
+    {
+      point=primitive_info[i].point;
+      primitive_info[i].point.x=graphic_context[n]->affine.sx*point.x+
+        graphic_context[n]->affine.ry*point.y+graphic_context[n]->affine.tx;
+      primitive_info[i].point.y=graphic_context[n]->affine.rx*point.x+
+        graphic_context[n]->affine.sy*point.y+graphic_context[n]->affine.ty;
+      point=primitive_info[i].point;
+      if (point.x < graphic_context[n]->bounds.x1)
+        graphic_context[n]->bounds.x1=point.x;
+      if (point.y < graphic_context[n]->bounds.y1)
+        graphic_context[n]->bounds.y1=point.y;
+      if (point.x > graphic_context[n]->bounds.x2)
+        graphic_context[n]->bounds.x2=point.x;
+      if (point.y > graphic_context[n]->bounds.y2)
+        graphic_context[n]->bounds.y2=point.y;
+      if (primitive_info[i].primitive == ImagePrimitive)
+        break;
+      if (i >= (ssize_t) number_points)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+    }
+    if (graphic_context[n]->render != MagickFalse)
+      {
+        if ((n != 0) && (graphic_context[n]->clip_mask != (char *) NULL) &&
+            (LocaleCompare(graphic_context[n]->clip_mask,
+             graphic_context[n-1]->clip_mask) != 0))
+          (void) DrawClipPath(image,graphic_context[n],
+            graphic_context[n]->clip_mask);
+        (void) DrawPrimitive(image,graphic_context[n],primitive_info);
+      }
+    if (primitive_info->text != (char *) NULL)
+      primitive_info->text=(char *) RelinquishMagickMemory(
+        primitive_info->text);
+    proceed=SetImageProgress(image,RenderImageTag,q-primitive,(MagickSizeType)
+      primitive_extent);
+    if (proceed == MagickFalse)
+      break;
+  }
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end draw-image");
+  /*
+    Relinquish resources.
+  */
+  token=DestroyString(token);
+  if (primitive_info != (PrimitiveInfo *) NULL)
+    primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
+  primitive=DestroyString(primitive);
+  for ( ; n >= 0; n--)
+    graphic_context[n]=DestroyDrawInfo(graphic_context[n]);
+  graphic_context=(DrawInfo **) RelinquishMagickMemory(graphic_context);
+  if (status == MagickFalse)
+    ThrowBinaryException(DrawError,"NonconformingDrawingPrimitiveDefinition",
+      keyword);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D r a w G r a d i e n t I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawGradientImage() draws a linear gradient on the image.
+%
+%  The format of the DrawGradientImage method is:
+%
+%      MagickBooleanType DrawGradientImage(Image *image,
+%        const DrawInfo *draw_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o _info: the draw info.
+%
+*/
+
+static inline MagickRealType GetStopColorOffset(const GradientInfo *gradient,
+  const ssize_t x,const ssize_t y)
+{
+  switch (gradient->type)
+  {
+    case UndefinedGradient:
+    case LinearGradient:
+    {
+      MagickRealType
+        gamma,
+        length,
+        offset,
+        scale;
+
+      PointInfo
+        p,
+        q;
+
+      const SegmentInfo
+        *gradient_vector;
+
+      gradient_vector=(&gradient->gradient_vector);
+      p.x=gradient_vector->x2-gradient_vector->x1;
+      p.y=gradient_vector->y2-gradient_vector->y1;
+      q.x=(double) x-gradient_vector->x1;
+      q.y=(double) y-gradient_vector->y1;
+      length=sqrt(q.x*q.x+q.y*q.y);
+      gamma=sqrt(p.x*p.x+p.y*p.y)*length;
+      gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+      scale=p.x*q.x+p.y*q.y;
+      offset=gamma*scale*length;
+      return(offset);
+    }
+    case RadialGradient:
+    {
+      MagickRealType
+        length,
+        offset;
+
+      PointInfo
+        v;
+
+      v.x=(double) x-gradient->center.x;
+      v.y=(double) y-gradient->center.y;
+      length=sqrt(v.x*v.x+v.y*v.y);
+      if (gradient->spread == RepeatSpread)
+        return(length);
+      offset=length/gradient->radius;
+      return(offset);
+    }
+  }
+  return(0.0);
+}
+
+MagickExport MagickBooleanType DrawGradientImage(Image *image,
+  const DrawInfo *draw_info)
+{
+  CacheView
+    *image_view;
+
+  const GradientInfo
+    *gradient;
+
+  const SegmentInfo
+    *gradient_vector;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    length;
+
+  PointInfo
+    point;
+
+  RectangleInfo
+    bounding_box;
+
+  ssize_t
+    y;
+
+  /*
+    Draw linear or radial gradient on image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (const DrawInfo *) NULL);
+  gradient=(&draw_info->gradient);
+  gradient_vector=(&gradient->gradient_vector);
+  point.x=gradient_vector->x2-gradient_vector->x1;
+  point.y=gradient_vector->y2-gradient_vector->y1;
+  length=sqrt(point.x*point.x+point.y*point.y);
+  bounding_box=gradient->bounding_box;
+  status=MagickTrue;
+  exception=(&image->exception);
+  GetPixelInfo(image,&zero);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=bounding_box.y; y < (ssize_t) bounding_box.height; y++)
+  {
+    PixelInfo
+      composite,
+      pixel;
+
+    MagickRealType
+      alpha,
+      offset;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      i,
+      x;
+
+    ssize_t
+      j;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    composite=zero;
+    offset=GetStopColorOffset(gradient,0,y);
+    if (gradient->type != RadialGradient)
+      offset/=length;
+    for (x=bounding_box.x; x < (ssize_t) bounding_box.width; x++)
+    {
+      SetPixelInfo(image,q,&pixel);
+      switch (gradient->spread)
+      {
+        case UndefinedSpread:
+        case PadSpread:
+        {
+          if ((x != (ssize_t) ceil(gradient_vector->x1-0.5)) ||
+              (y != (ssize_t) ceil(gradient_vector->y1-0.5)))
+            {
+              offset=GetStopColorOffset(gradient,x,y);
+              if (gradient->type != RadialGradient)
+                offset/=length;
+            }
+          for (i=0; i < (ssize_t) gradient->number_stops; i++)
+            if (offset < gradient->stops[i].offset)
+              break;
+          if ((offset < 0.0) || (i == 0))
+            composite=gradient->stops[0].color;
+          else
+            if ((offset > 1.0) || (i == (ssize_t) gradient->number_stops))
+              composite=gradient->stops[gradient->number_stops-1].color;
+            else
+              {
+                j=i;
+                i--;
+                alpha=(offset-gradient->stops[i].offset)/
+                  (gradient->stops[j].offset-gradient->stops[i].offset);
+                CompositePixelInfoBlend(&gradient->stops[i].color,1.0-alpha,
+                  &gradient->stops[j].color,alpha,&composite);
+              }
+          break;
+        }
+        case ReflectSpread:
+        {
+          if ((x != (ssize_t) ceil(gradient_vector->x1-0.5)) ||
+              (y != (ssize_t) ceil(gradient_vector->y1-0.5)))
+            {
+              offset=GetStopColorOffset(gradient,x,y);
+              if (gradient->type != RadialGradient)
+                offset/=length;
+            }
+          if (offset < 0.0)
+            offset=(-offset);
+          if ((ssize_t) fmod(offset,2.0) == 0)
+            offset=fmod(offset,1.0);
+          else
+            offset=1.0-fmod(offset,1.0);
+          for (i=0; i < (ssize_t) gradient->number_stops; i++)
+            if (offset < gradient->stops[i].offset)
+              break;
+          if (i == 0)
+            composite=gradient->stops[0].color;
+          else
+            if (i == (ssize_t) gradient->number_stops)
+              composite=gradient->stops[gradient->number_stops-1].color;
+            else
+              {
+                j=i;
+                i--;
+                alpha=(offset-gradient->stops[i].offset)/
+                  (gradient->stops[j].offset-gradient->stops[i].offset);
+                CompositePixelInfoBlend(&gradient->stops[i].color,1.0-alpha,
+                  &gradient->stops[j].color,alpha,&composite);
+              }
+          break;
+        }
+        case RepeatSpread:
+        {
+          MagickBooleanType
+            antialias;
+
+          MagickRealType
+            repeat;
+
+          antialias=MagickFalse;
+          repeat=0.0;
+          if ((x != (ssize_t) ceil(gradient_vector->x1-0.5)) ||
+              (y != (ssize_t) ceil(gradient_vector->y1-0.5)))
+            {
+              offset=GetStopColorOffset(gradient,x,y);
+              if (gradient->type == LinearGradient)
+                {
+                  repeat=fmod(offset,length);
+                  if (repeat < 0.0)
+                    repeat=length-fmod(-repeat,length);
+                  else
+                    repeat=fmod(offset,length);
+                  antialias=(repeat < length) && ((repeat+1.0) > length) ?
+                    MagickTrue : MagickFalse;
+                  offset=repeat/length;
+                }
+              else
+                {
+                  repeat=fmod(offset,gradient->radius);
+                  if (repeat < 0.0)
+                    repeat=gradient->radius-fmod(-repeat,gradient->radius);
+                  else
+                    repeat=fmod(offset,gradient->radius);
+                  antialias=repeat+1.0 > gradient->radius ? MagickTrue :
+                    MagickFalse;
+                  offset=repeat/gradient->radius;
+                }
+            }
+          for (i=0; i < (ssize_t) gradient->number_stops; i++)
+            if (offset < gradient->stops[i].offset)
+              break;
+          if (i == 0)
+            composite=gradient->stops[0].color;
+          else
+            if (i == (ssize_t) gradient->number_stops)
+              composite=gradient->stops[gradient->number_stops-1].color;
+            else
+              {
+                j=i;
+                i--;
+                alpha=(offset-gradient->stops[i].offset)/
+                  (gradient->stops[j].offset-gradient->stops[i].offset);
+                if (antialias != MagickFalse)
+                  {
+                    if (gradient->type == LinearGradient)
+                      alpha=length-repeat;
+                    else
+                      alpha=gradient->radius-repeat;
+                    i=0;
+                    j=(ssize_t) gradient->number_stops-1L;
+                  }
+                CompositePixelInfoBlend(&gradient->stops[i].color,1.0-alpha,
+                  &gradient->stops[j].color,alpha,&composite);
+              }
+          break;
+        }
+      }
+      CompositePixelInfoOver(&composite,composite.alpha,&pixel,pixel.alpha,
+        &pixel);
+      SetPixelPixelInfo(image,&pixel,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D r a w P a t t e r n P a t h                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawPatternPath() draws a pattern.
+%
+%  The format of the DrawPatternPath method is:
+%
+%      MagickBooleanType DrawPatternPath(Image *image,const DrawInfo *draw_info,
+%        const char *name,Image **pattern)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o name: the pattern name.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType DrawPatternPath(Image *image,
+  const DrawInfo *draw_info,const char *name,Image **pattern)
+{
+  char
+    property[MaxTextExtent];
+
+  const char
+    *geometry,
+    *path;
+
+  DrawInfo
+    *clone_info;
+
+  ImageInfo
+    *image_info;
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (const DrawInfo *) NULL);
+  assert(name != (const char *) NULL);
+  (void) FormatLocaleString(property,MaxTextExtent,"%s",name);
+  path=GetImageArtifact(image,property);
+  if (path == (const char *) NULL)
+    return(MagickFalse);
+  (void) FormatLocaleString(property,MaxTextExtent,"%s-geometry",name);
+  geometry=GetImageArtifact(image,property);
+  if (geometry == (const char *) NULL)
+    return(MagickFalse);
+  if ((*pattern) != (Image *) NULL)
+    *pattern=DestroyImage(*pattern);
+  image_info=AcquireImageInfo();
+  image_info->size=AcquireString(geometry);
+  *pattern=AcquireImage(image_info);
+  image_info=DestroyImageInfo(image_info);
+  (void) QueryColorDatabase("#00000000",&(*pattern)->background_color,
+    &image->exception);
+  (void) SetImageBackgroundColor(*pattern);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+      "begin pattern-path %s %s",name,geometry);
+  clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  clone_info->fill_pattern=NewImageList();
+  clone_info->stroke_pattern=NewImageList();
+  (void) CloneString(&clone_info->primitive,path);
+  status=DrawImage(*pattern,clone_info);
+  clone_info=DestroyDrawInfo(clone_info);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"end pattern-path");
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D r a w P o l y g o n P r i m i t i v e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawPolygonPrimitive() draws a polygon on the image.
+%
+%  The format of the DrawPolygonPrimitive method is:
+%
+%      MagickBooleanType DrawPolygonPrimitive(Image *image,
+%        const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
+%
+*/
+
+static PolygonInfo **DestroyPolygonThreadSet(PolygonInfo **polygon_info)
+{
+  register ssize_t
+    i;
+
+  assert(polygon_info != (PolygonInfo **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (polygon_info[i] != (PolygonInfo *) NULL)
+      polygon_info[i]=DestroyPolygonInfo(polygon_info[i]);
+  polygon_info=(PolygonInfo **) RelinquishMagickMemory(polygon_info);
+  return(polygon_info);
+}
+
+static PolygonInfo **AcquirePolygonThreadSet(const DrawInfo *draw_info,
+  const PrimitiveInfo *primitive_info)
+{
+  PathInfo
+    *restrict path_info;
+
+  PolygonInfo
+    **polygon_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  polygon_info=(PolygonInfo **) AcquireQuantumMemory(number_threads,
+    sizeof(*polygon_info));
+  if (polygon_info == (PolygonInfo **) NULL)
+    return((PolygonInfo **) NULL);
+  (void) ResetMagickMemory(polygon_info,0,GetOpenMPMaximumThreads()*
+    sizeof(*polygon_info));
+  path_info=ConvertPrimitiveToPath(draw_info,primitive_info);
+  if (path_info == (PathInfo *) NULL)
+    return(DestroyPolygonThreadSet(polygon_info));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    polygon_info[i]=ConvertPathToPolygon(draw_info,path_info);
+    if (polygon_info[i] == (PolygonInfo *) NULL)
+      return(DestroyPolygonThreadSet(polygon_info));
+  }
+  path_info=(PathInfo *) RelinquishMagickMemory(path_info);
+  return(polygon_info);
+}
+
+static MagickRealType GetPixelOpacity(PolygonInfo *polygon_info,
+  const MagickRealType mid,const MagickBooleanType fill,
+  const FillRule fill_rule,const double x,const double y,
+  MagickRealType *stroke_opacity)
+{
+  MagickRealType
+    alpha,
+    beta,
+    distance,
+    subpath_opacity;
+
+  PointInfo
+    delta;
+
+  register EdgeInfo
+    *p;
+
+  register const PointInfo
+    *q;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j,
+    winding_number;
+
+  /*
+    Compute fill & stroke opacity for this (x,y) point.
+  */
+  *stroke_opacity=0.0;
+  subpath_opacity=0.0;
+  p=polygon_info->edges;
+  for (j=0; j < (ssize_t) polygon_info->number_edges; j++, p++)
+  {
+    if (y <= (p->bounds.y1-mid-0.5))
+      break;
+    if (y > (p->bounds.y2+mid+0.5))
+      {
+        (void) DestroyEdge(polygon_info,(size_t) j);
+        continue;
+      }
+    if ((x <= (p->bounds.x1-mid-0.5)) || (x > (p->bounds.x2+mid+0.5)))
+      continue;
+    i=(ssize_t) MagickMax((double) p->highwater,1.0);
+    for ( ; i < (ssize_t) p->number_points; i++)
+    {
+      if (y <= (p->points[i-1].y-mid-0.5))
+        break;
+      if (y > (p->points[i].y+mid+0.5))
+        continue;
+      if (p->scanline != y)
+        {
+          p->scanline=y;
+          p->highwater=(size_t) i;
+        }
+      /*
+        Compute distance between a point and an edge.
+      */
+      q=p->points+i-1;
+      delta.x=(q+1)->x-q->x;
+      delta.y=(q+1)->y-q->y;
+      beta=delta.x*(x-q->x)+delta.y*(y-q->y);
+      if (beta < 0.0)
+        {
+          delta.x=x-q->x;
+          delta.y=y-q->y;
+          distance=delta.x*delta.x+delta.y*delta.y;
+        }
+      else
+        {
+          alpha=delta.x*delta.x+delta.y*delta.y;
+          if (beta > alpha)
+            {
+              delta.x=x-(q+1)->x;
+              delta.y=y-(q+1)->y;
+              distance=delta.x*delta.x+delta.y*delta.y;
+            }
+          else
+            {
+              alpha=1.0/alpha;
+              beta=delta.x*(y-q->y)-delta.y*(x-q->x);
+              distance=alpha*beta*beta;
+            }
+        }
+      /*
+        Compute stroke & subpath opacity.
+      */
+      beta=0.0;
+      if (p->ghostline == MagickFalse)
+        {
+          alpha=mid+0.5;
+          if ((*stroke_opacity < 1.0) &&
+              (distance <= ((alpha+0.25)*(alpha+0.25))))
+            {
+              alpha=mid-0.5;
+              if (distance <= ((alpha+0.25)*(alpha+0.25)))
+                *stroke_opacity=1.0;
+              else
+                {
+                  beta=1.0;
+                  if (distance != 1.0)
+                    beta=sqrt((double) distance);
+                  alpha=beta-mid-0.5;
+                  if (*stroke_opacity < ((alpha-0.25)*(alpha-0.25)))
+                    *stroke_opacity=(alpha-0.25)*(alpha-0.25);
+                }
+            }
+        }
+      if ((fill == MagickFalse) || (distance > 1.0) || (subpath_opacity >= 1.0))
+        continue;
+      if (distance <= 0.0)
+        {
+          subpath_opacity=1.0;
+          continue;
+        }
+      if (distance > 1.0)
+        continue;
+      if (beta == 0.0)
+        {
+          beta=1.0;
+          if (distance != 1.0)
+            beta=sqrt(distance);
+        }
+      alpha=beta-1.0;
+      if (subpath_opacity < (alpha*alpha))
+        subpath_opacity=alpha*alpha;
+    }
+  }
+  /*
+    Compute fill opacity.
+  */
+  if (fill == MagickFalse)
+    return(0.0);
+  if (subpath_opacity >= 1.0)
+    return(1.0);
+  /*
+    Determine winding number.
+  */
+  winding_number=0;
+  p=polygon_info->edges;
+  for (j=0; j < (ssize_t) polygon_info->number_edges; j++, p++)
+  {
+    if (y <= p->bounds.y1)
+      break;
+    if ((y > p->bounds.y2) || (x <= p->bounds.x1))
+      continue;
+    if (x > p->bounds.x2)
+      {
+        winding_number+=p->direction ? 1 : -1;
+        continue;
+      }
+    i=(ssize_t) MagickMax((double) p->highwater,1.0);
+    for ( ; i < (ssize_t) p->number_points; i++)
+      if (y <= p->points[i].y)
+        break;
+    q=p->points+i-1;
+    if ((((q+1)->x-q->x)*(y-q->y)) <= (((q+1)->y-q->y)*(x-q->x)))
+      winding_number+=p->direction ? 1 : -1;
+  }
+  if (fill_rule != NonZeroRule)
+    {
+      if ((MagickAbsoluteValue(winding_number) & 0x01) != 0)
+        return(1.0);
+    }
+  else
+    if (MagickAbsoluteValue(winding_number) != 0)
+      return(1.0);
+  return(subpath_opacity);
+}
+
+static MagickBooleanType DrawPolygonPrimitive(Image *image,
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    fill,
+    status;
+
+  MagickRealType
+    mid;
+
+  PolygonInfo
+    **restrict polygon_info;
+
+  register EdgeInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  SegmentInfo
+    bounds;
+
+  ssize_t
+    start,
+    stop,
+    y;
+
+  /*
+    Compute bounding box.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  assert(primitive_info != (PrimitiveInfo *) NULL);
+  if (primitive_info->coordinates == 0)
+    return(MagickTrue);
+  polygon_info=AcquirePolygonThreadSet(draw_info,primitive_info);
+  if (polygon_info == (PolygonInfo **) NULL)
+    return(MagickFalse);
+  if (0)
+    DrawBoundingRectangles(image,draw_info,polygon_info[0]);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    begin draw-polygon");
+  fill=(primitive_info->method == FillToBorderMethod) ||
+    (primitive_info->method == FloodfillMethod) ? MagickTrue : MagickFalse;
+  mid=ExpandAffine(&draw_info->affine)*draw_info->stroke_width/2.0;
+  bounds=polygon_info[0]->edges[0].bounds;
+  for (i=1; i < (ssize_t) polygon_info[0]->number_edges; i++)
+  {
+    p=polygon_info[0]->edges+i;
+    if (p->bounds.x1 < bounds.x1)
+      bounds.x1=p->bounds.x1;
+    if (p->bounds.y1 < bounds.y1)
+      bounds.y1=p->bounds.y1;
+    if (p->bounds.x2 > bounds.x2)
+      bounds.x2=p->bounds.x2;
+    if (p->bounds.y2 > bounds.y2)
+      bounds.y2=p->bounds.y2;
+  }
+  bounds.x1-=(mid+1.0);
+  bounds.x1=bounds.x1 < 0.0 ? 0.0 : (size_t) ceil(bounds.x1-0.5) >=
+    image->columns ? (double) image->columns-1.0 : bounds.x1;
+  bounds.y1-=(mid+1.0);
+  bounds.y1=bounds.y1 < 0.0 ? 0.0 : (size_t) ceil(bounds.y1-0.5) >=
+    image->rows ? (double) image->rows-1.0 : bounds.y1;
+  bounds.x2+=(mid+1.0);
+  bounds.x2=bounds.x2 < 0.0 ? 0.0 : (size_t) floor(bounds.x2+0.5) >=
+    image->columns ? (double) image->columns-1.0 : bounds.x2;
+  bounds.y2+=(mid+1.0);
+  bounds.y2=bounds.y2 < 0.0 ? 0.0 : (size_t) floor(bounds.y2+0.5) >=
+    image->rows ? (double) image->rows-1.0 : bounds.y2;
+  status=MagickTrue;
+  exception=(&image->exception);
+  start=(ssize_t) ceil(bounds.x1-0.5);
+  stop=(ssize_t) floor(bounds.x2+0.5);
+  image_view=AcquireCacheView(image);
+  if (primitive_info->coordinates == 1)
+    {
+      /*
+        Draw point.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=(ssize_t) ceil(bounds.y1-0.5); y <= (ssize_t) floor(bounds.y2+0.5); y++)
+      {
+        MagickBooleanType
+          sync;
+
+        PixelPacket
+          pixel;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        x=start;
+        q=GetCacheViewAuthenticPixels(image_view,x,y,(size_t) (stop-x+1),
+          1,exception);
+        if (q == (Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for ( ; x <= stop; x++)
+        {
+          if ((x == (ssize_t) ceil(primitive_info->point.x-0.5)) &&
+              (y == (ssize_t) ceil(primitive_info->point.y-0.5)))
+            {
+              (void) GetStrokeColor(draw_info,x,y,&pixel);
+              SetPixelPacket(image,&pixel,q);
+            }
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      polygon_info=DestroyPolygonThreadSet(polygon_info);
+      if (image->debug != MagickFalse)
+        (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+          "    end draw-polygon");
+      return(status);
+    }
+  /*
+    Draw polygon or line.
+  */
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=(ssize_t) ceil(bounds.y1-0.5); y <= (ssize_t) floor(bounds.y2+0.5); y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    MagickRealType
+      fill_opacity,
+      stroke_opacity;
+
+    PixelPacket
+      fill_color,
+      stroke_color;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,start,y,(size_t) (stop-
+      start+1),1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=start; x <= stop; x++)
+    {
+      /*
+        Fill and/or stroke.
+      */
+      fill_opacity=GetPixelOpacity(polygon_info[id],mid,fill,
+        draw_info->fill_rule,(double) x,(double) y,&stroke_opacity);
+      if (draw_info->stroke_antialias == MagickFalse)
+        {
+          fill_opacity=fill_opacity > 0.25 ? 1.0 : 0.0;
+          stroke_opacity=stroke_opacity > 0.25 ? 1.0 : 0.0;
+        }
+      (void) GetFillColor(draw_info,x,y,&fill_color);
+      fill_opacity=fill_opacity*fill_color.alpha;
+      CompositePixelOver(image,&fill_color,fill_opacity,q,(MagickRealType)
+        GetPixelAlpha(image,q),q);
+      (void) GetStrokeColor(draw_info,x,y,&stroke_color);
+      stroke_opacity=stroke_opacity*stroke_color.alpha;
+      CompositePixelOver(image,&stroke_color,stroke_opacity,q,(MagickRealType)
+        GetPixelAlpha(image,q),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  polygon_info=DestroyPolygonThreadSet(polygon_info);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end draw-polygon");
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D r a w P r i m i t i v e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawPrimitive() draws a primitive (line, rectangle, ellipse) on the image.
+%
+%  The format of the DrawPrimitive method is:
+%
+%      MagickBooleanType DrawPrimitive(Image *image,const DrawInfo *draw_info,
+%        PrimitiveInfo *primitive_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
+%
+*/
+
+static void LogPrimitiveInfo(const PrimitiveInfo *primitive_info)
+{
+  const char
+    *methods[] =
+    {
+      "point",
+      "replace",
+      "floodfill",
+      "filltoborder",
+      "reset",
+      "?"
+    };
+
+  PointInfo
+    p,
+    q,
+    point;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    coordinates,
+    y;
+
+  x=(ssize_t) ceil(primitive_info->point.x-0.5);
+  y=(ssize_t) ceil(primitive_info->point.y-0.5);
+  switch (primitive_info->primitive)
+  {
+    case PointPrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "PointPrimitive %.20g,%.20g %s",(double) x,(double) y,
+        methods[primitive_info->method]);
+      return;
+    }
+    case ColorPrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "ColorPrimitive %.20g,%.20g %s",(double) x,(double) y,
+        methods[primitive_info->method]);
+      return;
+    }
+    case MattePrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "MattePrimitive %.20g,%.20g %s",(double) x,(double) y,
+        methods[primitive_info->method]);
+      return;
+    }
+    case TextPrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "TextPrimitive %.20g,%.20g",(double) x,(double) y);
+      return;
+    }
+    case ImagePrimitive:
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "ImagePrimitive %.20g,%.20g",(double) x,(double) y);
+      return;
+    }
+    default:
+      break;
+  }
+  coordinates=0;
+  p=primitive_info[0].point;
+  q.x=(-1.0);
+  q.y=(-1.0);
+  for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++)
+  {
+    point=primitive_info[i].point;
+    if (coordinates <= 0)
+      {
+        coordinates=(ssize_t) primitive_info[i].coordinates;
+        (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+          "    begin open (%.20g)",(double) coordinates);
+        p=point;
+      }
+    point=primitive_info[i].point;
+    if ((fabs(q.x-point.x) > MagickEpsilon) ||
+        (fabs(q.y-point.y) > MagickEpsilon))
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "      %.20g: %.18g,%.18g",(double) coordinates,point.x,point.y);
+    else
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "      %.20g: %g %g (duplicate)",(double) coordinates,point.x,point.y);
+    q=point;
+    coordinates--;
+    if (coordinates > 0)
+      continue;
+    if ((fabs(p.x-point.x) > MagickEpsilon) ||
+        (fabs(p.y-point.y) > MagickEpsilon))
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end last (%.20g)",
+        (double) coordinates);
+    else
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),"    end open (%.20g)",
+        (double) coordinates);
+  }
+}
+
+MagickExport MagickBooleanType DrawPrimitive(Image *image,
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    y;
+
+  if (image->debug != MagickFalse)
+    {
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "  begin draw-primitive");
+      (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+        "    affine: %g %g %g %g %g %g",draw_info->affine.sx,
+        draw_info->affine.rx,draw_info->affine.ry,draw_info->affine.sy,
+        draw_info->affine.tx,draw_info->affine.ty);
+    }
+  status=MagickTrue;
+  exception=(&image->exception);
+  x=(ssize_t) ceil(primitive_info->point.x-0.5);
+  y=(ssize_t) ceil(primitive_info->point.y-0.5);
+  image_view=AcquireCacheView(image);
+  switch (primitive_info->primitive)
+  {
+    case PointPrimitive:
+    {
+      PixelPacket
+        fill_color;
+
+      register Quantum
+        *q;
+
+      if ((y < 0) || (y >= (ssize_t) image->rows))
+        break;
+      if ((x < 0) || (x >= (ssize_t) image->columns))
+        break;
+      q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
+      if (q == (Quantum *) NULL)
+        break;
+      (void) GetFillColor(draw_info,x,y,&fill_color);
+      CompositePixelOver(image,&fill_color,(MagickRealType) fill_color.alpha,q,
+        (MagickRealType) GetPixelAlpha(image,q),q);
+      (void) SyncCacheViewAuthenticPixels(image_view,exception);
+      break;
+    }
+    case ColorPrimitive:
+    {
+      switch (primitive_info->method)
+      {
+        case PointMethod:
+        default:
+        {
+          PixelPacket
+            pixel;
+
+          register Quantum
+            *q;
+
+          q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
+          if (q == (Quantum *) NULL)
+            break;
+          (void) GetFillColor(draw_info,x,y,&pixel);
+          SetPixelPacket(image,&pixel,q);
+          (void) SyncCacheViewAuthenticPixels(image_view,exception);
+          break;
+        }
+        case ReplaceMethod:
+        {
+          MagickBooleanType
+            sync;
+
+          PixelPacket
+            pixel,
+            target;
+
+          (void) GetOneCacheViewVirtualPixel(image_view,x,y,&target,exception);
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            register Quantum
+              *restrict q;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) image->columns; x++)
+            {
+              GetPixelPacket(image,q,&pixel);
+              if (IsFuzzyEquivalencePixelPacket(image,&pixel,&target) == MagickFalse)
+                {
+                  q+=GetPixelChannels(image);
+                  continue;
+                }
+              (void) GetFillColor(draw_info,x,y,&pixel);
+              SetPixelAlpha(image,pixel.alpha,q);
+              q+=GetPixelChannels(image);
+            }
+            sync=SyncCacheViewAuthenticPixels(image_view,exception);
+            if (sync == MagickFalse)
+              break;
+          }
+          break;
+        }
+        case FloodfillMethod:
+        case FillToBorderMethod:
+        {
+          PixelInfo
+            target;
+
+          (void) GetOneVirtualMagickPixel(image,x,y,&target,exception);
+          if (primitive_info->method == FillToBorderMethod)
+            {
+              target.red=(MagickRealType) draw_info->border_color.red;
+              target.green=(MagickRealType) draw_info->border_color.green;
+              target.blue=(MagickRealType) draw_info->border_color.blue;
+            }
+          (void) FloodfillPaintImage(image,DefaultChannels,draw_info,&target,x,
+            y,primitive_info->method == FloodfillMethod ? MagickFalse :
+            MagickTrue);
+          break;
+        }
+        case ResetMethod:
+        {
+          MagickBooleanType
+            sync;
+
+          PixelPacket
+            pixel;
+
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            register Quantum
+              *restrict q;
+
+            register ssize_t
+              x;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) image->columns; x++)
+            {
+              (void) GetFillColor(draw_info,x,y,&pixel);
+              SetPixelPacket(image,&pixel,q);
+              q+=GetPixelChannels(image);
+            }
+            sync=SyncCacheViewAuthenticPixels(image_view,exception);
+            if (sync == MagickFalse)
+              break;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case MattePrimitive:
+    {
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      switch (primitive_info->method)
+      {
+        case PointMethod:
+        default:
+        {
+          PixelPacket
+            pixel;
+
+          register Quantum
+            *q;
+
+          q=GetCacheViewAuthenticPixels(image_view,x,y,1,1,exception);
+          if (q == (Quantum *) NULL)
+            break;
+          (void) GetFillColor(draw_info,x,y,&pixel);
+          SetPixelAlpha(image,pixel.alpha,q);
+          (void) SyncCacheViewAuthenticPixels(image_view,exception);
+          break;
+        }
+        case ReplaceMethod:
+        {
+          MagickBooleanType
+            sync;
+
+          PixelPacket
+            pixel,
+            target;
+
+          (void) GetOneCacheViewVirtualPixel(image_view,x,y,&target,exception);
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            register Quantum
+              *restrict q;
+
+            register ssize_t
+              x;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) image->columns; x++)
+            {
+              GetPixelPacket(image,q,&pixel);
+              if (IsFuzzyEquivalencePixelPacket(image,&pixel,&target) == MagickFalse)
+                {
+                  q+=GetPixelChannels(image);
+                  continue;
+                }
+              (void) GetFillColor(draw_info,x,y,&pixel);
+              SetPixelAlpha(image,pixel.alpha,q);
+              q+=GetPixelChannels(image);
+            }
+            sync=SyncCacheViewAuthenticPixels(image_view,exception);
+            if (sync == MagickFalse)
+              break;
+          }
+          break;
+        }
+        case FloodfillMethod:
+        case FillToBorderMethod:
+        {
+          PixelInfo
+            target;
+
+          (void) GetOneVirtualMagickPixel(image,x,y,&target,exception);
+          if (primitive_info->method == FillToBorderMethod)
+            {
+              target.red=(MagickRealType) draw_info->border_color.red;
+              target.green=(MagickRealType) draw_info->border_color.green;
+              target.blue=(MagickRealType) draw_info->border_color.blue;
+            }
+          (void) FloodfillPaintImage(image,OpacityChannel,draw_info,&target,x,y,
+            primitive_info->method == FloodfillMethod ? MagickFalse :
+            MagickTrue);
+          break;
+        }
+        case ResetMethod:
+        {
+          MagickBooleanType
+            sync;
+
+          PixelPacket
+            pixel;
+
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            register Quantum
+              *restrict q;
+
+            register ssize_t
+              x;
+
+            q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+              exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) image->columns; x++)
+            {
+              (void) GetFillColor(draw_info,x,y,&pixel);
+              SetPixelAlpha(image,pixel.alpha,q);
+              q+=GetPixelChannels(image);
+            }
+            sync=SyncCacheViewAuthenticPixels(image_view,exception);
+            if (sync == MagickFalse)
+              break;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case TextPrimitive:
+    {
+      char
+        geometry[MaxTextExtent];
+
+      DrawInfo
+        *clone_info;
+
+      if (primitive_info->text == (char *) NULL)
+        break;
+      clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+      (void) CloneString(&clone_info->text,primitive_info->text);
+      (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
+        primitive_info->point.x,primitive_info->point.y);
+      (void) CloneString(&clone_info->geometry,geometry);
+      status=AnnotateImage(image,clone_info);
+      clone_info=DestroyDrawInfo(clone_info);
+      break;
+    }
+    case ImagePrimitive:
+    {
+      AffineMatrix
+        affine;
+
+      char
+        composite_geometry[MaxTextExtent];
+
+      Image
+        *composite_image;
+
+      ImageInfo
+        *clone_info;
+
+      RectangleInfo
+        geometry;
+
+      ssize_t
+        x1,
+        y1;
+
+      if (primitive_info->text == (char *) NULL)
+        break;
+      clone_info=AcquireImageInfo();
+      if (LocaleNCompare(primitive_info->text,"data:",5) == 0)
+        composite_image=ReadInlineImage(clone_info,primitive_info->text,
+          &image->exception);
+      else
+        {
+          (void) CopyMagickString(clone_info->filename,primitive_info->text,
+            MaxTextExtent);
+          composite_image=ReadImage(clone_info,&image->exception);
+        }
+      clone_info=DestroyImageInfo(clone_info);
+      if (composite_image == (Image *) NULL)
+        break;
+      (void) SetImageProgressMonitor(composite_image,(MagickProgressMonitor)
+        NULL,(void *) NULL);
+      x1=(ssize_t) ceil(primitive_info[1].point.x-0.5);
+      y1=(ssize_t) ceil(primitive_info[1].point.y-0.5);
+      if (((x1 != 0L) && (x1 != (ssize_t) composite_image->columns)) ||
+          ((y1 != 0L) && (y1 != (ssize_t) composite_image->rows)))
+        {
+          char
+            geometry[MaxTextExtent];
+
+          /*
+            Resize image.
+          */
+          (void) FormatLocaleString(geometry,MaxTextExtent,"%gx%g!",
+            primitive_info[1].point.x,primitive_info[1].point.y);
+          composite_image->filter=image->filter;
+          (void) TransformImage(&composite_image,(char *) NULL,geometry);
+        }
+      if (composite_image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
+      if (draw_info->alpha != OpaqueAlpha)
+        (void) SetImageOpacity(composite_image,draw_info->alpha);
+      SetGeometry(image,&geometry);
+      image->gravity=draw_info->gravity;
+      geometry.x=x;
+      geometry.y=y;
+      (void) FormatLocaleString(composite_geometry,MaxTextExtent,
+        "%.20gx%.20g%+.20g%+.20g",(double) composite_image->columns,(double)
+        composite_image->rows,(double) geometry.x,(double) geometry.y);
+      (void) ParseGravityGeometry(image,composite_geometry,&geometry,
+        &image->exception);
+      affine=draw_info->affine;
+      affine.tx=(double) geometry.x;
+      affine.ty=(double) geometry.y;
+      composite_image->interpolate=image->interpolate;
+      if (draw_info->compose == OverCompositeOp)
+        (void) DrawAffineImage(image,composite_image,&affine);
+      else
+        (void) CompositeImage(image,draw_info->compose,composite_image,
+          geometry.x,geometry.y);
+      composite_image=DestroyImage(composite_image);
+      break;
+    }
+    default:
+    {
+      MagickRealType
+        mid,
+        scale;
+
+      DrawInfo
+        *clone_info;
+
+      if (IsEventLogging() != MagickFalse)
+        LogPrimitiveInfo(primitive_info);
+      scale=ExpandAffine(&draw_info->affine);
+      if ((draw_info->dash_pattern != (double *) NULL) &&
+          (draw_info->dash_pattern[0] != 0.0) &&
+          ((scale*draw_info->stroke_width) > MagickEpsilon) &&
+          (draw_info->stroke.alpha != (Quantum) TransparentAlpha))
+        {
+          /*
+            Draw dash polygon.
+          */
+          clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+          clone_info->stroke_width=0.0;
+          clone_info->stroke.alpha=(Quantum) TransparentAlpha;
+          status=DrawPolygonPrimitive(image,clone_info,primitive_info);
+          clone_info=DestroyDrawInfo(clone_info);
+          (void) DrawDashPolygon(draw_info,primitive_info,image);
+          break;
+        }
+      mid=ExpandAffine(&draw_info->affine)*draw_info->stroke_width/2.0;
+      if ((mid > 1.0) &&
+          (draw_info->stroke.alpha != (Quantum) TransparentAlpha))
+        {
+          MagickBooleanType
+            closed_path;
+
+          /*
+            Draw strokes while respecting line cap/join attributes.
+          */
+          for (i=0; primitive_info[i].primitive != UndefinedPrimitive; i++) ;
+          closed_path=
+            (primitive_info[i-1].point.x == primitive_info[0].point.x) &&
+            (primitive_info[i-1].point.y == primitive_info[0].point.y) ?
+            MagickTrue : MagickFalse;
+          i=(ssize_t) primitive_info[0].coordinates;
+          if ((((draw_info->linecap == RoundCap) ||
+                (closed_path != MagickFalse)) &&
+               (draw_info->linejoin == RoundJoin)) ||
+               (primitive_info[i].primitive != UndefinedPrimitive))
+            {
+              (void) DrawPolygonPrimitive(image,draw_info,primitive_info);
+              break;
+            }
+          clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+          clone_info->stroke_width=0.0;
+          clone_info->stroke.alpha=(Quantum) TransparentAlpha;
+          status=DrawPolygonPrimitive(image,clone_info,primitive_info);
+          clone_info=DestroyDrawInfo(clone_info);
+          status|=DrawStrokePolygon(image,draw_info,primitive_info);
+          break;
+        }
+      status=DrawPolygonPrimitive(image,draw_info,primitive_info);
+      break;
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),"  end draw-primitive");
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D r a w S t r o k e P o l y g o n                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DrawStrokePolygon() draws a stroked polygon (line, rectangle, ellipse) on
+%  the image while respecting the line cap and join attributes.
+%
+%  The format of the DrawStrokePolygon method is:
+%
+%      MagickBooleanType DrawStrokePolygon(Image *image,
+%        const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
+%
+%
+*/
+
+static void DrawRoundLinecap(Image *image,const DrawInfo *draw_info,
+  const PrimitiveInfo *primitive_info)
+{
+  PrimitiveInfo
+    linecap[5];
+
+  register ssize_t
+    i;
+
+  for (i=0; i < 4; i++)
+    linecap[i]=(*primitive_info);
+  linecap[0].coordinates=4;
+  linecap[1].point.x+=(double) (10.0*MagickEpsilon);
+  linecap[2].point.x+=(double) (10.0*MagickEpsilon);
+  linecap[2].point.y+=(double) (10.0*MagickEpsilon);
+  linecap[3].point.y+=(double) (10.0*MagickEpsilon);
+  linecap[4].primitive=UndefinedPrimitive;
+  (void) DrawPolygonPrimitive(image,draw_info,linecap);
+}
+
+static MagickBooleanType DrawStrokePolygon(Image *image,
+  const DrawInfo *draw_info,const PrimitiveInfo *primitive_info)
+{
+  DrawInfo
+    *clone_info;
+
+  MagickBooleanType
+    closed_path,
+    status;
+
+  PrimitiveInfo
+    *stroke_polygon;
+
+  register const PrimitiveInfo
+    *p,
+    *q;
+
+  /*
+    Draw stroked polygon.
+  */
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+      "    begin draw-stroke-polygon");
+  clone_info=CloneDrawInfo((ImageInfo *) NULL,draw_info);
+  clone_info->fill=draw_info->stroke;
+  clone_info->stroke.alpha=(Quantum) TransparentAlpha;
+  clone_info->stroke_width=0.0;
+  clone_info->fill_rule=NonZeroRule;
+  status=MagickTrue;
+  for (p=primitive_info; p->primitive != UndefinedPrimitive; p+=p->coordinates)
+  {
+    stroke_polygon=TraceStrokePolygon(draw_info,p);
+    status=DrawPolygonPrimitive(image,clone_info,stroke_polygon);
+    stroke_polygon=(PrimitiveInfo *) RelinquishMagickMemory(stroke_polygon);
+    q=p+p->coordinates-1;
+    closed_path=(q->point.x == p->point.x) && (q->point.y == p->point.y) ?
+      MagickTrue : MagickFalse;
+    if ((draw_info->linecap == RoundCap) && (closed_path == MagickFalse))
+      {
+        DrawRoundLinecap(image,draw_info,p);
+        DrawRoundLinecap(image,draw_info,q);
+      }
+  }
+  clone_info=DestroyDrawInfo(clone_info);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(DrawEvent,GetMagickModule(),
+      "    end draw-stroke-polygon");
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t A f f i n e M a t r i x                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAffineMatrix() returns an AffineMatrix initialized to the identity
+%  matrix.
+%
+%  The format of the GetAffineMatrix method is:
+%
+%      void GetAffineMatrix(AffineMatrix *affine_matrix)
+%
+%  A description of each parameter follows:
+%
+%    o affine_matrix: the affine matrix.
+%
+*/
+MagickExport void GetAffineMatrix(AffineMatrix *affine_matrix)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(affine_matrix != (AffineMatrix *) NULL);
+  (void) ResetMagickMemory(affine_matrix,0,sizeof(*affine_matrix));
+  affine_matrix->sx=1.0;
+  affine_matrix->sy=1.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t D r a w I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetDrawInfo() initializes draw_info to default values.
+%
+%  The format of the GetDrawInfo method is:
+%
+%      void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info..
+%
+%    o draw_info: the draw info.
+%
+*/
+MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
+{
+  const char
+    *option;
+
+  ExceptionInfo
+    *exception;
+
+  ImageInfo
+    *clone_info;
+
+  /*
+    Initialize draw attributes.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(draw_info != (DrawInfo *) NULL);
+  (void) ResetMagickMemory(draw_info,0,sizeof(*draw_info));
+  clone_info=CloneImageInfo(image_info);
+  GetAffineMatrix(&draw_info->affine);
+  exception=AcquireExceptionInfo();
+  (void) QueryColorDatabase("#000F",&draw_info->fill,exception);
+  (void) QueryColorDatabase("#FFF0",&draw_info->stroke,exception);
+  draw_info->stroke_antialias=clone_info->antialias;
+  draw_info->stroke_width=1.0;
+  draw_info->alpha=OpaqueAlpha;
+  draw_info->fill_rule=EvenOddRule;
+  draw_info->linecap=ButtCap;
+  draw_info->linejoin=MiterJoin;
+  draw_info->miterlimit=10;
+  draw_info->decorate=NoDecoration;
+  if (clone_info->font != (char *) NULL)
+    draw_info->font=AcquireString(clone_info->font);
+  if (clone_info->density != (char *) NULL)
+    draw_info->density=AcquireString(clone_info->density);
+  draw_info->text_antialias=clone_info->antialias;
+  draw_info->pointsize=12.0;
+  if (clone_info->pointsize != 0.0)
+    draw_info->pointsize=clone_info->pointsize;
+  draw_info->undercolor.alpha=(Quantum) TransparentAlpha;
+  draw_info->border_color=clone_info->border_color;
+  draw_info->compose=OverCompositeOp;
+  if (clone_info->server_name != (char *) NULL)
+    draw_info->server_name=AcquireString(clone_info->server_name);
+  draw_info->render=MagickTrue;
+  draw_info->debug=IsEventLogging();
+  option=GetImageOption(clone_info,"encoding");
+  if (option != (const char *) NULL)
+    (void) CloneString(&draw_info->encoding,option);
+  option=GetImageOption(clone_info,"kerning");
+  if (option != (const char *) NULL)
+    draw_info->kerning=InterpretLocaleValue(option,(char **) NULL);
+  option=GetImageOption(clone_info,"interline-spacing");
+  if (option != (const char *) NULL)
+    draw_info->interline_spacing=InterpretLocaleValue(option,(char **) NULL);
+  draw_info->direction=UndefinedDirection;
+  option=GetImageOption(clone_info,"interword-spacing");
+  if (option != (const char *) NULL)
+    draw_info->interword_spacing=InterpretLocaleValue(option,(char **) NULL);
+  option=GetImageOption(clone_info,"direction");
+  if (option != (const char *) NULL)
+    draw_info->direction=(DirectionType) ParseCommandOption(
+      MagickDirectionOptions,MagickFalse,option);
+  option=GetImageOption(clone_info,"fill");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&draw_info->fill,exception);
+  option=GetImageOption(clone_info,"stroke");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&draw_info->stroke,exception);
+  option=GetImageOption(clone_info,"strokewidth");
+  if (option != (const char *) NULL)
+    draw_info->stroke_width=InterpretLocaleValue(option,(char **) NULL);
+  option=GetImageOption(clone_info,"undercolor");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&draw_info->undercolor,exception);
+  option=GetImageOption(clone_info,"gravity");
+  if (option != (const char *) NULL)
+    draw_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
+      MagickFalse,option);
+  exception=DestroyExceptionInfo(exception);
+  draw_info->signature=MagickSignature;
+  clone_info=DestroyImageInfo(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P e r m u t a t e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Permutate() returns the permuation of the (n,k).
+%
+%  The format of the Permutate method is:
+%
+%      void Permutate(ssize_t n,ssize_t k)
+%
+%  A description of each parameter follows:
+%
+%    o n:
+%
+%    o k:
+%
+%
+*/
+static inline MagickRealType Permutate(const ssize_t n,const ssize_t k)
+{
+  MagickRealType
+    r;
+
+  register ssize_t
+    i;
+
+  r=1.0;
+  for (i=k+1; i <= n; i++)
+    r*=i;
+  for (i=1; i <= (n-k); i++)
+    r/=i;
+  return(r);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   T r a c e P r i m i t i v e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TracePrimitive is a collection of methods for generating graphic
+%  primitives such as arcs, ellipses, paths, etc.
+%
+*/
+
+static void TraceArc(PrimitiveInfo *primitive_info,const PointInfo start,
+  const PointInfo end,const PointInfo degrees)
+{
+  PointInfo
+    center,
+    radii;
+
+  center.x=0.5*(end.x+start.x);
+  center.y=0.5*(end.y+start.y);
+  radii.x=fabs(center.x-start.x);
+  radii.y=fabs(center.y-start.y);
+  TraceEllipse(primitive_info,center,radii,degrees);
+}
+
+static void TraceArcPath(PrimitiveInfo *primitive_info,const PointInfo start,
+  const PointInfo end,const PointInfo arc,const MagickRealType angle,
+  const MagickBooleanType large_arc,const MagickBooleanType sweep)
+{
+  MagickRealType
+    alpha,
+    beta,
+    delta,
+    factor,
+    gamma,
+    theta;
+
+  PointInfo
+    center,
+    points[3],
+    radii;
+
+  register MagickRealType
+    cosine,
+    sine;
+
+  register PrimitiveInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    arc_segments;
+
+  if ((start.x == end.x) && (start.y == end.y))
+    {
+      TracePoint(primitive_info,end);
+      return;
+    }
+  radii.x=fabs(arc.x);
+  radii.y=fabs(arc.y);
+  if ((radii.x == 0.0) || (radii.y == 0.0))
+    {
+      TraceLine(primitive_info,start,end);
+      return;
+    }
+  cosine=cos(DegreesToRadians(fmod((double) angle,360.0)));
+  sine=sin(DegreesToRadians(fmod((double) angle,360.0)));
+  center.x=(double) (cosine*(end.x-start.x)/2+sine*(end.y-start.y)/2);
+  center.y=(double) (cosine*(end.y-start.y)/2-sine*(end.x-start.x)/2);
+  delta=(center.x*center.x)/(radii.x*radii.x)+(center.y*center.y)/
+    (radii.y*radii.y);
+  if (delta < MagickEpsilon)
+    {
+      TraceLine(primitive_info,start,end);
+      return;
+    }
+  if (delta > 1.0)
+    {
+      radii.x*=sqrt((double) delta);
+      radii.y*=sqrt((double) delta);
+    }
+  points[0].x=(double) (cosine*start.x/radii.x+sine*start.y/radii.x);
+  points[0].y=(double) (cosine*start.y/radii.y-sine*start.x/radii.y);
+  points[1].x=(double) (cosine*end.x/radii.x+sine*end.y/radii.x);
+  points[1].y=(double) (cosine*end.y/radii.y-sine*end.x/radii.y);
+  alpha=points[1].x-points[0].x;
+  beta=points[1].y-points[0].y;
+  factor=1.0/(alpha*alpha+beta*beta)-0.25;
+  if (factor <= 0.0)
+    factor=0.0;
+  else
+    {
+      factor=sqrt((double) factor);
+      if (sweep == large_arc)
+        factor=(-factor);
+    }
+  center.x=(double) ((points[0].x+points[1].x)/2-factor*beta);
+  center.y=(double) ((points[0].y+points[1].y)/2+factor*alpha);
+  alpha=atan2(points[0].y-center.y,points[0].x-center.x);
+  theta=atan2(points[1].y-center.y,points[1].x-center.x)-alpha;
+  if ((theta < 0.0) && (sweep != MagickFalse))
+    theta+=(MagickRealType) (2.0*MagickPI);
+  else
+    if ((theta > 0.0) && (sweep == MagickFalse))
+      theta-=(MagickRealType) (2.0*MagickPI);
+  arc_segments=(size_t) ceil(fabs((double) (theta/(0.5*MagickPI+
+    MagickEpsilon))));
+  p=primitive_info;
+  for (i=0; i < (ssize_t) arc_segments; i++)
+  {
+    beta=0.5*((alpha+(i+1)*theta/arc_segments)-(alpha+i*theta/arc_segments));
+    gamma=(8.0/3.0)*sin(fmod((double) (0.5*beta),DegreesToRadians(360.0)))*
+      sin(fmod((double) (0.5*beta),DegreesToRadians(360.0)))/
+      sin(fmod((double) beta,DegreesToRadians(360.0)));
+    points[0].x=(double) (center.x+cos(fmod((double) (alpha+(double) i*theta/
+      arc_segments),DegreesToRadians(360.0)))-gamma*sin(fmod((double) (alpha+
+      (double) i*theta/arc_segments),DegreesToRadians(360.0))));
+    points[0].y=(double) (center.y+sin(fmod((double) (alpha+(double) i*theta/
+      arc_segments),DegreesToRadians(360.0)))+gamma*cos(fmod((double) (alpha+
+      (double) i*theta/arc_segments),DegreesToRadians(360.0))));
+    points[2].x=(double) (center.x+cos(fmod((double) (alpha+(double) (i+1)*
+      theta/arc_segments),DegreesToRadians(360.0))));
+    points[2].y=(double) (center.y+sin(fmod((double) (alpha+(double) (i+1)*
+      theta/arc_segments),DegreesToRadians(360.0))));
+    points[1].x=(double) (points[2].x+gamma*sin(fmod((double) (alpha+(double)
+      (i+1)*theta/arc_segments),DegreesToRadians(360.0))));
+    points[1].y=(double) (points[2].y-gamma*cos(fmod((double) (alpha+(double)
+      (i+1)*theta/arc_segments),DegreesToRadians(360.0))));
+    p->point.x=(p == primitive_info) ? start.x : (p-1)->point.x;
+    p->point.y=(p == primitive_info) ? start.y : (p-1)->point.y;
+    (p+1)->point.x=(double) (cosine*radii.x*points[0].x-sine*radii.y*
+      points[0].y);
+    (p+1)->point.y=(double) (sine*radii.x*points[0].x+cosine*radii.y*
+      points[0].y);
+    (p+2)->point.x=(double) (cosine*radii.x*points[1].x-sine*radii.y*
+      points[1].y);
+    (p+2)->point.y=(double) (sine*radii.x*points[1].x+cosine*radii.y*
+      points[1].y);
+    (p+3)->point.x=(double) (cosine*radii.x*points[2].x-sine*radii.y*
+      points[2].y);
+    (p+3)->point.y=(double) (sine*radii.x*points[2].x+cosine*radii.y*
+      points[2].y);
+    if (i == (ssize_t) (arc_segments-1))
+      (p+3)->point=end;
+    TraceBezier(p,4);
+    p+=p->coordinates;
+  }
+  primitive_info->coordinates=(size_t) (p-primitive_info);
+  for (i=0; i < (ssize_t) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+}
+
+static void TraceBezier(PrimitiveInfo *primitive_info,
+  const size_t number_coordinates)
+{
+  MagickRealType
+    alpha,
+    *coefficients,
+    weight;
+
+  PointInfo
+    end,
+    point,
+    *points;
+
+  register PrimitiveInfo
+    *p;
+
+  register ssize_t
+    i,
+    j;
+
+  size_t
+    control_points,
+    quantum;
+
+  /*
+    Allocate coeficients.
+  */
+  quantum=number_coordinates;
+  for (i=0; i < (ssize_t) number_coordinates; i++)
+  {
+    for (j=i+1; j < (ssize_t) number_coordinates; j++)
+    {
+      alpha=fabs(primitive_info[j].point.x-primitive_info[i].point.x);
+      if (alpha > (MagickRealType) quantum)
+        quantum=(size_t) alpha;
+      alpha=fabs(primitive_info[j].point.y-primitive_info[i].point.y);
+      if (alpha > (MagickRealType) quantum)
+        quantum=(size_t) alpha;
+    }
+  }
+  quantum=(size_t) MagickMin((double) quantum/number_coordinates,
+    (double) BezierQuantum);
+  control_points=quantum*number_coordinates;
+  coefficients=(MagickRealType *) AcquireQuantumMemory((size_t)
+    number_coordinates,sizeof(*coefficients));
+  points=(PointInfo *) AcquireQuantumMemory((size_t) control_points,
+    sizeof(*points));
+  if ((coefficients == (MagickRealType *) NULL) ||
+      (points == (PointInfo *) NULL))
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  /*
+    Compute bezier points.
+  */
+  end=primitive_info[number_coordinates-1].point;
+  for (i=0; i < (ssize_t) number_coordinates; i++)
+    coefficients[i]=Permutate((ssize_t) number_coordinates-1,i);
+  weight=0.0;
+  for (i=0; i < (ssize_t) control_points; i++)
+  {
+    p=primitive_info;
+    point.x=0.0;
+    point.y=0.0;
+    alpha=pow((double) (1.0-weight),(double) number_coordinates-1.0);
+    for (j=0; j < (ssize_t) number_coordinates; j++)
+    {
+      point.x+=alpha*coefficients[j]*p->point.x;
+      point.y+=alpha*coefficients[j]*p->point.y;
+      alpha*=weight/(1.0-weight);
+      p++;
+    }
+    points[i]=point;
+    weight+=1.0/control_points;
+  }
+  /*
+    Bezier curves are just short segmented polys.
+  */
+  p=primitive_info;
+  for (i=0; i < (ssize_t) control_points; i++)
+  {
+    TracePoint(p,points[i]);
+    p+=p->coordinates;
+  }
+  TracePoint(p,end);
+  p+=p->coordinates;
+  primitive_info->coordinates=(size_t) (p-primitive_info);
+  for (i=0; i < (ssize_t) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+  points=(PointInfo *) RelinquishMagickMemory(points);
+  coefficients=(MagickRealType *) RelinquishMagickMemory(coefficients);
+}
+
+static void TraceCircle(PrimitiveInfo *primitive_info,const PointInfo start,
+  const PointInfo end)
+{
+  MagickRealType
+    alpha,
+    beta,
+    radius;
+
+  PointInfo
+    offset,
+    degrees;
+
+  alpha=end.x-start.x;
+  beta=end.y-start.y;
+  radius=hypot((double) alpha,(double) beta);
+  offset.x=(double) radius;
+  offset.y=(double) radius;
+  degrees.x=0.0;
+  degrees.y=360.0;
+  TraceEllipse(primitive_info,start,offset,degrees);
+}
+
+static void TraceEllipse(PrimitiveInfo *primitive_info,const PointInfo start,
+  const PointInfo stop,const PointInfo degrees)
+{
+  MagickRealType
+    delta,
+    step,
+    y;
+
+  PointInfo
+    angle,
+    point;
+
+  register PrimitiveInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Ellipses are just short segmented polys.
+  */
+  if ((stop.x == 0.0) && (stop.y == 0.0))
+    {
+      TracePoint(primitive_info,start);
+      return;
+    }
+  delta=2.0/MagickMax(stop.x,stop.y);
+  step=(MagickRealType) (MagickPI/8.0);
+  if ((delta >= 0.0) && (delta < (MagickRealType) (MagickPI/8.0)))
+    step=(MagickRealType) (MagickPI/(4*(MagickPI/delta/2+0.5)));
+  angle.x=DegreesToRadians(degrees.x);
+  y=degrees.y;
+  while (y < degrees.x)
+    y+=360.0;
+  angle.y=(double) (DegreesToRadians(y)-MagickEpsilon);
+  for (p=primitive_info; angle.x < angle.y; angle.x+=step)
+  {
+    point.x=cos(fmod(angle.x,DegreesToRadians(360.0)))*stop.x+start.x;
+    point.y=sin(fmod(angle.x,DegreesToRadians(360.0)))*stop.y+start.y;
+    TracePoint(p,point);
+    p+=p->coordinates;
+  }
+  point.x=cos(fmod(angle.y,DegreesToRadians(360.0)))*stop.x+start.x;
+  point.y=sin(fmod(angle.y,DegreesToRadians(360.0)))*stop.y+start.y;
+  TracePoint(p,point);
+  p+=p->coordinates;
+  primitive_info->coordinates=(size_t) (p-primitive_info);
+  for (i=0; i < (ssize_t) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+}
+
+static void TraceLine(PrimitiveInfo *primitive_info,const PointInfo start,
+  const PointInfo end)
+{
+  TracePoint(primitive_info,start);
+  if ((fabs(start.x-end.x) <= MagickEpsilon) &&
+      (fabs(start.y-end.y) <= MagickEpsilon))
+    {
+      primitive_info->primitive=PointPrimitive;
+      primitive_info->coordinates=1;
+      return;
+    }
+  TracePoint(primitive_info+1,end);
+  (primitive_info+1)->primitive=primitive_info->primitive;
+  primitive_info->coordinates=2;
+}
+
+static size_t TracePath(PrimitiveInfo *primitive_info,const char *path)
+{
+  char
+    token[MaxTextExtent];
+
+  const char
+    *p;
+
+  int
+    attribute,
+    last_attribute;
+
+  MagickRealType
+    x,
+    y;
+
+  PointInfo
+    end,
+    points[4],
+    point,
+    start;
+
+  PrimitiveType
+    primitive_type;
+
+  register PrimitiveInfo
+    *q;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_coordinates,
+    z_count;
+
+  attribute=0;
+  point.x=0.0;
+  point.y=0.0;
+  start.x=0.0;
+  start.y=0.0;
+  number_coordinates=0;
+  z_count=0;
+  primitive_type=primitive_info->primitive;
+  q=primitive_info;
+  for (p=path; *p != '\0'; )
+  {
+    while (isspace((int) ((unsigned char) *p)) != 0)
+      p++;
+    if (*p == '\0')
+      break;
+    last_attribute=attribute;
+    attribute=(int) (*p++);
+    switch (attribute)
+    {
+      case 'a':
+      case 'A':
+      {
+        MagickBooleanType
+          large_arc,
+          sweep;
+
+        MagickRealType
+          angle;
+
+        PointInfo
+          arc;
+
+        /*
+          Compute arc points.
+        */
+        do
+        {
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          arc.x=InterpretLocaleValue(token,(char **) NULL);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          arc.y=InterpretLocaleValue(token,(char **) NULL);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          angle=InterpretLocaleValue(token,(char **) NULL);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          large_arc=StringToLong(token) != 0 ? MagickTrue : MagickFalse;
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          sweep=StringToLong(token) != 0 ? MagickTrue : MagickFalse;
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          x=InterpretLocaleValue(token,(char **) NULL);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=InterpretLocaleValue(token,(char **) NULL);
+          end.x=(double) (attribute == (int) 'A' ? x : point.x+x);
+          end.y=(double) (attribute == (int) 'A' ? y : point.y+y);
+          TraceArcPath(q,point,end,arc,angle,large_arc,sweep);
+          q+=q->coordinates;
+          point=end;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'c':
+      case 'C':
+      {
+        /*
+          Compute bezier points.
+        */
+        do
+        {
+          points[0]=point;
+          for (i=1; i < 4; i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            x=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=InterpretLocaleValue(token,(char **) NULL);
+            end.x=(double) (attribute == (int) 'C' ? x : point.x+x);
+            end.y=(double) (attribute == (int) 'C' ? y : point.y+y);
+            points[i]=end;
+          }
+          for (i=0; i < 4; i++)
+            (q+i)->point=points[i];
+          TraceBezier(q,4);
+          q+=q->coordinates;
+          point=end;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'H':
+      case 'h':
+      {
+        do
+        {
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          x=InterpretLocaleValue(token,(char **) NULL);
+          point.x=(double) (attribute == (int) 'H' ? x: point.x+x);
+          TracePoint(q,point);
+          q+=q->coordinates;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'l':
+      case 'L':
+      {
+        do
+        {
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          x=InterpretLocaleValue(token,(char **) NULL);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=InterpretLocaleValue(token,(char **) NULL);
+          point.x=(double) (attribute == (int) 'L' ? x : point.x+x);
+          point.y=(double) (attribute == (int) 'L' ? y : point.y+y);
+          TracePoint(q,point);
+          q+=q->coordinates;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'M':
+      case 'm':
+      {
+        if (q != primitive_info)
+          {
+            primitive_info->coordinates=(size_t) (q-primitive_info);
+            number_coordinates+=primitive_info->coordinates;
+            primitive_info=q;
+          }
+        i=0;
+        do
+        {
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          x=InterpretLocaleValue(token,(char **) NULL);
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=InterpretLocaleValue(token,(char **) NULL);
+          point.x=(double) (attribute == (int) 'M' ? x : point.x+x);
+          point.y=(double) (attribute == (int) 'M' ? y : point.y+y);
+          if (i == 0)
+            start=point;
+          i++;
+          TracePoint(q,point);
+          q+=q->coordinates;
+          if ((i != 0) && (attribute == (int) 'M'))
+            {
+              TracePoint(q,point);
+              q+=q->coordinates;
+            }
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'q':
+      case 'Q':
+      {
+        /*
+          Compute bezier points.
+        */
+        do
+        {
+          points[0]=point;
+          for (i=1; i < 3; i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            x=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=InterpretLocaleValue(token,(char **) NULL);
+            if (*p == ',')
+              p++;
+            end.x=(double) (attribute == (int) 'Q' ? x : point.x+x);
+            end.y=(double) (attribute == (int) 'Q' ? y : point.y+y);
+            points[i]=end;
+          }
+          for (i=0; i < 3; i++)
+            (q+i)->point=points[i];
+          TraceBezier(q,3);
+          q+=q->coordinates;
+          point=end;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 's':
+      case 'S':
+      {
+        /*
+          Compute bezier points.
+        */
+        do
+        {
+          points[0]=points[3];
+          points[1].x=2.0*points[3].x-points[2].x;
+          points[1].y=2.0*points[3].y-points[2].y;
+          for (i=2; i < 4; i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            x=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=InterpretLocaleValue(token,(char **) NULL);
+            if (*p == ',')
+              p++;
+            end.x=(double) (attribute == (int) 'S' ? x : point.x+x);
+            end.y=(double) (attribute == (int) 'S' ? y : point.y+y);
+            points[i]=end;
+          }
+          if (strchr("CcSs",last_attribute) == (char *) NULL)
+            {
+              points[0]=points[2];
+              points[1]=points[3];
+            }
+          for (i=0; i < 4; i++)
+            (q+i)->point=points[i];
+          TraceBezier(q,4);
+          q+=q->coordinates;
+          point=end;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 't':
+      case 'T':
+      {
+        /*
+          Compute bezier points.
+        */
+        do
+        {
+          points[0]=points[2];
+          points[1].x=2.0*points[2].x-points[1].x;
+          points[1].y=2.0*points[2].y-points[1].y;
+          for (i=2; i < 3; i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            x=InterpretLocaleValue(token,(char **) NULL);
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            y=InterpretLocaleValue(token,(char **) NULL);
+            end.x=(double) (attribute == (int) 'T' ? x : point.x+x);
+            end.y=(double) (attribute == (int) 'T' ? y : point.y+y);
+            points[i]=end;
+          }
+          if (strchr("QqTt",last_attribute) == (char *) NULL)
+            {
+              points[0]=points[2];
+              points[1]=points[3];
+            }
+          for (i=0; i < 3; i++)
+            (q+i)->point=points[i];
+          TraceBezier(q,3);
+          q+=q->coordinates;
+          point=end;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'v':
+      case 'V':
+      {
+        do
+        {
+          GetMagickToken(p,&p,token);
+          if (*token == ',')
+            GetMagickToken(p,&p,token);
+          y=InterpretLocaleValue(token,(char **) NULL);
+          point.y=(double) (attribute == (int) 'V' ? y : point.y+y);
+          TracePoint(q,point);
+          q+=q->coordinates;
+        } while (IsPoint(p) != MagickFalse);
+        break;
+      }
+      case 'z':
+      case 'Z':
+      {
+        point=start;
+        TracePoint(q,point);
+        q+=q->coordinates;
+        primitive_info->coordinates=(size_t) (q-primitive_info);
+        number_coordinates+=primitive_info->coordinates;
+        primitive_info=q;
+        z_count++;
+        break;
+      }
+      default:
+      {
+        if (isalpha((int) ((unsigned char) attribute)) != 0)
+          (void) FormatLocaleFile(stderr,"attribute not recognized: %c\n",
+            attribute);
+        break;
+      }
+    }
+  }
+  primitive_info->coordinates=(size_t) (q-primitive_info);
+  number_coordinates+=primitive_info->coordinates;
+  for (i=0; i < (ssize_t) number_coordinates; i++)
+  {
+    q--;
+    q->primitive=primitive_type;
+    if (z_count > 1)
+      q->method=FillToBorderMethod;
+  }
+  q=primitive_info;
+  return(number_coordinates);
+}
+
+static void TraceRectangle(PrimitiveInfo *primitive_info,const PointInfo start,
+  const PointInfo end)
+{
+  PointInfo
+    point;
+
+  register PrimitiveInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  p=primitive_info;
+  TracePoint(p,start);
+  p+=p->coordinates;
+  point.x=start.x;
+  point.y=end.y;
+  TracePoint(p,point);
+  p+=p->coordinates;
+  TracePoint(p,end);
+  p+=p->coordinates;
+  point.x=end.x;
+  point.y=start.y;
+  TracePoint(p,point);
+  p+=p->coordinates;
+  TracePoint(p,start);
+  p+=p->coordinates;
+  primitive_info->coordinates=(size_t) (p-primitive_info);
+  for (i=0; i < (ssize_t) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+}
+
+static void TraceRoundRectangle(PrimitiveInfo *primitive_info,
+  const PointInfo start,const PointInfo end,PointInfo arc)
+{
+  PointInfo
+    degrees,
+    offset,
+    point;
+
+  register PrimitiveInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  p=primitive_info;
+  offset.x=fabs(end.x-start.x);
+  offset.y=fabs(end.y-start.y);
+  if (arc.x > (0.5*offset.x))
+    arc.x=0.5*offset.x;
+  if (arc.y > (0.5*offset.y))
+    arc.y=0.5*offset.y;
+  point.x=start.x+offset.x-arc.x;
+  point.y=start.y+arc.y;
+  degrees.x=270.0;
+  degrees.y=360.0;
+  TraceEllipse(p,point,arc,degrees);
+  p+=p->coordinates;
+  point.x=start.x+offset.x-arc.x;
+  point.y=start.y+offset.y-arc.y;
+  degrees.x=0.0;
+  degrees.y=90.0;
+  TraceEllipse(p,point,arc,degrees);
+  p+=p->coordinates;
+  point.x=start.x+arc.x;
+  point.y=start.y+offset.y-arc.y;
+  degrees.x=90.0;
+  degrees.y=180.0;
+  TraceEllipse(p,point,arc,degrees);
+  p+=p->coordinates;
+  point.x=start.x+arc.x;
+  point.y=start.y+arc.y;
+  degrees.x=180.0;
+  degrees.y=270.0;
+  TraceEllipse(p,point,arc,degrees);
+  p+=p->coordinates;
+  TracePoint(p,primitive_info->point);
+  p+=p->coordinates;
+  primitive_info->coordinates=(size_t) (p-primitive_info);
+  for (i=0; i < (ssize_t) primitive_info->coordinates; i++)
+  {
+    p->primitive=primitive_info->primitive;
+    p--;
+  }
+}
+
+static void TraceSquareLinecap(PrimitiveInfo *primitive_info,
+  const size_t number_vertices,const MagickRealType offset)
+{
+  MagickRealType
+    distance;
+
+  register MagickRealType
+    dx,
+    dy;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  dx=0.0;
+  dy=0.0;
+  for (i=1; i < (ssize_t) number_vertices; i++)
+  {
+    dx=primitive_info[0].point.x-primitive_info[i].point.x;
+    dy=primitive_info[0].point.y-primitive_info[i].point.y;
+    if ((fabs((double) dx) >= MagickEpsilon) ||
+        (fabs((double) dy) >= MagickEpsilon))
+      break;
+  }
+  if (i == (ssize_t) number_vertices)
+    i=(ssize_t) number_vertices-1L;
+  distance=hypot((double) dx,(double) dy);
+  primitive_info[0].point.x=(double) (primitive_info[i].point.x+
+    dx*(distance+offset)/distance);
+  primitive_info[0].point.y=(double) (primitive_info[i].point.y+
+    dy*(distance+offset)/distance);
+  for (j=(ssize_t) number_vertices-2; j >= 0;  j--)
+  {
+    dx=primitive_info[number_vertices-1].point.x-primitive_info[j].point.x;
+    dy=primitive_info[number_vertices-1].point.y-primitive_info[j].point.y;
+    if ((fabs((double) dx) >= MagickEpsilon) ||
+        (fabs((double) dy) >= MagickEpsilon))
+      break;
+  }
+  distance=hypot((double) dx,(double) dy);
+  primitive_info[number_vertices-1].point.x=(double) (primitive_info[j].point.x+
+    dx*(distance+offset)/distance);
+  primitive_info[number_vertices-1].point.y=(double) (primitive_info[j].point.y+
+    dy*(distance+offset)/distance);
+}
+
+static PrimitiveInfo *TraceStrokePolygon(const DrawInfo *draw_info,
+  const PrimitiveInfo *primitive_info)
+{
+  typedef struct _LineSegment
+  {
+    double
+      p,
+      q;
+  } LineSegment;
+
+  LineSegment
+    dx,
+    dy,
+    inverse_slope,
+    slope,
+    theta;
+
+  MagickBooleanType
+    closed_path;
+
+  MagickRealType
+    delta_theta,
+    dot_product,
+    mid,
+    miterlimit;
+
+  PointInfo
+    box_p[5],
+    box_q[5],
+    center,
+    offset,
+    *path_p,
+    *path_q;
+
+  PrimitiveInfo
+    *polygon_primitive,
+    *stroke_polygon;
+
+  register ssize_t
+    i;
+
+  size_t
+    arc_segments,
+    max_strokes,
+    number_vertices;
+
+  ssize_t
+    j,
+    n,
+    p,
+    q;
+
+  /*
+    Allocate paths.
+  */
+  number_vertices=primitive_info->coordinates;
+  max_strokes=2*number_vertices+6*BezierQuantum+360;
+  path_p=(PointInfo *) AcquireQuantumMemory((size_t) max_strokes,
+    sizeof(*path_p));
+  path_q=(PointInfo *) AcquireQuantumMemory((size_t) max_strokes,
+    sizeof(*path_q));
+  polygon_primitive=(PrimitiveInfo *) AcquireQuantumMemory((size_t)
+    number_vertices+2UL,sizeof(*polygon_primitive));
+  if ((path_p == (PointInfo *) NULL) || (path_q == (PointInfo *) NULL) ||
+      (polygon_primitive == (PrimitiveInfo *) NULL))
+    return((PrimitiveInfo *) NULL);
+  (void) CopyMagickMemory(polygon_primitive,primitive_info,(size_t)
+    number_vertices*sizeof(*polygon_primitive));
+  closed_path=
+    (primitive_info[number_vertices-1].point.x == primitive_info[0].point.x) &&
+    (primitive_info[number_vertices-1].point.y == primitive_info[0].point.y) ?
+    MagickTrue : MagickFalse;
+  if ((draw_info->linejoin == RoundJoin) ||
+      ((draw_info->linejoin == MiterJoin) && (closed_path != MagickFalse)))
+    {
+      polygon_primitive[number_vertices]=primitive_info[1];
+      number_vertices++;
+    }
+  polygon_primitive[number_vertices].primitive=UndefinedPrimitive;
+  /*
+    Compute the slope for the first line segment, p.
+  */
+  dx.p=0.0;
+  dy.p=0.0;
+  for (n=1; n < (ssize_t) number_vertices; n++)
+  {
+    dx.p=polygon_primitive[n].point.x-polygon_primitive[0].point.x;
+    dy.p=polygon_primitive[n].point.y-polygon_primitive[0].point.y;
+    if ((fabs(dx.p) >= MagickEpsilon) || (fabs(dy.p) >= MagickEpsilon))
+      break;
+  }
+  if (n == (ssize_t) number_vertices)
+    n=(ssize_t) number_vertices-1L;
+  slope.p=0.0;
+  inverse_slope.p=0.0;
+  if (fabs(dx.p) <= MagickEpsilon)
+    {
+      if (dx.p >= 0.0)
+        slope.p=dy.p < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
+      else
+        slope.p=dy.p < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
+    }
+  else
+    if (fabs(dy.p) <= MagickEpsilon)
+      {
+        if (dy.p >= 0.0)
+          inverse_slope.p=dx.p < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
+        else
+          inverse_slope.p=dx.p < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
+      }
+    else
+      {
+        slope.p=dy.p/dx.p;
+        inverse_slope.p=(-1.0/slope.p);
+      }
+  mid=ExpandAffine(&draw_info->affine)*draw_info->stroke_width/2.0;
+  miterlimit=(MagickRealType) (draw_info->miterlimit*draw_info->miterlimit*
+    mid*mid);
+  if ((draw_info->linecap == SquareCap) && (closed_path == MagickFalse))
+    TraceSquareLinecap(polygon_primitive,number_vertices,mid);
+  offset.x=sqrt((double) (mid*mid/(inverse_slope.p*inverse_slope.p+1.0)));
+  offset.y=(double) (offset.x*inverse_slope.p);
+  if ((dy.p*offset.x-dx.p*offset.y) > 0.0)
+    {
+      box_p[0].x=polygon_primitive[0].point.x-offset.x;
+      box_p[0].y=polygon_primitive[0].point.y-offset.x*inverse_slope.p;
+      box_p[1].x=polygon_primitive[n].point.x-offset.x;
+      box_p[1].y=polygon_primitive[n].point.y-offset.x*inverse_slope.p;
+      box_q[0].x=polygon_primitive[0].point.x+offset.x;
+      box_q[0].y=polygon_primitive[0].point.y+offset.x*inverse_slope.p;
+      box_q[1].x=polygon_primitive[n].point.x+offset.x;
+      box_q[1].y=polygon_primitive[n].point.y+offset.x*inverse_slope.p;
+    }
+  else
+    {
+      box_p[0].x=polygon_primitive[0].point.x+offset.x;
+      box_p[0].y=polygon_primitive[0].point.y+offset.y;
+      box_p[1].x=polygon_primitive[n].point.x+offset.x;
+      box_p[1].y=polygon_primitive[n].point.y+offset.y;
+      box_q[0].x=polygon_primitive[0].point.x-offset.x;
+      box_q[0].y=polygon_primitive[0].point.y-offset.y;
+      box_q[1].x=polygon_primitive[n].point.x-offset.x;
+      box_q[1].y=polygon_primitive[n].point.y-offset.y;
+    }
+  /*
+    Create strokes for the line join attribute: bevel, miter, round.
+  */
+  p=0;
+  q=0;
+  path_q[p++]=box_q[0];
+  path_p[q++]=box_p[0];
+  for (i=(ssize_t) n+1; i < (ssize_t) number_vertices; i++)
+  {
+    /*
+      Compute the slope for this line segment, q.
+    */
+    dx.q=polygon_primitive[i].point.x-polygon_primitive[n].point.x;
+    dy.q=polygon_primitive[i].point.y-polygon_primitive[n].point.y;
+    dot_product=dx.q*dx.q+dy.q*dy.q;
+    if (dot_product < 0.25)
+      continue;
+    slope.q=0.0;
+    inverse_slope.q=0.0;
+    if (fabs(dx.q) < MagickEpsilon)
+      {
+        if (dx.q >= 0.0)
+          slope.q=dy.q < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
+        else
+          slope.q=dy.q < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
+      }
+    else
+      if (fabs(dy.q) <= MagickEpsilon)
+        {
+          if (dy.q >= 0.0)
+            inverse_slope.q=dx.q < 0.0 ? -1.0/MagickEpsilon : 1.0/MagickEpsilon;
+          else
+            inverse_slope.q=dx.q < 0.0 ? 1.0/MagickEpsilon : -1.0/MagickEpsilon;
+        }
+      else
+        {
+          slope.q=dy.q/dx.q;
+          inverse_slope.q=(-1.0/slope.q);
+        }
+    offset.x=sqrt((double) (mid*mid/(inverse_slope.q*inverse_slope.q+1.0)));
+    offset.y=(double) (offset.x*inverse_slope.q);
+    dot_product=dy.q*offset.x-dx.q*offset.y;
+    if (dot_product > 0.0)
+      {
+        box_p[2].x=polygon_primitive[n].point.x-offset.x;
+        box_p[2].y=polygon_primitive[n].point.y-offset.y;
+        box_p[3].x=polygon_primitive[i].point.x-offset.x;
+        box_p[3].y=polygon_primitive[i].point.y-offset.y;
+        box_q[2].x=polygon_primitive[n].point.x+offset.x;
+        box_q[2].y=polygon_primitive[n].point.y+offset.y;
+        box_q[3].x=polygon_primitive[i].point.x+offset.x;
+        box_q[3].y=polygon_primitive[i].point.y+offset.y;
+      }
+    else
+      {
+        box_p[2].x=polygon_primitive[n].point.x+offset.x;
+        box_p[2].y=polygon_primitive[n].point.y+offset.y;
+        box_p[3].x=polygon_primitive[i].point.x+offset.x;
+        box_p[3].y=polygon_primitive[i].point.y+offset.y;
+        box_q[2].x=polygon_primitive[n].point.x-offset.x;
+        box_q[2].y=polygon_primitive[n].point.y-offset.y;
+        box_q[3].x=polygon_primitive[i].point.x-offset.x;
+        box_q[3].y=polygon_primitive[i].point.y-offset.y;
+      }
+    if (fabs((double) (slope.p-slope.q)) <= MagickEpsilon)
+      {
+        box_p[4]=box_p[1];
+        box_q[4]=box_q[1];
+      }
+    else
+      {
+        box_p[4].x=(double) ((slope.p*box_p[0].x-box_p[0].y-slope.q*box_p[3].x+
+          box_p[3].y)/(slope.p-slope.q));
+        box_p[4].y=(double) (slope.p*(box_p[4].x-box_p[0].x)+box_p[0].y);
+        box_q[4].x=(double) ((slope.p*box_q[0].x-box_q[0].y-slope.q*box_q[3].x+
+          box_q[3].y)/(slope.p-slope.q));
+        box_q[4].y=(double) (slope.p*(box_q[4].x-box_q[0].x)+box_q[0].y);
+      }
+    if (q >= (ssize_t) (max_strokes-6*BezierQuantum-360))
+      {
+         max_strokes+=6*BezierQuantum+360;
+         path_p=(PointInfo *) ResizeQuantumMemory(path_p,(size_t) max_strokes,
+           sizeof(*path_p));
+         path_q=(PointInfo *) ResizeQuantumMemory(path_q,(size_t) max_strokes,
+           sizeof(*path_q));
+         if ((path_p == (PointInfo *) NULL) || (path_q == (PointInfo *) NULL))
+           {
+             polygon_primitive=(PrimitiveInfo *)
+               RelinquishMagickMemory(polygon_primitive);
+             return((PrimitiveInfo *) NULL);
+           }
+      }
+    dot_product=dx.q*dy.p-dx.p*dy.q;
+    if (dot_product <= 0.0)
+      switch (draw_info->linejoin)
+      {
+        case BevelJoin:
+        {
+          path_q[q++]=box_q[1];
+          path_q[q++]=box_q[2];
+          dot_product=(box_q[4].x-box_p[4].x)*(box_q[4].x-box_p[4].x)+
+            (box_q[4].y-box_p[4].y)*(box_q[4].y-box_p[4].y);
+          if (dot_product <= miterlimit)
+            path_p[p++]=box_p[4];
+          else
+            {
+              path_p[p++]=box_p[1];
+              path_p[p++]=box_p[2];
+            }
+          break;
+        }
+        case MiterJoin:
+        {
+          dot_product=(box_q[4].x-box_p[4].x)*(box_q[4].x-box_p[4].x)+
+            (box_q[4].y-box_p[4].y)*(box_q[4].y-box_p[4].y);
+          if (dot_product <= miterlimit)
+            {
+              path_q[q++]=box_q[4];
+              path_p[p++]=box_p[4];
+            }
+          else
+            {
+              path_q[q++]=box_q[1];
+              path_q[q++]=box_q[2];
+              path_p[p++]=box_p[1];
+              path_p[p++]=box_p[2];
+            }
+          break;
+        }
+        case RoundJoin:
+        {
+          dot_product=(box_q[4].x-box_p[4].x)*(box_q[4].x-box_p[4].x)+
+            (box_q[4].y-box_p[4].y)*(box_q[4].y-box_p[4].y);
+          if (dot_product <= miterlimit)
+            path_p[p++]=box_p[4];
+          else
+            {
+              path_p[p++]=box_p[1];
+              path_p[p++]=box_p[2];
+            }
+          center=polygon_primitive[n].point;
+          theta.p=atan2(box_q[1].y-center.y,box_q[1].x-center.x);
+          theta.q=atan2(box_q[2].y-center.y,box_q[2].x-center.x);
+          if (theta.q < theta.p)
+            theta.q+=(MagickRealType) (2.0*MagickPI);
+          arc_segments=(size_t) ceil((double) ((theta.q-theta.p)/
+            (2.0*sqrt((double) (1.0/mid)))));
+          path_q[q].x=box_q[1].x;
+          path_q[q].y=box_q[1].y;
+          q++;
+          for (j=1; j < (ssize_t) arc_segments; j++)
+          {
+            delta_theta=(MagickRealType) (j*(theta.q-theta.p)/arc_segments);
+            path_q[q].x=(double) (center.x+mid*cos(fmod((double)
+              (theta.p+delta_theta),DegreesToRadians(360.0))));
+            path_q[q].y=(double) (center.y+mid*sin(fmod((double)
+              (theta.p+delta_theta),DegreesToRadians(360.0))));
+            q++;
+          }
+          path_q[q++]=box_q[2];
+          break;
+        }
+        default:
+          break;
+      }
+    else
+      switch (draw_info->linejoin)
+      {
+        case BevelJoin:
+        {
+          path_p[p++]=box_p[1];
+          path_p[p++]=box_p[2];
+          dot_product=(box_q[4].x-box_p[4].x)*(box_q[4].x-box_p[4].x)+
+            (box_q[4].y-box_p[4].y)*(box_q[4].y-box_p[4].y);
+          if (dot_product <= miterlimit)
+            path_q[q++]=box_q[4];
+          else
+            {
+              path_q[q++]=box_q[1];
+              path_q[q++]=box_q[2];
+            }
+          break;
+        }
+        case MiterJoin:
+        {
+          dot_product=(box_q[4].x-box_p[4].x)*(box_q[4].x-box_p[4].x)+
+            (box_q[4].y-box_p[4].y)*(box_q[4].y-box_p[4].y);
+          if (dot_product <= miterlimit)
+            {
+              path_q[q++]=box_q[4];
+              path_p[p++]=box_p[4];
+            }
+          else
+            {
+              path_q[q++]=box_q[1];
+              path_q[q++]=box_q[2];
+              path_p[p++]=box_p[1];
+              path_p[p++]=box_p[2];
+            }
+          break;
+        }
+        case RoundJoin:
+        {
+          dot_product=(box_q[4].x-box_p[4].x)*(box_q[4].x-box_p[4].x)+
+            (box_q[4].y-box_p[4].y)*(box_q[4].y-box_p[4].y);
+          if (dot_product <= miterlimit)
+            path_q[q++]=box_q[4];
+          else
+            {
+              path_q[q++]=box_q[1];
+              path_q[q++]=box_q[2];
+            }
+          center=polygon_primitive[n].point;
+          theta.p=atan2(box_p[1].y-center.y,box_p[1].x-center.x);
+          theta.q=atan2(box_p[2].y-center.y,box_p[2].x-center.x);
+          if (theta.p < theta.q)
+            theta.p+=(MagickRealType) (2.0*MagickPI);
+          arc_segments=(size_t) ceil((double) ((theta.p-theta.q)/
+            (2.0*sqrt((double) (1.0/mid)))));
+          path_p[p++]=box_p[1];
+          for (j=1; j < (ssize_t) arc_segments; j++)
+          {
+            delta_theta=(MagickRealType) (j*(theta.q-theta.p)/arc_segments);
+            path_p[p].x=(double) (center.x+mid*cos(fmod((double)
+              (theta.p+delta_theta),DegreesToRadians(360.0))));
+            path_p[p].y=(double) (center.y+mid*sin(fmod((double)
+              (theta.p+delta_theta),DegreesToRadians(360.0))));
+            p++;
+          }
+          path_p[p++]=box_p[2];
+          break;
+        }
+        default:
+          break;
+      }
+    slope.p=slope.q;
+    inverse_slope.p=inverse_slope.q;
+    box_p[0]=box_p[2];
+    box_p[1]=box_p[3];
+    box_q[0]=box_q[2];
+    box_q[1]=box_q[3];
+    dx.p=dx.q;
+    dy.p=dy.q;
+    n=i;
+  }
+  path_p[p++]=box_p[1];
+  path_q[q++]=box_q[1];
+  /*
+    Trace stroked polygon.
+  */
+  stroke_polygon=(PrimitiveInfo *) AcquireQuantumMemory((size_t)
+    (p+q+2UL*closed_path+2UL),sizeof(*stroke_polygon));
+  if (stroke_polygon != (PrimitiveInfo *) NULL)
+    {
+      for (i=0; i < (ssize_t) p; i++)
+      {
+        stroke_polygon[i]=polygon_primitive[0];
+        stroke_polygon[i].point=path_p[i];
+      }
+      if (closed_path != MagickFalse)
+        {
+          stroke_polygon[i]=polygon_primitive[0];
+          stroke_polygon[i].point=stroke_polygon[0].point;
+          i++;
+        }
+      for ( ; i < (ssize_t) (p+q+closed_path); i++)
+      {
+        stroke_polygon[i]=polygon_primitive[0];
+        stroke_polygon[i].point=path_q[p+q+closed_path-(i+1)];
+      }
+      if (closed_path != MagickFalse)
+        {
+          stroke_polygon[i]=polygon_primitive[0];
+          stroke_polygon[i].point=stroke_polygon[p+closed_path].point;
+          i++;
+        }
+      stroke_polygon[i]=polygon_primitive[0];
+      stroke_polygon[i].point=stroke_polygon[0].point;
+      i++;
+      stroke_polygon[i].primitive=UndefinedPrimitive;
+      stroke_polygon[0].coordinates=(size_t) (p+q+2*closed_path+1);
+    }
+  path_p=(PointInfo *) RelinquishMagickMemory(path_p);
+  path_q=(PointInfo *) RelinquishMagickMemory(path_q);
+  polygon_primitive=(PrimitiveInfo *) RelinquishMagickMemory(polygon_primitive);
+  return(stroke_polygon);
+}
diff --git a/MagickCore/draw.h b/MagickCore/draw.h
new file mode 100644
index 0000000..66e80aa
--- /dev/null
+++ b/MagickCore/draw.h
@@ -0,0 +1,394 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore drawing methods.
+*/
+#ifndef _MAGICKCORE_DRAW_H
+#define _MAGICKCORE_DRAW_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/type.h"
+
+typedef enum
+{
+  UndefinedAlign,
+  LeftAlign,
+  CenterAlign,
+  RightAlign
+} AlignType;
+
+typedef enum
+{
+  UndefinedPathUnits,
+  UserSpace,
+  UserSpaceOnUse,
+  ObjectBoundingBox
+} ClipPathUnits;
+
+typedef enum
+{
+  UndefinedDecoration,
+  NoDecoration,
+  UnderlineDecoration,
+  OverlineDecoration,
+  LineThroughDecoration
+} DecorationType;
+
+typedef enum
+{
+  UndefinedDirection,
+  RightToLeftDirection,
+  LeftToRightDirection
+} DirectionType;
+
+typedef enum
+{
+  UndefinedRule,
+#undef EvenOddRule
+  EvenOddRule,
+  NonZeroRule
+} FillRule;
+
+typedef enum
+{
+  UndefinedGradient,
+  LinearGradient,
+  RadialGradient
+} GradientType;
+
+typedef enum
+{
+  UndefinedCap,
+  ButtCap,
+  RoundCap,
+  SquareCap
+} LineCap;
+
+typedef enum
+{
+  UndefinedJoin,
+  MiterJoin,
+  RoundJoin,
+  BevelJoin
+} LineJoin;
+
+typedef enum
+{
+  UndefinedMethod,
+  PointMethod,
+  ReplaceMethod,
+  FloodfillMethod,
+  FillToBorderMethod,
+  ResetMethod
+} PaintMethod;
+
+typedef enum
+{
+  UndefinedPrimitive,
+  PointPrimitive,
+  LinePrimitive,
+  RectanglePrimitive,
+  RoundRectanglePrimitive,
+  ArcPrimitive,
+  EllipsePrimitive,
+  CirclePrimitive,
+  PolylinePrimitive,
+  PolygonPrimitive,
+  BezierPrimitive,
+  ColorPrimitive,
+  MattePrimitive,
+  TextPrimitive,
+  ImagePrimitive,
+  PathPrimitive
+} PrimitiveType;
+
+typedef enum
+{
+  UndefinedReference,
+  GradientReference
+} ReferenceType;
+
+typedef enum
+{
+  UndefinedSpread,
+  PadSpread,
+  ReflectSpread,
+  RepeatSpread
+} SpreadMethod;
+
+typedef struct _PointInfo
+{ 
+  double
+    x,
+    y;
+} PointInfo;
+
+typedef struct _StopInfo
+{
+  PixelInfo
+    color;
+
+  MagickRealType
+    offset;
+} StopInfo;
+
+typedef struct _GradientInfo
+{
+  GradientType
+    type;
+
+  RectangleInfo
+    bounding_box;
+
+  SegmentInfo
+    gradient_vector;
+
+  StopInfo
+    *stops;
+
+  size_t
+    number_stops;
+
+  SpreadMethod
+    spread;
+
+  MagickBooleanType
+    debug;
+
+  size_t
+    signature;
+
+  PointInfo
+    center;
+
+  MagickRealType
+    radius;
+} GradientInfo;
+
+typedef struct _ElementReference
+{
+  char
+    *id;
+
+  ReferenceType
+    type;
+
+  GradientInfo
+    gradient;
+
+  size_t
+    signature;
+
+  struct _ElementReference
+    *previous,
+    *next;
+} ElementReference;
+
+typedef struct _DrawInfo
+{
+  char
+    *primitive,
+    *geometry;
+
+  RectangleInfo
+    viewbox;
+
+  AffineMatrix
+    affine;
+
+  GravityType
+    gravity;
+
+  PixelPacket
+    fill,
+    stroke;
+
+  double
+    stroke_width;
+
+  GradientInfo
+    gradient;
+
+  Image
+    *fill_pattern,
+    *stroke_pattern;
+
+  MagickBooleanType
+    stroke_antialias,
+    text_antialias;
+
+  FillRule
+    fill_rule;
+
+  LineCap
+    linecap;
+
+  LineJoin
+    linejoin;
+
+  size_t
+    miterlimit;
+
+  double
+    dash_offset;
+
+  DecorationType
+    decorate;
+
+  CompositeOperator
+    compose;
+
+  char
+    *text;
+
+  size_t
+    face;
+
+  char
+    *font,
+    *metrics,
+    *family;
+
+  StyleType
+    style;
+
+  StretchType
+    stretch;
+
+  size_t
+    weight;
+
+  char
+    *encoding;
+
+  double
+    pointsize;
+
+  char
+    *density;
+
+  AlignType
+    align;
+
+  PixelPacket
+    undercolor,
+    border_color;
+
+  char
+    *server_name;
+
+  double
+    *dash_pattern;
+
+  char
+    *clip_mask;
+
+  SegmentInfo
+    bounds;
+
+  ClipPathUnits
+    clip_units;
+
+  Quantum
+    alpha;
+
+  MagickBooleanType
+    render;
+
+  ElementReference
+    element_reference;
+
+  MagickBooleanType
+    debug;
+
+  size_t
+    signature;
+
+  double
+    kerning,
+    interword_spacing,
+    interline_spacing;
+
+  DirectionType
+    direction;
+} DrawInfo;
+
+typedef struct _PrimitiveInfo
+{
+  PointInfo
+    point;
+
+  size_t
+    coordinates;
+
+  PrimitiveType
+    primitive;
+
+  PaintMethod
+    method;
+
+  char
+    *text;
+} PrimitiveInfo;
+
+typedef struct _TypeMetric
+{
+  PointInfo
+    pixels_per_em;
+
+  double
+    ascent,
+    descent,
+    width,
+    height,
+    max_advance,
+    underline_position,
+    underline_thickness;
+
+  SegmentInfo
+    bounds;
+
+  PointInfo
+    origin;
+} TypeMetric;
+
+extern MagickExport DrawInfo
+  *AcquireDrawInfo(void),
+  *CloneDrawInfo(const ImageInfo *,const DrawInfo *),
+  *DestroyDrawInfo(DrawInfo *);
+
+extern MagickExport MagickBooleanType
+  DrawAffineImage(Image *,const Image *,const AffineMatrix *),
+  DrawClipPath(Image *,const DrawInfo *,const char *),
+  DrawGradientImage(Image *,const DrawInfo *),
+  DrawImage(Image *,const DrawInfo *),
+  DrawPatternPath(Image *,const DrawInfo *,const char *,Image **),
+  DrawPrimitive(Image *,const DrawInfo *,const PrimitiveInfo *);
+
+extern MagickExport void
+  GetAffineMatrix(AffineMatrix *),
+  GetDrawInfo(const ImageInfo *,DrawInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/effect.c b/MagickCore/effect.c
new file mode 100644
index 0000000..5de76f8
--- /dev/null
+++ b/MagickCore/effect.c
@@ -0,0 +1,5405 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                   EEEEE  FFFFF  FFFFF  EEEEE  CCCC  TTTTT                   %
+%                   E      F      F      E     C        T                     %
+%                   EEE    FFF    FFF    EEE   C        T                     %
+%                   E      F      F      E     C        T                     %
+%                   EEEEE  F      F      EEEEE  CCCC    T                     %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Image Effects Methods                      %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                 October 1996                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/accelerate.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/morphology.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/random-private.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resample-private.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/threshold.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A d a p t i v e B l u r I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AdaptiveBlurImage() adaptively blurs the image by blurring less
+%  intensely near image edges and more intensely far from edges.  We blur the
+%  image with a Gaussian operator of the given radius and standard deviation
+%  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
+%  radius of 0 and AdaptiveBlurImage() selects a suitable radius for you.
+%
+%  The format of the AdaptiveBlurImage method is:
+%
+%      Image *AdaptiveBlurImage(const Image *image,const double radius,
+%        const double sigma,ExceptionInfo *exception)
+%      Image *AdaptiveBlurImageChannel(const Image *image,
+%        const ChannelType channel,double radius,const double sigma,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Laplacian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  Image
+    *blur_image;
+
+  blur_image=AdaptiveBlurImageChannel(image,DefaultChannels,radius,sigma,
+    exception);
+  return(blur_image);
+}
+
+MagickExport Image *AdaptiveBlurImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  ExceptionInfo *exception)
+{
+#define AdaptiveBlurImageTag  "Convolve/Image"
+#define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
+
+  CacheView
+    *blur_view,
+    *edge_view,
+    *image_view;
+
+  double
+    **kernel,
+    normalize;
+
+  Image
+    *blur_image,
+    *edge_image,
+    *gaussian_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    k,
+    u,
+    v,
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  blur_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (blur_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (fabs(sigma) <= MagickEpsilon)
+    return(blur_image);
+  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&blur_image->exception);
+      blur_image=DestroyImage(blur_image);
+      return((Image *) NULL);
+    }
+  /*
+    Edge detect the image brighness channel, level, blur, and level again.
+  */
+  edge_image=EdgeImage(image,radius,exception);
+  if (edge_image == (Image *) NULL)
+    {
+      blur_image=DestroyImage(blur_image);
+      return((Image *) NULL);
+    }
+  (void) LevelImage(edge_image,"20%,95%");
+  gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception);
+  if (gaussian_image != (Image *) NULL)
+    {
+      edge_image=DestroyImage(edge_image);
+      edge_image=gaussian_image;
+    }
+  (void) LevelImage(edge_image,"10%,95%");
+  /*
+    Create a set of kernels from maximum (radius,sigma) to minimum.
+  */
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double **) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  if (kernel == (double **) NULL)
+    {
+      edge_image=DestroyImage(edge_image);
+      blur_image=DestroyImage(blur_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
+  for (i=0; i < (ssize_t) width; i+=2)
+  {
+    kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)*
+      sizeof(**kernel));
+    if (kernel[i] == (double *) NULL)
+      break;
+    normalize=0.0;
+    j=(ssize_t) (width-i)/2;
+    k=0;
+    for (v=(-j); v <= j; v++)
+    {
+      for (u=(-j); u <= j; u++)
+      {
+        kernel[i][k]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+          MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+        normalize+=kernel[i][k];
+        k++;
+      }
+    }
+    if (fabs(normalize) <= MagickEpsilon)
+      normalize=1.0;
+    normalize=1.0/normalize;
+    for (k=0; k < (j*j); k++)
+      kernel[i][k]=normalize*kernel[i][k];
+  }
+  if (i < (ssize_t) width)
+    {
+      for (i-=2; i >= 0; i-=2)
+        kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
+      kernel=(double **) RelinquishMagickMemory(kernel);
+      edge_image=DestroyImage(edge_image);
+      blur_image=DestroyImage(blur_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Adaptively blur image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  SetPixelInfoBias(image,&bias);
+  image_view=AcquireCacheView(image);
+  edge_view=AcquireCacheView(edge_image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict r;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if ((r == (const Quantum *) NULL) || (q == (const Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        alpha,
+        gamma;
+
+      register const double
+        *restrict k;
+
+      register ssize_t
+        i,
+        u,
+        v;
+
+      gamma=0.0;
+      i=(ssize_t) ceil((double) width*QuantumScale*
+        GetPixelIntensity(edge_image,r)-0.5);
+      if (i < 0)
+        i=0;
+      else
+        if (i > (ssize_t) width)
+          i=(ssize_t) width;
+      if ((i & 0x01) != 0)
+        i--;
+      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
+        (ssize_t) ((width-i)/2L),width-i,width-i,exception);
+      if (p == (const Quantum *) NULL)
+        break;
+      pixel=bias;
+      k=kernel[i];
+      for (v=0; v < (ssize_t) (width-i); v++)
+      {
+        for (u=0; u < (ssize_t) (width-i); u++)
+        {
+          alpha=1.0;
+          if (((channel & AlphaChannel) != 0) &&
+              (image->matte != MagickFalse))
+            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
+          if ((channel & RedChannel) != 0)
+            pixel.red+=(*k)*alpha*GetPixelRed(image,p);
+          if ((channel & GreenChannel) != 0)
+            pixel.green+=(*k)*alpha*GetPixelGreen(image,p);
+          if ((channel & BlueChannel) != 0)
+            pixel.blue+=(*k)*alpha*GetPixelBlue(image,p);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            pixel.black+=(*k)*alpha*GetPixelBlack(image,p);
+          if ((channel & AlphaChannel) != 0)
+            pixel.alpha+=(*k)*GetPixelAlpha(image,p);
+          gamma+=(*k)*alpha;
+          k++;
+          p+=GetPixelChannels(image);
+        }
+      }
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
+      if ((channel & AlphaChannel) != 0)
+        SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+      q+=GetPixelChannels(blur_image);
+      r+=GetPixelChannels(edge_image);
+    }
+    if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_AdaptiveBlurImageChannel)
+#endif
+        proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  blur_image->type=image->type;
+  blur_view=DestroyCacheView(blur_view);
+  edge_view=DestroyCacheView(edge_view);
+  image_view=DestroyCacheView(image_view);
+  edge_image=DestroyImage(edge_image);
+  for (i=0; i < (ssize_t) width;  i+=2)
+    kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
+  kernel=(double **) RelinquishMagickMemory(kernel);
+  if (status == MagickFalse)
+    blur_image=DestroyImage(blur_image);
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A d a p t i v e S h a r p e n I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AdaptiveSharpenImage() adaptively sharpens the image by sharpening more
+%  intensely near image edges and less intensely far from edges. We sharpen the
+%  image with a Gaussian operator of the given radius and standard deviation
+%  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
+%  radius of 0 and AdaptiveSharpenImage() selects a suitable radius for you.
+%
+%  The format of the AdaptiveSharpenImage method is:
+%
+%      Image *AdaptiveSharpenImage(const Image *image,const double radius,
+%        const double sigma,ExceptionInfo *exception)
+%      Image *AdaptiveSharpenImageChannel(const Image *image,
+%        const ChannelType channel,double radius,const double sigma,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Laplacian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  Image
+    *sharp_image;
+
+  sharp_image=AdaptiveSharpenImageChannel(image,DefaultChannels,radius,sigma,
+    exception);
+  return(sharp_image);
+}
+
+MagickExport Image *AdaptiveSharpenImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  ExceptionInfo *exception)
+{
+#define AdaptiveSharpenImageTag  "Convolve/Image"
+#define MagickSigma  (fabs(sigma) <= MagickEpsilon ? 1.0 : sigma)
+
+  CacheView
+    *sharp_view,
+    *edge_view,
+    *image_view;
+
+  double
+    **kernel,
+    normalize;
+
+  Image
+    *sharp_image,
+    *edge_image,
+    *gaussian_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    k,
+    u,
+    v,
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  sharp_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (sharp_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (fabs(sigma) <= MagickEpsilon)
+    return(sharp_image);
+  if (SetImageStorageClass(sharp_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&sharp_image->exception);
+      sharp_image=DestroyImage(sharp_image);
+      return((Image *) NULL);
+    }
+  /*
+    Edge detect the image brighness channel, level, sharp, and level again.
+  */
+  edge_image=EdgeImage(image,radius,exception);
+  if (edge_image == (Image *) NULL)
+    {
+      sharp_image=DestroyImage(sharp_image);
+      return((Image *) NULL);
+    }
+  (void) LevelImage(edge_image,"20%,95%");
+  gaussian_image=GaussianBlurImage(edge_image,radius,sigma,exception);
+  if (gaussian_image != (Image *) NULL)
+    {
+      edge_image=DestroyImage(edge_image);
+      edge_image=gaussian_image;
+    }
+  (void) LevelImage(edge_image,"10%,95%");
+  /*
+    Create a set of kernels from maximum (radius,sigma) to minimum.
+  */
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double **) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  if (kernel == (double **) NULL)
+    {
+      edge_image=DestroyImage(edge_image);
+      sharp_image=DestroyImage(sharp_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  (void) ResetMagickMemory(kernel,0,(size_t) width*sizeof(*kernel));
+  for (i=0; i < (ssize_t) width; i+=2)
+  {
+    kernel[i]=(double *) AcquireQuantumMemory((size_t) (width-i),(width-i)*
+      sizeof(**kernel));
+    if (kernel[i] == (double *) NULL)
+      break;
+    normalize=0.0;
+    j=(ssize_t) (width-i)/2;
+    k=0;
+    for (v=(-j); v <= j; v++)
+    {
+      for (u=(-j); u <= j; u++)
+      {
+        kernel[i][k]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+          MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+        normalize+=kernel[i][k];
+        k++;
+      }
+    }
+    if (fabs(normalize) <= MagickEpsilon)
+      normalize=1.0;
+    normalize=1.0/normalize;
+    for (k=0; k < (j*j); k++)
+      kernel[i][k]=normalize*kernel[i][k];
+  }
+  if (i < (ssize_t) width)
+    {
+      for (i-=2; i >= 0; i-=2)
+        kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
+      kernel=(double **) RelinquishMagickMemory(kernel);
+      edge_image=DestroyImage(edge_image);
+      sharp_image=DestroyImage(sharp_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Adaptively sharpen image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  SetPixelInfoBias(image,&bias);
+  image_view=AcquireCacheView(image);
+  edge_view=AcquireCacheView(edge_image);
+  sharp_view=AcquireCacheView(sharp_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) sharp_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict r;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
+      exception);
+    if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) sharp_image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        alpha,
+        gamma;
+
+      register const double
+        *restrict k;
+
+      register ssize_t
+        i,
+        u,
+        v;
+
+      gamma=0.0;
+      i=(ssize_t) ceil((double) width*QuantumScale*
+        GetPixelIntensity(edge_image,r)-0.5);
+      if (i < 0)
+        i=0;
+      else
+        if (i > (ssize_t) width)
+          i=(ssize_t) width;
+      if ((i & 0x01) != 0)
+        i--;
+      p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-i)/2L),y-
+        (ssize_t) ((width-i)/2L),width-i,width-i,exception);
+      if (p == (const Quantum *) NULL)
+        break;
+      k=kernel[i];
+      pixel=bias;
+      for (v=0; v < (ssize_t) (width-i); v++)
+      {
+        for (u=0; u < (ssize_t) (width-i); u++)
+        {
+          alpha=1.0;
+          if (((channel & AlphaChannel) != 0) &&
+              (image->matte != MagickFalse))
+            alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
+          if ((channel & RedChannel) != 0)
+            pixel.red+=(*k)*alpha*GetPixelRed(image,p);
+          if ((channel & GreenChannel) != 0)
+            pixel.green+=(*k)*alpha*GetPixelGreen(image,p);
+          if ((channel & BlueChannel) != 0)
+            pixel.blue+=(*k)*alpha*GetPixelBlue(image,p);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            pixel.black+=(*k)*alpha*GetPixelBlack(image,p);
+          if ((channel & AlphaChannel) != 0)
+            pixel.alpha+=(*k)*GetPixelAlpha(image,p);
+          gamma+=(*k)*alpha;
+          k++;
+          p+=GetPixelChannels(image);
+        }
+      }
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(sharp_image,ClampToQuantum(gamma*pixel.red),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(sharp_image,ClampToQuantum(gamma*pixel.green),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(sharp_image,ClampToQuantum(gamma*pixel.blue),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(sharp_image,ClampToQuantum(gamma*pixel.black),q);
+      if ((channel & AlphaChannel) != 0)
+        SetPixelAlpha(sharp_image,ClampToQuantum(pixel.alpha),q);
+      q+=GetPixelChannels(sharp_image);
+      r+=GetPixelChannels(edge_image);
+    }
+    if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_AdaptiveSharpenImageChannel)
+#endif
+        proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  sharp_image->type=image->type;
+  sharp_view=DestroyCacheView(sharp_view);
+  edge_view=DestroyCacheView(edge_view);
+  image_view=DestroyCacheView(image_view);
+  edge_image=DestroyImage(edge_image);
+  for (i=0; i < (ssize_t) width;  i+=2)
+    kernel[i]=(double *) RelinquishMagickMemory(kernel[i]);
+  kernel=(double **) RelinquishMagickMemory(kernel);
+  if (status == MagickFalse)
+    sharp_image=DestroyImage(sharp_image);
+  return(sharp_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     B l u r I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BlurImage() blurs an image.  We convolve the image with a Gaussian operator
+%  of the given radius and standard deviation (sigma).  For reasonable results,
+%  the radius should be larger than sigma.  Use a radius of 0 and BlurImage()
+%  selects a suitable radius for you.
+%
+%  BlurImage() differs from GaussianBlurImage() in that it uses a separable
+%  kernel which is faster but mathematically equivalent to the non-separable
+%  kernel.
+%
+%  The format of the BlurImage method is:
+%
+%      Image *BlurImage(const Image *image,const double radius,
+%        const double sigma,ExceptionInfo *exception)
+%      Image *BlurImageChannel(const Image *image,const ChannelType channel,
+%        const double radius,const double sigma,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *BlurImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  Image
+    *blur_image;
+
+  blur_image=BlurImageChannel(image,DefaultChannels,radius,sigma,exception);
+  return(blur_image);
+}
+
+static double *GetBlurKernel(const size_t width,const double sigma)
+{
+  double
+    *kernel,
+    normalize;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j,
+    k;
+
+  /*
+    Generate a 1-D convolution kernel.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    return(0);
+  normalize=0.0;
+  j=(ssize_t) width/2;
+  i=0;
+  for (k=(-j); k <= j; k++)
+  {
+    kernel[i]=(double) (exp(-((double) k*k)/(2.0*MagickSigma*MagickSigma))/
+      (MagickSQ2PI*MagickSigma));
+    normalize+=kernel[i];
+    i++;
+  }
+  for (i=0; i < (ssize_t) width; i++)
+    kernel[i]/=normalize;
+  return(kernel);
+}
+
+MagickExport Image *BlurImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  ExceptionInfo *exception)
+{
+#define BlurImageTag  "Blur/Image"
+
+  CacheView
+    *blur_view,
+    *image_view;
+
+  double
+    *kernel;
+
+  Image
+    *blur_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    x,
+    y;
+
+  /*
+    Initialize blur image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (blur_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (fabs(sigma) <= MagickEpsilon)
+    return(blur_image);
+  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&blur_image->exception);
+      blur_image=DestroyImage(blur_image);
+      return((Image *) NULL);
+    }
+  width=GetOptimalKernelWidth1D(radius,sigma);
+  kernel=GetBlurKernel(width,sigma);
+  if (kernel == (double *) NULL)
+    {
+      blur_image=DestroyImage(blur_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      register const double
+        *k;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  BlurImage with %.20g kernel:",(double) width);
+      message=AcquireString("");
+      k=kernel;
+      for (i=0; i < (ssize_t) width; i++)
+      {
+        *message='\0';
+        (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) i);
+        (void) ConcatenateString(&message,format);
+        (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
+        (void) ConcatenateString(&message,format);
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  /*
+    Blur rows.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  SetPixelInfoBias(image,&bias);
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y,
+      image->columns+width,1,exception);
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict kernel_pixels;
+
+      register ssize_t
+        i;
+
+      pixel=bias;
+      k=kernel;
+      kernel_pixels=p;
+      if (((channel & AlphaChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (ssize_t) width; i++)
+          {
+            pixel.red+=(*k)*GetPixelRed(image,kernel_pixels);
+            pixel.green+=(*k)*GetPixelGreen(image,kernel_pixels);
+            pixel.blue+=(*k)*GetPixelBlue(image,kernel_pixels);
+            if (image->colorspace == CMYKColorspace)
+              pixel.black+=(*k)*GetPixelBlack(image,kernel_pixels);
+            k++;
+            kernel_pixels+=GetPixelChannels(image);
+          }
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,ClampToQuantum(pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,ClampToQuantum(pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,ClampToQuantum(pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (blur_image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,ClampToQuantum(pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (ssize_t) width; i++)
+              {
+                pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels);
+                k++;
+                kernel_pixels+=GetPixelChannels(image);
+              }
+              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < (ssize_t) width; i++)
+          {
+            alpha=(MagickRealType) (QuantumScale*
+              GetPixelAlpha(image,kernel_pixels));
+            pixel.red+=(*k)*alpha*GetPixelRed(image,kernel_pixels);
+            pixel.green+=(*k)*alpha*GetPixelGreen(image,kernel_pixels);
+            pixel.blue+=(*k)*alpha*GetPixelBlue(image,kernel_pixels);
+            if (image->colorspace == CMYKColorspace)
+              pixel.black+=(*k)*alpha*GetPixelBlack(image,kernel_pixels);
+            gamma+=(*k)*alpha;
+            k++;
+            kernel_pixels+=GetPixelChannels(image);
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (blur_image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (ssize_t) width; i++)
+              {
+                pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels);
+                k++;
+                kernel_pixels+=GetPixelChannels(image);
+              }
+              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(blur_image);
+    }
+    if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_BlurImageChannel)
+#endif
+        proceed=SetImageProgress(image,BlurImageTag,progress++,blur_image->rows+
+          blur_image->columns);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  blur_view=DestroyCacheView(blur_view);
+  image_view=DestroyCacheView(image_view);
+  /*
+    Blur columns.
+  */
+  image_view=AcquireCacheView(blur_image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (x=0; x < (ssize_t) blur_image->columns; x++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      y;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,x,-((ssize_t) width/2L),1,
+      image->rows+width,exception);
+    q=GetCacheViewAuthenticPixels(blur_view,x,0,1,blur_image->rows,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (y=0; y < (ssize_t) blur_image->rows; y++)
+    {
+      PixelInfo
+        pixel;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict kernel_pixels;
+
+      register ssize_t
+        i;
+
+      pixel=bias;
+      k=kernel;
+      kernel_pixels=p;
+      if (((channel & AlphaChannel) == 0) || (blur_image->matte == MagickFalse))
+        {
+          for (i=0; i < (ssize_t) width; i++)
+          {
+            pixel.red+=(*k)*GetPixelRed(blur_image,kernel_pixels);
+            pixel.green+=(*k)*GetPixelGreen(blur_image,kernel_pixels);
+            pixel.blue+=(*k)*GetPixelBlue(blur_image,kernel_pixels);
+            if (blur_image->colorspace == CMYKColorspace)
+              pixel.black+=(*k)*GetPixelBlack(blur_image,kernel_pixels);
+            k++;
+            kernel_pixels+=GetPixelChannels(blur_image);
+          }
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,ClampToQuantum(pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,ClampToQuantum(pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,ClampToQuantum(pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (blur_image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,ClampToQuantum(pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (ssize_t) width; i++)
+              {
+                pixel.alpha+=(*k)*GetPixelAlpha(blur_image,kernel_pixels);
+                k++;
+                kernel_pixels+=GetPixelChannels(blur_image);
+              }
+              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < (ssize_t) width; i++)
+          {
+            alpha=(MagickRealType) (QuantumScale*
+              GetPixelAlpha(blur_image,kernel_pixels));
+            pixel.red+=(*k)*alpha*GetPixelRed(blur_image,kernel_pixels);
+            pixel.green+=(*k)*alpha*GetPixelGreen(blur_image,kernel_pixels);
+            pixel.blue+=(*k)*alpha*GetPixelBlue(blur_image,kernel_pixels);
+            if (blur_image->colorspace == CMYKColorspace)
+              pixel.black+=(*k)*alpha*GetPixelBlack(blur_image,kernel_pixels);
+            gamma+=(*k)*alpha;
+            k++;
+            kernel_pixels+=GetPixelChannels(blur_image);
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (blur_image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=kernel;
+              kernel_pixels=p;
+              for (i=0; i < (ssize_t) width; i++)
+              {
+                pixel.alpha+=(*k)*GetPixelAlpha(blur_image,kernel_pixels);
+                k++;
+                kernel_pixels+=GetPixelChannels(blur_image);
+              }
+              SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      p+=GetPixelChannels(blur_image);
+      q+=GetPixelChannels(blur_image);
+    }
+    if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (blur_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_BlurImageChannel)
+#endif
+        proceed=SetImageProgress(blur_image,BlurImageTag,progress++,
+          blur_image->rows+blur_image->columns);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  blur_view=DestroyCacheView(blur_view);
+  image_view=DestroyCacheView(image_view);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  if (status == MagickFalse)
+    blur_image=DestroyImage(blur_image);
+  blur_image->type=image->type;
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o n v o l v e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvolveImage() applies a custom convolution kernel to the image.
+%
+%  The format of the ConvolveImage method is:
+%
+%      Image *ConvolveImage(const Image *image,const size_t order,
+%        const double *kernel,ExceptionInfo *exception)
+%      Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
+%        const size_t order,const double *kernel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o order: the number of columns and rows in the filter kernel.
+%
+%    o kernel: An array of double representing the convolution kernel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *ConvolveImage(const Image *image,const size_t order,
+  const double *kernel,ExceptionInfo *exception)
+{
+  Image
+    *convolve_image;
+
+  convolve_image=ConvolveImageChannel(image,DefaultChannels,order,kernel,
+    exception);
+  return(convolve_image);
+}
+
+MagickExport Image *ConvolveImageChannel(const Image *image,
+  const ChannelType channel,const size_t order,const double *kernel,
+  ExceptionInfo *exception)
+{
+#define ConvolveImageTag  "Convolve/Image"
+
+  CacheView
+    *convolve_view,
+    *image_view;
+
+  double
+    *normal_kernel;
+
+  Image
+    *convolve_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  MagickRealType
+    gamma;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize convolve image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=order;
+  if ((width % 2) == 0)
+    ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
+  convolve_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (convolve_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(convolve_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&convolve_image->exception);
+      convolve_image=DestroyImage(convolve_image);
+      return((Image *) NULL);
+    }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      register const double
+        *k;
+
+      ssize_t
+        u,
+        v;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  ConvolveImage with %.20gx%.20g kernel:",(double) width,(double)
+        width);
+      message=AcquireString("");
+      k=kernel;
+      for (v=0; v < (ssize_t) width; v++)
+      {
+        *message='\0';
+        (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
+          (void) ConcatenateString(&message,format);
+        }
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  /*
+    Normalize kernel.
+  */
+  normal_kernel=(double *) AcquireQuantumMemory(width*width,
+    sizeof(*normal_kernel));
+  if (normal_kernel == (double *) NULL)
+    {
+      convolve_image=DestroyImage(convolve_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  gamma=0.0;
+  for (i=0; i < (ssize_t) (width*width); i++)
+    gamma+=kernel[i];
+  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+  for (i=0; i < (ssize_t) (width*width); i++)
+    normal_kernel[i]=gamma*kernel[i];
+  /*
+    Convolve image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  SetPixelInfoBias(image,&bias);
+  image_view=AcquireCacheView(image);
+  convolve_view=AcquireCacheView(convolve_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+      (width/2L),image->columns+width,width,exception);
+    q=GetCacheViewAuthenticPixels(convolve_view,0,y,convolve_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict kernel_pixels;
+
+      register ssize_t
+        u;
+
+      ssize_t
+        v;
+
+      pixel=bias;
+      k=normal_kernel;
+      kernel_pixels=p;
+      if (((channel & AlphaChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (v=0; v < (ssize_t) width; v++)
+          {
+            for (u=0; u < (ssize_t) width; u++)
+            {
+              pixel.red+=(*k)*GetPixelRed(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.green+=(*k)*GetPixelGreen(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.blue+=(*k)*GetPixelBlue(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              if (image->colorspace == CMYKColorspace)
+                pixel.black+=(*k)*GetPixelBlack(image,kernel_pixels+u*
+                  GetPixelChannels(image));
+              k++;
+            }
+            kernel_pixels+=(image->columns+width)*GetPixelChannels(image);
+          }
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(convolve_image,ClampToQuantum(pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(convolve_image,ClampToQuantum(pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(convolve_image,ClampToQuantum(pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(convolve_image,ClampToQuantum(pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=normal_kernel;
+              kernel_pixels=p;
+              for (v=0; v < (ssize_t) width; v++)
+              {
+                for (u=0; u < (ssize_t) width; u++)
+                {
+                  pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels+u*
+                    GetPixelChannels(image));
+                  k++;
+                }
+                kernel_pixels+=(image->columns+width)*
+                  GetPixelChannels(image);
+              }
+              SetPixelAlpha(convolve_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (v=0; v < (ssize_t) width; v++)
+          {
+            for (u=0; u < (ssize_t) width; u++)
+            {
+              alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,
+                kernel_pixels+u*GetPixelChannels(image)));
+              pixel.red+=(*k)*alpha*GetPixelRed(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.green+=(*k)*alpha*GetPixelGreen(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.blue+=(*k)*alpha*GetPixelBlue(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              if (image->colorspace == CMYKColorspace)
+                pixel.black+=(*k)*alpha*GetPixelBlack(image,kernel_pixels+u*
+                  GetPixelChannels(image));
+              gamma+=(*k)*alpha;
+              k++;
+            }
+            kernel_pixels+=(image->columns+width)*GetPixelChannels(image);
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(convolve_image,ClampToQuantum(gamma*pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(convolve_image,ClampToQuantum(gamma*pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(convolve_image,ClampToQuantum(gamma*pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(convolve_image,ClampToQuantum(gamma*pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=normal_kernel;
+              kernel_pixels=p;
+              for (v=0; v < (ssize_t) width; v++)
+              {
+                for (u=0; u < (ssize_t) width; u++)
+                {
+                  pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels+u);
+                  k++;
+                }
+                kernel_pixels+=(image->columns+width)*
+                  GetPixelChannels(image);
+              }
+              SetPixelAlpha(convolve_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(convolve_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(convolve_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ConvolveImageChannel)
+#endif
+        proceed=SetImageProgress(image,ConvolveImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  convolve_image->type=image->type;
+  convolve_view=DestroyCacheView(convolve_view);
+  image_view=DestroyCacheView(image_view);
+  normal_kernel=(double *) RelinquishMagickMemory(normal_kernel);
+  if (status == MagickFalse)
+    convolve_image=DestroyImage(convolve_image);
+  return(convolve_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D e s p e c k l e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DespeckleImage() reduces the speckle noise in an image while perserving the
+%  edges of the original image.
+%
+%  The format of the DespeckleImage method is:
+%
+%      Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void Hull(const ssize_t x_offset,const ssize_t y_offset,
+  const size_t columns,const size_t rows,Quantum *f,Quantum *g,
+  const int polarity)
+{
+  MagickRealType
+    v;
+
+  register Quantum
+    *p,
+    *q,
+    *r,
+    *s;
+
+  register ssize_t
+    x;
+
+  ssize_t
+    y;
+
+  assert(f != (Quantum *) NULL);
+  assert(g != (Quantum *) NULL);
+  p=f+(columns+2);
+  q=g+(columns+2);
+  r=p+(y_offset*((ssize_t) columns+2)+x_offset);
+  for (y=0; y < (ssize_t) rows; y++)
+  {
+    p++;
+    q++;
+    r++;
+    if (polarity > 0)
+      for (x=(ssize_t) columns; x != 0; x--)
+      {
+        v=(MagickRealType) (*p);
+        if ((MagickRealType) *r >= (v+(MagickRealType) ScaleCharToQuantum(2)))
+          v+=ScaleCharToQuantum(1);
+        *q=(Quantum) v;
+        p++;
+        q++;
+        r++;
+      }
+    else
+      for (x=(ssize_t) columns; x != 0; x--)
+      {
+        v=(MagickRealType) (*p);
+        if ((MagickRealType) *r <= (v-(MagickRealType) ScaleCharToQuantum(2)))
+          v-=(ssize_t) ScaleCharToQuantum(1);
+        *q=(Quantum) v;
+        p++;
+        q++;
+        r++;
+      }
+    p++;
+    q++;
+    r++;
+  }
+  p=f+(columns+2);
+  q=g+(columns+2);
+  r=q+(y_offset*((ssize_t) columns+2)+x_offset);
+  s=q-(y_offset*((ssize_t) columns+2)+x_offset);
+  for (y=0; y < (ssize_t) rows; y++)
+  {
+    p++;
+    q++;
+    r++;
+    s++;
+    if (polarity > 0)
+      for (x=(ssize_t) columns; x != 0; x--)
+      {
+        v=(MagickRealType) (*q);
+        if (((MagickRealType) *s >=
+             (v+(MagickRealType) ScaleCharToQuantum(2))) &&
+            ((MagickRealType) *r > v))
+          v+=ScaleCharToQuantum(1);
+        *p=(Quantum) v;
+        p++;
+        q++;
+        r++;
+        s++;
+      }
+    else
+      for (x=(ssize_t) columns; x != 0; x--)
+      {
+        v=(MagickRealType) (*q);
+        if (((MagickRealType) *s <=
+             (v-(MagickRealType) ScaleCharToQuantum(2))) &&
+            ((MagickRealType) *r < v))
+          v-=(MagickRealType) ScaleCharToQuantum(1);
+        *p=(Quantum) v;
+        p++;
+        q++;
+        r++;
+        s++;
+      }
+    p++;
+    q++;
+    r++;
+    s++;
+  }
+}
+
+MagickExport Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
+{
+#define DespeckleImageTag  "Despeckle/Image"
+
+  CacheView
+    *despeckle_view,
+    *image_view;
+
+  Image
+    *despeckle_image;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  Quantum
+    *restrict buffers,
+    *restrict pixels;
+
+  size_t
+    length,
+    number_channels;
+
+  static const ssize_t
+    X[4] = {0, 1, 1,-1},
+    Y[4] = {1, 0, 1, 1};
+
+  /*
+    Allocate despeckled image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  despeckle_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (despeckle_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(despeckle_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&despeckle_image->exception);
+      despeckle_image=DestroyImage(despeckle_image);
+      return((Image *) NULL);
+    }
+  /*
+    Allocate image buffers.
+  */
+  length=(size_t) ((image->columns+2)*(image->rows+2));
+  pixels=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels));
+  buffers=(Quantum *) AcquireQuantumMemory(length,2*sizeof(*pixels));
+  if ((pixels == (Quantum *) NULL) || (buffers == (Quantum *) NULL))
+    {
+      if (buffers != (Quantum *) NULL)
+        buffers=(Quantum *) RelinquishMagickMemory(buffers);
+      if (pixels != (Quantum *) NULL)
+        pixels=(Quantum *) RelinquishMagickMemory(pixels);
+      despeckle_image=DestroyImage(despeckle_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Reduce speckle in the image.
+  */
+  status=MagickTrue;
+  number_channels=(size_t) (image->colorspace == CMYKColorspace ? 5 : 4);
+  image_view=AcquireCacheView(image);
+  despeckle_view=AcquireCacheView(despeckle_image);
+  for (i=0; i < (ssize_t) number_channels; i++)
+  {
+    register Quantum
+      *buffer,
+      *pixel;
+
+    register ssize_t
+      k,
+      x;
+
+    ssize_t
+      j,
+      y;
+
+    if (status == MagickFalse)
+      continue;
+    pixel=pixels;
+    (void) ResetMagickMemory(pixel,0,length*sizeof(*pixel));
+    buffer=buffers;
+    j=(ssize_t) image->columns+2;
+    for (y=0; y < (ssize_t) image->rows; y++)
+    {
+      register const Quantum
+        *restrict p;
+
+      p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+      if (p == (const Quantum *) NULL)
+        break;
+      j++;
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        switch (i)
+        {
+          case 0: pixel[j]=GetPixelRed(image,p); break;
+          case 1: pixel[j]=GetPixelGreen(image,p); break;
+          case 2: pixel[j]=GetPixelBlue(image,p); break;
+          case 3: pixel[j]=GetPixelAlpha(image,p); break;
+          case 4: pixel[j]=GetPixelBlack(image,p); break;
+          default: break;
+        }
+        p+=GetPixelChannels(image);
+        j++;
+      }
+      j++;
+    }
+    (void) ResetMagickMemory(buffer,0,length*sizeof(*buffer));
+    for (k=0; k < 4; k++)
+    {
+      Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,1);
+      Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,1);
+      Hull(-X[k],-Y[k],image->columns,image->rows,pixel,buffer,-1);
+      Hull(X[k],Y[k],image->columns,image->rows,pixel,buffer,-1);
+    }
+    j=(ssize_t) image->columns+2;
+    for (y=0; y < (ssize_t) image->rows; y++)
+    {
+      MagickBooleanType
+        sync;
+
+      register Quantum
+        *restrict q;
+
+      q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
+        1,exception);
+      if (q == (const Quantum *) NULL)
+        break;
+      j++;
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        switch (i)
+        {
+          case 0: SetPixelRed(despeckle_image,pixel[j],q); break;
+          case 1: SetPixelGreen(despeckle_image,pixel[j],q); break;
+          case 2: SetPixelBlue(despeckle_image,pixel[j],q); break;
+          case 3: SetPixelAlpha(despeckle_image,pixel[j],q); break;
+          case 4: SetPixelBlack(despeckle_image,pixel[j],q); break;
+          default: break;
+        }
+        q+=GetPixelChannels(despeckle_image);
+        j++;
+      }
+      sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
+      if (sync == MagickFalse)
+        {
+          status=MagickFalse;
+          break;
+        }
+      j++;
+    }
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,DespeckleImageTag,(MagickOffsetType) i,
+          number_channels);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  despeckle_view=DestroyCacheView(despeckle_view);
+  image_view=DestroyCacheView(image_view);
+  buffers=(Quantum *) RelinquishMagickMemory(buffers);
+  pixels=(Quantum *) RelinquishMagickMemory(pixels);
+  despeckle_image->type=image->type;
+  if (status == MagickFalse)
+    despeckle_image=DestroyImage(despeckle_image);
+  return(despeckle_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     E d g e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EdgeImage() finds edges in an image.  Radius defines the radius of the
+%  convolution filter.  Use a radius of 0 and EdgeImage() selects a suitable
+%  radius for you.
+%
+%  The format of the EdgeImage method is:
+%
+%      Image *EdgeImage(const Image *image,const double radius,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius: the radius of the pixel neighborhood.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *EdgeImage(const Image *image,const double radius,
+  ExceptionInfo *exception)
+{
+  Image
+    *edge_image;
+
+  double
+    *kernel;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth1D(radius,0.5);
+  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  for (i=0; i < (ssize_t) (width*width); i++)
+    kernel[i]=(-1.0);
+  kernel[i/2]=(double) (width*width-1.0);
+  edge_image=ConvolveImage(image,width,kernel,exception);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  return(edge_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     E m b o s s I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EmbossImage() returns a grayscale image with a three-dimensional effect.
+%  We convolve the image with a Gaussian operator of the given radius and
+%  standard deviation (sigma).  For reasonable results, radius should be
+%  larger than sigma.  Use a radius of 0 and Emboss() selects a suitable
+%  radius for you.
+%
+%  The format of the EmbossImage method is:
+%
+%      Image *EmbossImage(const Image *image,const double radius,
+%        const double sigma,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius: the radius of the pixel neighborhood.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *EmbossImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  double
+    *kernel;
+
+  Image
+    *emboss_image;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    k,
+    u,
+    v;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  j=(ssize_t) width/2;
+  k=j;
+  i=0;
+  for (v=(-j); v <= j; v++)
+  {
+    for (u=(-j); u <= j; u++)
+    {
+      kernel[i]=(double) (((u < 0) || (v < 0) ? -8.0 : 8.0)*
+        exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
+        (2.0*MagickPI*MagickSigma*MagickSigma));
+      if (u != k)
+        kernel[i]=0.0;
+      i++;
+    }
+    k--;
+  }
+  emboss_image=ConvolveImage(image,width,kernel,exception);
+  if (emboss_image != (Image *) NULL)
+    (void) EqualizeImage(emboss_image);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  return(emboss_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     F i l t e r I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FilterImage() applies a custom convolution kernel to the image.
+%
+%  The format of the FilterImage method is:
+%
+%      Image *FilterImage(const Image *image,const KernelInfo *kernel,
+%        ExceptionInfo *exception)
+%      Image *FilterImageChannel(const Image *image,const ChannelType channel,
+%        const KernelInfo *kernel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o kernel: the filtering kernel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *FilterImage(const Image *image,const KernelInfo *kernel,
+  ExceptionInfo *exception)
+{
+  Image
+    *filter_image;
+
+  filter_image=FilterImageChannel(image,DefaultChannels,kernel,exception);
+  return(filter_image);
+}
+
+MagickExport Image *FilterImageChannel(const Image *image,
+  const ChannelType channel,const KernelInfo *kernel,ExceptionInfo *exception)
+{
+#define FilterImageTag  "Filter/Image"
+
+  CacheView
+    *filter_view,
+    *image_view;
+
+  Image
+    *filter_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize filter image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((kernel->width % 2) == 0)
+    ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
+  filter_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (filter_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(filter_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&filter_image->exception);
+      filter_image=DestroyImage(filter_image);
+      return((Image *) NULL);
+    }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      register const double
+        *k;
+
+      ssize_t
+        u,
+        v;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  FilterImage with %.20gx%.20g kernel:",(double) kernel->width,(double)
+        kernel->height);
+      message=AcquireString("");
+      k=kernel->values;
+      for (v=0; v < (ssize_t) kernel->height; v++)
+      {
+        *message='\0';
+        (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < (ssize_t) kernel->width; u++)
+        {
+          (void) FormatLocaleString(format,MaxTextExtent,"%g ",*k++);
+          (void) ConcatenateString(&message,format);
+        }
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  status=AccelerateConvolveImage(image,kernel,filter_image,exception);
+  if (status == MagickTrue)
+    return(filter_image);
+  /*
+    Filter image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  SetPixelInfoBias(image,&bias);
+  image_view=AcquireCacheView(image);
+  filter_view=AcquireCacheView(filter_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) kernel->width/2L),
+      y-(ssize_t) (kernel->height/2L),image->columns+kernel->width,
+      kernel->height,exception);
+    q=GetCacheViewAuthenticPixels(filter_view,0,y,filter_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict kernel_pixels;
+
+      register ssize_t
+        u;
+
+      ssize_t
+        v;
+
+      pixel=bias;
+      k=kernel->values;
+      kernel_pixels=p;
+      if (((channel & AlphaChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (v=0; v < (ssize_t) kernel->width; v++)
+          {
+            for (u=0; u < (ssize_t) kernel->height; u++)
+            {
+              pixel.red+=(*k)*GetPixelRed(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.green+=(*k)*GetPixelGreen(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.blue+=(*k)*GetPixelBlue(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              if (image->colorspace == CMYKColorspace)
+                pixel.black+=(*k)*GetPixelBlack(image,kernel_pixels+u*
+                  GetPixelChannels(image));
+              k++;
+            }
+            kernel_pixels+=(image->columns+kernel->width)*
+              GetPixelChannels(image);
+          }
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(filter_image,ClampToQuantum(pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(filter_image,ClampToQuantum(pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(filter_image,ClampToQuantum(pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(filter_image,ClampToQuantum(pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=kernel->values;
+              kernel_pixels=p;
+              for (v=0; v < (ssize_t) kernel->width; v++)
+              {
+                for (u=0; u < (ssize_t) kernel->height; u++)
+                {
+                  pixel.alpha+=(*k)*GetPixelRed(image,kernel_pixels+u*
+                    GetPixelChannels(image));
+                  k++;
+                }
+                kernel_pixels+=(image->columns+kernel->width)*
+                  GetPixelChannels(image);
+              }
+              SetPixelAlpha(filter_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          gamma=0.0;
+          for (v=0; v < (ssize_t) kernel->width; v++)
+          {
+            for (u=0; u < (ssize_t) kernel->height; u++)
+            {
+              alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,
+                kernel_pixels+u*GetPixelChannels(image)));
+              pixel.red+=(*k)*alpha*GetPixelRed(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.green+=(*k)*alpha*GetPixelGreen(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              pixel.blue+=(*k)*alpha*GetPixelBlue(image,kernel_pixels+u*
+                GetPixelChannels(image));
+              if (image->colorspace == CMYKColorspace)
+                pixel.black+=(*k)*alpha*GetPixelBlack(image,kernel_pixels+u*
+                  GetPixelChannels(image));
+              gamma+=(*k)*alpha;
+              k++;
+            }
+            kernel_pixels+=(image->columns+kernel->width);
+              GetPixelChannels(image);
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(filter_image,ClampToQuantum(gamma*pixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(filter_image,ClampToQuantum(gamma*pixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(filter_image,ClampToQuantum(gamma*pixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(filter_image,ClampToQuantum(gamma*pixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            {
+              k=kernel->values;
+              kernel_pixels=p;
+              for (v=0; v < (ssize_t) kernel->width; v++)
+              {
+                for (u=0; u < (ssize_t) kernel->height; u++)
+                {
+                  pixel.alpha+=(*k)*GetPixelAlpha(image,kernel_pixels+u*
+                    GetPixelChannels(image));
+                  k++;
+                }
+                kernel_pixels+=(image->columns+kernel->width)*
+                  GetPixelChannels(image);
+              }
+              SetPixelAlpha(filter_image,ClampToQuantum(pixel.alpha),q);
+            }
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(filter_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(filter_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_FilterImageChannel)
+#endif
+        proceed=SetImageProgress(image,FilterImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  filter_image->type=image->type;
+  filter_view=DestroyCacheView(filter_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    filter_image=DestroyImage(filter_image);
+  return(filter_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     G a u s s i a n B l u r I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GaussianBlurImage() blurs an image.  We convolve the image with a
+%  Gaussian operator of the given radius and standard deviation (sigma).
+%  For reasonable results, the radius should be larger than sigma.  Use a
+%  radius of 0 and GaussianBlurImage() selects a suitable radius for you
+%
+%  The format of the GaussianBlurImage method is:
+%
+%      Image *GaussianBlurImage(const Image *image,onst double radius,
+%        const double sigma,ExceptionInfo *exception)
+%      Image *GaussianBlurImageChannel(const Image *image,
+%        const ChannelType channel,const double radius,const double sigma,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  Image
+    *blur_image;
+
+  blur_image=GaussianBlurImageChannel(image,DefaultChannels,radius,sigma,
+    exception);
+  return(blur_image);
+}
+
+MagickExport Image *GaussianBlurImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  ExceptionInfo *exception)
+{
+  double
+    *kernel;
+
+  Image
+    *blur_image;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    u,
+    v;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  j=(ssize_t) width/2;
+  i=0;
+  for (v=(-j); v <= j; v++)
+  {
+    for (u=(-j); u <= j; u++)
+      kernel[i++]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+        MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+  }
+  blur_image=ConvolveImageChannel(image,channel,width,kernel,exception);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M o t i o n B l u r I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MotionBlurImage() simulates motion blur.  We convolve the image with a
+%  Gaussian operator of the given radius and standard deviation (sigma).
+%  For reasonable results, radius should be larger than sigma.  Use a
+%  radius of 0 and MotionBlurImage() selects a suitable radius for you.
+%  Angle gives the angle of the blurring motion.
+%
+%  Andrew Protano contributed this effect.
+%
+%  The format of the MotionBlurImage method is:
+%
+%    Image *MotionBlurImage(const Image *image,const double radius,
+%      const double sigma,const double angle,ExceptionInfo *exception)
+%    Image *MotionBlurImageChannel(const Image *image,const ChannelType channel,
+%      const double radius,const double sigma,const double angle,
+%      ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%    o radius: the radius of the Gaussian, in pixels, not counting
+%      the center pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o angle: Apply the effect along this angle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static double *GetMotionBlurKernel(const size_t width,const double sigma)
+{
+  double
+    *kernel,
+    normalize;
+
+  register ssize_t
+    i;
+
+  /*
+   Generate a 1-D convolution kernel.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  kernel=(double *) AcquireQuantumMemory((size_t) width,sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    return(kernel);
+  normalize=0.0;
+  for (i=0; i < (ssize_t) width; i++)
+  {
+    kernel[i]=(double) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
+      MagickSigma)))/(MagickSQ2PI*MagickSigma));
+    normalize+=kernel[i];
+  }
+  for (i=0; i < (ssize_t) width; i++)
+    kernel[i]/=normalize;
+  return(kernel);
+}
+
+MagickExport Image *MotionBlurImage(const Image *image,const double radius,
+  const double sigma,const double angle,ExceptionInfo *exception)
+{
+  Image
+    *motion_blur;
+
+  motion_blur=MotionBlurImageChannel(image,DefaultChannels,radius,sigma,angle,
+    exception);
+  return(motion_blur);
+}
+
+MagickExport Image *MotionBlurImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  const double angle,ExceptionInfo *exception)
+{
+  CacheView
+    *blur_view,
+    *image_view;
+
+  double
+    *kernel;
+
+  Image
+    *blur_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  OffsetInfo
+    *offset;
+
+  PointInfo
+    point;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  width=GetOptimalKernelWidth1D(radius,sigma);
+  kernel=GetMotionBlurKernel(width,sigma);
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
+  if (offset == (OffsetInfo *) NULL)
+    {
+      kernel=(double *) RelinquishMagickMemory(kernel);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (blur_image == (Image *) NULL)
+    {
+      kernel=(double *) RelinquishMagickMemory(kernel);
+      offset=(OffsetInfo *) RelinquishMagickMemory(offset);
+      return((Image *) NULL);
+    }
+  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+    {
+      kernel=(double *) RelinquishMagickMemory(kernel);
+      offset=(OffsetInfo *) RelinquishMagickMemory(offset);
+      InheritException(exception,&blur_image->exception);
+      blur_image=DestroyImage(blur_image);
+      return((Image *) NULL);
+    }
+  point.x=(double) width*sin(DegreesToRadians(angle));
+  point.y=(double) width*cos(DegreesToRadians(angle));
+  for (i=0; i < (ssize_t) width; i++)
+  {
+    offset[i].x=(ssize_t) ceil((double) (i*point.y)/hypot(point.x,point.y)-0.5);
+    offset[i].y=(ssize_t) ceil((double) (i*point.x)/hypot(point.x,point.y)-0.5);
+  }
+  /*
+    Motion blur image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        qixel;
+
+      PixelPacket
+        pixel;
+
+      register double
+        *restrict k;
+
+      register ssize_t
+        i;
+
+      k=kernel;
+      qixel=bias;
+      if (((channel & AlphaChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (ssize_t) width; i++)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
+              offset[i].y,&pixel,exception);
+            qixel.red+=(*k)*pixel.red;
+            qixel.green+=(*k)*pixel.green;
+            qixel.blue+=(*k)*pixel.blue;
+            qixel.alpha+=(*k)*pixel.alpha;
+            if (image->colorspace == CMYKColorspace)
+              qixel.black+=(*k)*pixel.black;
+            k++;
+          }
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,
+              ClampToQuantum(qixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,
+              ClampToQuantum(qixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,
+              ClampToQuantum(qixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,
+              ClampToQuantum(qixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            SetPixelAlpha(blur_image,
+              ClampToQuantum(qixel.alpha),q);
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          alpha=0.0;
+          gamma=0.0;
+          for (i=0; i < (ssize_t) width; i++)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,x+offset[i].x,y+
+              offset[i].y,&pixel,exception);
+            alpha=(MagickRealType) (QuantumScale*pixel.alpha);
+            qixel.red+=(*k)*alpha*pixel.red;
+            qixel.green+=(*k)*alpha*pixel.green;
+            qixel.blue+=(*k)*alpha*pixel.blue;
+            qixel.alpha+=(*k)*pixel.alpha;
+            if (image->colorspace == CMYKColorspace)
+              qixel.black+=(*k)*alpha*pixel.black;
+            gamma+=(*k)*alpha;
+            k++;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,
+              ClampToQuantum(gamma*qixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,
+              ClampToQuantum(gamma*qixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,
+              ClampToQuantum(gamma*qixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,
+              ClampToQuantum(gamma*qixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            SetPixelAlpha(blur_image,
+              ClampToQuantum(qixel.alpha),q);
+        }
+      q+=GetPixelChannels(blur_image);
+    }
+    if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_MotionBlurImageChannel)
+#endif
+        proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  blur_view=DestroyCacheView(blur_view);
+  image_view=DestroyCacheView(image_view);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
+  if (status == MagickFalse)
+    blur_image=DestroyImage(blur_image);
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P r e v i e w I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PreviewImage() tiles 9 thumbnails of the specified image with an image
+%  processing operation applied with varying parameters.  This may be helpful
+%  pin-pointing an appropriate parameter for a particular image processing
+%  operation.
+%
+%  The format of the PreviewImages method is:
+%
+%      Image *PreviewImages(const Image *image,const PreviewType preview,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o preview: the image processing operation.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
+  ExceptionInfo *exception)
+{
+#define NumberTiles  9
+#define PreviewImageTag  "Preview/Image"
+#define DefaultPreviewGeometry  "204x204+10+10"
+
+  char
+    factor[MaxTextExtent],
+    label[MaxTextExtent];
+
+  double
+    degrees,
+    gamma,
+    percentage,
+    radius,
+    sigma,
+    threshold;
+
+  Image
+    *images,
+    *montage_image,
+    *preview_image,
+    *thumbnail;
+
+  ImageInfo
+    *preview_info;
+
+  MagickBooleanType
+    proceed;
+
+  MontageInfo
+    *montage_info;
+
+  QuantizeInfo
+    quantize_info;
+
+  RectangleInfo
+    geometry;
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    colors;
+
+  ssize_t
+    y;
+
+  /*
+    Open output image file.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  colors=2;
+  degrees=0.0;
+  gamma=(-0.2f);
+  preview_info=AcquireImageInfo();
+  SetGeometry(image,&geometry);
+  (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
+    &geometry.width,&geometry.height);
+  images=NewImageList();
+  percentage=12.5;
+  GetQuantizeInfo(&quantize_info);
+  radius=0.0;
+  sigma=1.0;
+  threshold=0.0;
+  x=0;
+  y=0;
+  for (i=0; i < NumberTiles; i++)
+  {
+    thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
+    if (thumbnail == (Image *) NULL)
+      break;
+    (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
+      (void *) NULL);
+    (void) SetImageProperty(thumbnail,"label",DefaultTileLabel);
+    if (i == (NumberTiles/2))
+      {
+        (void) QueryColorDatabase("#dfdfdf",&thumbnail->matte_color,exception);
+        AppendImageToList(&images,thumbnail);
+        continue;
+      }
+    switch (preview)
+    {
+      case RotatePreview:
+      {
+        degrees+=45.0;
+        preview_image=RotateImage(thumbnail,degrees,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"rotate %g",degrees);
+        break;
+      }
+      case ShearPreview:
+      {
+        degrees+=5.0;
+        preview_image=ShearImage(thumbnail,degrees,degrees,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"shear %gx%g",
+          degrees,2.0*degrees);
+        break;
+      }
+      case RollPreview:
+      {
+        x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
+        y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
+        preview_image=RollImage(thumbnail,x,y,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"roll %+.20gx%+.20g",
+          (double) x,(double) y);
+        break;
+      }
+      case HuePreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatLocaleString(factor,MaxTextExtent,"100,100,%g",
+          2.0*percentage);
+        (void) ModulateImage(preview_image,factor);
+        (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
+        break;
+      }
+      case SaturationPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatLocaleString(factor,MaxTextExtent,"100,%g",
+          2.0*percentage);
+        (void) ModulateImage(preview_image,factor);
+        (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
+        break;
+      }
+      case BrightnessPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatLocaleString(factor,MaxTextExtent,"%g",2.0*percentage);
+        (void) ModulateImage(preview_image,factor);
+        (void) FormatLocaleString(label,MaxTextExtent,"modulate %s",factor);
+        break;
+      }
+      case GammaPreview:
+      default:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        gamma+=0.4f;
+        (void) GammaImageChannel(preview_image,DefaultChannels,gamma);
+        (void) FormatLocaleString(label,MaxTextExtent,"gamma %g",gamma);
+        break;
+      }
+      case SpiffPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image != (Image *) NULL)
+          for (x=0; x < i; x++)
+            (void) ContrastImage(preview_image,MagickTrue);
+        (void) FormatLocaleString(label,MaxTextExtent,"contrast (%.20g)",
+          (double) i+1);
+        break;
+      }
+      case DullPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        for (x=0; x < i; x++)
+          (void) ContrastImage(preview_image,MagickFalse);
+        (void) FormatLocaleString(label,MaxTextExtent,"+contrast (%.20g)",
+          (double) i+1);
+        break;
+      }
+      case GrayscalePreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        colors<<=1;
+        quantize_info.number_colors=colors;
+        quantize_info.colorspace=GRAYColorspace;
+        (void) QuantizeImage(&quantize_info,preview_image);
+        (void) FormatLocaleString(label,MaxTextExtent,
+          "-colorspace gray -colors %.20g",(double) colors);
+        break;
+      }
+      case QuantizePreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        colors<<=1;
+        quantize_info.number_colors=colors;
+        (void) QuantizeImage(&quantize_info,preview_image);
+        (void) FormatLocaleString(label,MaxTextExtent,"colors %.20g",(double)
+          colors);
+        break;
+      }
+      case DespecklePreview:
+      {
+        for (x=0; x < (i-1); x++)
+        {
+          preview_image=DespeckleImage(thumbnail,exception);
+          if (preview_image == (Image *) NULL)
+            break;
+          thumbnail=DestroyImage(thumbnail);
+          thumbnail=preview_image;
+        }
+        preview_image=DespeckleImage(thumbnail,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) FormatLocaleString(label,MaxTextExtent,"despeckle (%.20g)",
+          (double) i+1);
+        break;
+      }
+      case ReduceNoisePreview:
+      {
+        preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) radius,
+          (size_t) radius,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"noise %g",radius);
+        break;
+      }
+      case AddNoisePreview:
+      {
+        switch ((int) i)
+        {
+          case 0:
+          {
+            (void) CopyMagickString(factor,"uniform",MaxTextExtent);
+            break;
+          }
+          case 1:
+          {
+            (void) CopyMagickString(factor,"gaussian",MaxTextExtent);
+            break;
+          }
+          case 2:
+          {
+            (void) CopyMagickString(factor,"multiplicative",MaxTextExtent);
+            break;
+          }
+          case 3:
+          {
+            (void) CopyMagickString(factor,"impulse",MaxTextExtent);
+            break;
+          }
+          case 4:
+          {
+            (void) CopyMagickString(factor,"laplacian",MaxTextExtent);
+            break;
+          }
+          case 5:
+          {
+            (void) CopyMagickString(factor,"Poisson",MaxTextExtent);
+            break;
+          }
+          default:
+          {
+            (void) CopyMagickString(thumbnail->magick,"NULL",MaxTextExtent);
+            break;
+          }
+        }
+        preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) i,
+          (size_t) i,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"+noise %s",factor);
+        break;
+      }
+      case SharpenPreview:
+      {
+        preview_image=SharpenImage(thumbnail,radius,sigma,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"sharpen %gx%g",
+          radius,sigma);
+        break;
+      }
+      case BlurPreview:
+      {
+        preview_image=BlurImage(thumbnail,radius,sigma,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"blur %gx%g",radius,
+          sigma);
+        break;
+      }
+      case ThresholdPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) BilevelImage(thumbnail,
+          (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
+        (void) FormatLocaleString(label,MaxTextExtent,"threshold %g",
+          (double) (percentage*((MagickRealType) QuantumRange+1.0))/100.0);
+        break;
+      }
+      case EdgeDetectPreview:
+      {
+        preview_image=EdgeImage(thumbnail,radius,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"edge %g",radius);
+        break;
+      }
+      case SpreadPreview:
+      {
+        preview_image=SpreadImage(thumbnail,radius,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"spread %g",
+          radius+0.5);
+        break;
+      }
+      case SolarizePreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        (void) SolarizeImage(preview_image,(double) QuantumRange*
+          percentage/100.0);
+        (void) FormatLocaleString(label,MaxTextExtent,"solarize %g",
+          (QuantumRange*percentage)/100.0);
+        break;
+      }
+      case ShadePreview:
+      {
+        degrees+=10.0;
+        preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
+          exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"shade %gx%g",
+          degrees,degrees);
+        break;
+      }
+      case RaisePreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        geometry.width=(size_t) (2*i+2);
+        geometry.height=(size_t) (2*i+2);
+        geometry.x=i/2;
+        geometry.y=i/2;
+        (void) RaiseImage(preview_image,&geometry,MagickTrue);
+        (void) FormatLocaleString(label,MaxTextExtent,
+          "raise %.20gx%.20g%+.20g%+.20g",(double) geometry.width,(double)
+          geometry.height,(double) geometry.x,(double) geometry.y);
+        break;
+      }
+      case SegmentPreview:
+      {
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        threshold+=0.4f;
+        (void) SegmentImage(preview_image,RGBColorspace,MagickFalse,threshold,
+          threshold);
+        (void) FormatLocaleString(label,MaxTextExtent,"segment %gx%g",
+          threshold,threshold);
+        break;
+      }
+      case SwirlPreview:
+      {
+        preview_image=SwirlImage(thumbnail,degrees,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"swirl %g",degrees);
+        degrees+=45.0;
+        break;
+      }
+      case ImplodePreview:
+      {
+        degrees+=0.1f;
+        preview_image=ImplodeImage(thumbnail,degrees,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"implode %g",degrees);
+        break;
+      }
+      case WavePreview:
+      {
+        degrees+=5.0f;
+        preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"wave %gx%g",
+          0.5*degrees,2.0*degrees);
+        break;
+      }
+      case OilPaintPreview:
+      {
+        preview_image=OilPaintImage(thumbnail,(double) radius,exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"paint %g",radius);
+        break;
+      }
+      case CharcoalDrawingPreview:
+      {
+        preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
+          exception);
+        (void) FormatLocaleString(label,MaxTextExtent,"charcoal %gx%g",
+          radius,sigma);
+        break;
+      }
+      case JPEGPreview:
+      {
+        char
+          filename[MaxTextExtent];
+
+        int
+          file;
+
+        MagickBooleanType
+          status;
+
+        preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
+        if (preview_image == (Image *) NULL)
+          break;
+        preview_info->quality=(size_t) percentage;
+        (void) FormatLocaleString(factor,MaxTextExtent,"%.20g",(double)
+          preview_info->quality);
+        file=AcquireUniqueFileResource(filename);
+        if (file != -1)
+          file=close(file)-1;
+        (void) FormatLocaleString(preview_image->filename,MaxTextExtent,
+          "jpeg:%s",filename);
+        status=WriteImage(preview_info,preview_image);
+        if (status != MagickFalse)
+          {
+            Image
+              *quality_image;
+
+            (void) CopyMagickString(preview_info->filename,
+              preview_image->filename,MaxTextExtent);
+            quality_image=ReadImage(preview_info,exception);
+            if (quality_image != (Image *) NULL)
+              {
+                preview_image=DestroyImage(preview_image);
+                preview_image=quality_image;
+              }
+          }
+        (void) RelinquishUniqueFileResource(preview_image->filename);
+        if ((GetBlobSize(preview_image)/1024) >= 1024)
+          (void) FormatLocaleString(label,MaxTextExtent,"quality %s\n%gmb ",
+            factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
+            1024.0/1024.0);
+        else
+          if (GetBlobSize(preview_image) >= 1024)
+            (void) FormatLocaleString(label,MaxTextExtent,
+              "quality %s\n%gkb ",factor,(double) ((MagickOffsetType)
+              GetBlobSize(preview_image))/1024.0);
+          else
+            (void) FormatLocaleString(label,MaxTextExtent,"quality %s\n%.20gb ",
+              factor,(double) ((MagickOffsetType) GetBlobSize(thumbnail)));
+        break;
+      }
+    }
+    thumbnail=DestroyImage(thumbnail);
+    percentage+=12.5;
+    radius+=0.5;
+    sigma+=0.25;
+    if (preview_image == (Image *) NULL)
+      break;
+    (void) DeleteImageProperty(preview_image,"label");
+    (void) SetImageProperty(preview_image,"label",label);
+    AppendImageToList(&images,preview_image);
+    proceed=SetImageProgress(image,PreviewImageTag,(MagickOffsetType) i,
+      NumberTiles);
+    if (proceed == MagickFalse)
+      break;
+  }
+  if (images == (Image *) NULL)
+    {
+      preview_info=DestroyImageInfo(preview_info);
+      return((Image *) NULL);
+    }
+  /*
+    Create the montage.
+  */
+  montage_info=CloneMontageInfo(preview_info,(MontageInfo *) NULL);
+  (void) CopyMagickString(montage_info->filename,image->filename,MaxTextExtent);
+  montage_info->shadow=MagickTrue;
+  (void) CloneString(&montage_info->tile,"3x3");
+  (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
+  (void) CloneString(&montage_info->frame,DefaultTileFrame);
+  montage_image=MontageImages(images,montage_info,exception);
+  montage_info=DestroyMontageInfo(montage_info);
+  images=DestroyImageList(images);
+  if (montage_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  if (montage_image->montage != (char *) NULL)
+    {
+      /*
+        Free image directory.
+      */
+      montage_image->montage=(char *) RelinquishMagickMemory(
+        montage_image->montage);
+      if (image->directory != (char *) NULL)
+        montage_image->directory=(char *) RelinquishMagickMemory(
+          montage_image->directory);
+    }
+  preview_info=DestroyImageInfo(preview_info);
+  return(montage_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     R a d i a l B l u r I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RadialBlurImage() applies a radial blur to the image.
+%
+%  Andrew Protano contributed this effect.
+%
+%  The format of the RadialBlurImage method is:
+%
+%    Image *RadialBlurImage(const Image *image,const double angle,
+%      ExceptionInfo *exception)
+%    Image *RadialBlurImageChannel(const Image *image,const ChannelType channel,
+%      const double angle,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o angle: the angle of the radial blur.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *RadialBlurImage(const Image *image,const double angle,
+  ExceptionInfo *exception)
+{
+  Image
+    *blur_image;
+
+  blur_image=RadialBlurImageChannel(image,DefaultChannels,angle,exception);
+  return(blur_image);
+}
+
+MagickExport Image *RadialBlurImageChannel(const Image *image,
+  const ChannelType channel,const double angle,ExceptionInfo *exception)
+{
+  CacheView
+    *blur_view,
+    *image_view;
+
+  Image
+    *blur_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  MagickRealType
+    blur_radius,
+    *cos_theta,
+    offset,
+    *sin_theta,
+    theta;
+
+  PointInfo
+    blur_center;
+
+  register ssize_t
+    i;
+
+  size_t
+    n;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate blur image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (blur_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&blur_image->exception);
+      blur_image=DestroyImage(blur_image);
+      return((Image *) NULL);
+    }
+  blur_center.x=(double) image->columns/2.0;
+  blur_center.y=(double) image->rows/2.0;
+  blur_radius=hypot(blur_center.x,blur_center.y);
+  n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
+  theta=DegreesToRadians(angle)/(MagickRealType) (n-1);
+  cos_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n,
+    sizeof(*cos_theta));
+  sin_theta=(MagickRealType *) AcquireQuantumMemory((size_t) n,
+    sizeof(*sin_theta));
+  if ((cos_theta == (MagickRealType *) NULL) ||
+      (sin_theta == (MagickRealType *) NULL))
+    {
+      blur_image=DestroyImage(blur_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  offset=theta*(MagickRealType) (n-1)/2.0;
+  for (i=0; i < (ssize_t) n; i++)
+  {
+    cos_theta[i]=cos((double) (theta*i-offset));
+    sin_theta[i]=sin((double) (theta*i-offset));
+  }
+  /*
+    Radial blur image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) blur_image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) blur_image->columns; x++)
+    {
+      PixelInfo
+        qixel;
+
+      MagickRealType
+        normalize,
+        radius;
+
+      PixelPacket
+        pixel;
+
+      PointInfo
+        center;
+
+      register ssize_t
+        i;
+
+      size_t
+        step;
+
+      center.x=(double) x-blur_center.x;
+      center.y=(double) y-blur_center.y;
+      radius=hypot((double) center.x,center.y);
+      if (radius == 0)
+        step=1;
+      else
+        {
+          step=(size_t) (blur_radius/radius);
+          if (step == 0)
+            step=1;
+          else
+            if (step >= n)
+              step=n-1;
+        }
+      normalize=0.0;
+      qixel=bias;
+      if (((channel & AlphaChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+              (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
+              (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
+              cos_theta[i]+0.5),&pixel,exception);
+            qixel.red+=pixel.red;
+            qixel.green+=pixel.green;
+            qixel.blue+=pixel.blue;
+            if (image->colorspace == CMYKColorspace)
+              qixel.black+=pixel.black;
+            qixel.alpha+=pixel.alpha;
+            normalize+=1.0;
+          }
+          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
+            normalize);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,
+              ClampToQuantum(normalize*qixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,
+              ClampToQuantum(normalize*qixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,
+              ClampToQuantum(normalize*qixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,
+              ClampToQuantum(normalize*qixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            SetPixelAlpha(blur_image,
+              ClampToQuantum(normalize*qixel.alpha),q);
+        }
+      else
+        {
+          MagickRealType
+            alpha,
+            gamma;
+
+          alpha=1.0;
+          gamma=0.0;
+          for (i=0; i < (ssize_t) n; i+=(ssize_t) step)
+          {
+            (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+              (blur_center.x+center.x*cos_theta[i]-center.y*sin_theta[i]+0.5),
+              (ssize_t) (blur_center.y+center.x*sin_theta[i]+center.y*
+              cos_theta[i]+0.5),&pixel,exception);
+            alpha=(MagickRealType) (QuantumScale*pixel.alpha);
+            qixel.red+=alpha*pixel.red;
+            qixel.green+=alpha*pixel.green;
+            qixel.blue+=alpha*pixel.blue;
+            qixel.alpha+=pixel.alpha;
+            if (image->colorspace == CMYKColorspace)
+              qixel.black+=alpha*pixel.black;
+            gamma+=alpha;
+            normalize+=1.0;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 :
+            normalize);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(blur_image,
+              ClampToQuantum(gamma*qixel.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(blur_image,
+              ClampToQuantum(gamma*qixel.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(blur_image,
+              ClampToQuantum(gamma*qixel.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(blur_image,
+              ClampToQuantum(gamma*qixel.black),q);
+          if ((channel & AlphaChannel) != 0)
+            SetPixelAlpha(blur_image,
+              ClampToQuantum(normalize*qixel.alpha),q);
+        }
+      q+=GetPixelChannels(blur_image);
+    }
+    if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_RadialBlurImageChannel)
+#endif
+        proceed=SetImageProgress(image,BlurImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  blur_view=DestroyCacheView(blur_view);
+  image_view=DestroyCacheView(image_view);
+  cos_theta=(MagickRealType *) RelinquishMagickMemory(cos_theta);
+  sin_theta=(MagickRealType *) RelinquishMagickMemory(sin_theta);
+  if (status == MagickFalse)
+    blur_image=DestroyImage(blur_image);
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S e l e c t i v e B l u r I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SelectiveBlurImage() selectively blur pixels within a contrast threshold.
+%  It is similar to the unsharpen mask that sharpens everything with contrast
+%  above a certain threshold.
+%
+%  The format of the SelectiveBlurImage method is:
+%
+%      Image *SelectiveBlurImage(const Image *image,const double radius,
+%        const double sigma,const double threshold,ExceptionInfo *exception)
+%      Image *SelectiveBlurImageChannel(const Image *image,
+%        const ChannelType channel,const double radius,const double sigma,
+%        const double threshold,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o threshold: only pixels within this contrast threshold are included
+%      in the blur operation.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
+  const double sigma,const double threshold,ExceptionInfo *exception)
+{
+  Image
+    *blur_image;
+
+  blur_image=SelectiveBlurImageChannel(image,DefaultChannels,radius,sigma,
+    threshold,exception);
+  return(blur_image);
+}
+
+MagickExport Image *SelectiveBlurImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  const double threshold,ExceptionInfo *exception)
+{
+#define SelectiveBlurImageTag  "SelectiveBlur/Image"
+
+  CacheView
+    *blur_view,
+    *image_view;
+
+  double
+    *kernel;
+
+  Image
+    *blur_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    u,
+    v,
+    y;
+
+  /*
+    Initialize blur image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth1D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width,width*sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  j=(ssize_t) width/2;
+  i=0;
+  for (v=(-j); v <= j; v++)
+  {
+    for (u=(-j); u <= j; u++)
+      kernel[i++]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+        MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+  }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      register const double
+        *k;
+
+      ssize_t
+        u,
+        v;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(double)
+        width);
+      message=AcquireString("");
+      k=kernel;
+      for (v=0; v < (ssize_t) width; v++)
+      {
+        *message='\0';
+        (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          (void) FormatLocaleString(format,MaxTextExtent,"%+f ",*k++);
+          (void) ConcatenateString(&message,format);
+        }
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  blur_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (blur_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(blur_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&blur_image->exception);
+      blur_image=DestroyImage(blur_image);
+      return((Image *) NULL);
+    }
+  /*
+    Threshold blur image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  SetPixelInfoBias(image,&bias);
+  image_view=AcquireCacheView(image);
+  blur_view=AcquireCacheView(blur_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      contrast;
+
+    MagickBooleanType
+      sync;
+
+    MagickRealType
+      gamma;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+      (width/2L),image->columns+width,width,exception);
+    q=GetCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      register const double
+        *restrict k;
+
+      register ssize_t
+        u;
+
+      ssize_t
+        j,
+        v;
+
+      pixel=bias;
+      k=kernel;
+      gamma=0.0;
+      j=0;
+      if (((channel & AlphaChannel) == 0) || (image->matte == MagickFalse))
+        {
+          for (v=0; v < (ssize_t) width; v++)
+          {
+            for (u=0; u < (ssize_t) width; u++)
+            {
+              contrast=GetPixelIntensity(image,p+(u+j)*GetPixelChannels(image))-
+                (double) GetPixelIntensity(blur_image,q);
+              if (fabs(contrast) < threshold)
+                {
+                  pixel.red+=(*k)*
+                    GetPixelRed(image,p+(u+j)*GetPixelChannels(image));
+                  pixel.green+=(*k)*
+                    GetPixelGreen(image,p+(u+j)*GetPixelChannels(image));
+                  pixel.blue+=(*k)*
+                    GetPixelBlue(image,p+(u+j)*GetPixelChannels(image));
+                  if (image->colorspace == CMYKColorspace)
+                    pixel.black+=(*k)*
+                      GetPixelBlack(image,p+(u+j)*GetPixelChannels(image));
+                  gamma+=(*k);
+                  k++;
+                }
+            }
+            j+=(ssize_t) (image->columns+width);
+          }
+          if (gamma != 0.0)
+            {
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              if ((channel & RedChannel) != 0)
+                SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
+              if ((channel & GreenChannel) != 0)
+                SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
+              if ((channel & BlueChannel) != 0)
+                SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
+              if (((channel & BlackChannel) != 0) &&
+                  (image->colorspace == CMYKColorspace))
+                SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
+            }
+          if ((channel & AlphaChannel) != 0)
+            {
+              gamma=0.0;
+              j=0;
+              for (v=0; v < (ssize_t) width; v++)
+              {
+                for (u=0; u < (ssize_t) width; u++)
+                {
+                  contrast=GetPixelIntensity(image,p+(u+j)*
+                    GetPixelChannels(image))-(double)
+                    GetPixelIntensity(blur_image,q);
+                  if (fabs(contrast) < threshold)
+                    {
+                      pixel.alpha+=(*k)*
+                        GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image));
+                      gamma+=(*k);
+                      k++;
+                    }
+                }
+                j+=(ssize_t) (image->columns+width);
+              }
+              if (gamma != 0.0)
+                {
+                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
+                    gamma);
+                  SetPixelAlpha(blur_image,ClampToQuantum(gamma*pixel.alpha),q);
+                }
+            }
+        }
+      else
+        {
+          MagickRealType
+            alpha;
+
+          for (v=0; v < (ssize_t) width; v++)
+          {
+            for (u=0; u < (ssize_t) width; u++)
+            {
+              contrast=GetPixelIntensity(image,p+(u+j)*
+                GetPixelChannels(image))-(double)
+                GetPixelIntensity(blur_image,q);
+              if (fabs(contrast) < threshold)
+                {
+                  alpha=(MagickRealType) (QuantumScale*
+                    GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image)));
+                  pixel.red+=(*k)*alpha*
+                    GetPixelRed(image,p+(u+j)*GetPixelChannels(image));
+                  pixel.green+=(*k)*alpha*GetPixelGreen(image,p+(u+j)*
+                    GetPixelChannels(image));
+                  pixel.blue+=(*k)*alpha*GetPixelBlue(image,p+(u+j)*
+                    GetPixelChannels(image));
+                  pixel.alpha+=(*k)*GetPixelAlpha(image,p+(u+j)*
+                    GetPixelChannels(image));
+                  if (image->colorspace == CMYKColorspace)
+                    pixel.black+=(*k)*GetPixelBlack(image,p+(u+j)*
+                      GetPixelChannels(image));
+                  gamma+=(*k)*alpha;
+                  k++;
+                }
+            }
+            j+=(ssize_t) (image->columns+width);
+          }
+          if (gamma != 0.0)
+            {
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              if ((channel & RedChannel) != 0)
+                SetPixelRed(blur_image,ClampToQuantum(gamma*pixel.red),q);
+              if ((channel & GreenChannel) != 0)
+                SetPixelGreen(blur_image,ClampToQuantum(gamma*pixel.green),q);
+              if ((channel & BlueChannel) != 0)
+                SetPixelBlue(blur_image,ClampToQuantum(gamma*pixel.blue),q);
+              if (((channel & BlackChannel) != 0) &&
+                  (image->colorspace == CMYKColorspace))
+                SetPixelBlack(blur_image,ClampToQuantum(gamma*pixel.black),q);
+            }
+          if ((channel & AlphaChannel) != 0)
+            {
+              gamma=0.0;
+              j=0;
+              for (v=0; v < (ssize_t) width; v++)
+              {
+                for (u=0; u < (ssize_t) width; u++)
+                {
+                  contrast=GetPixelIntensity(image,p+(u+j)*
+                    GetPixelChannels(image))-(double)
+                    GetPixelIntensity(blur_image,q);
+                  if (fabs(contrast) < threshold)
+                    {
+                      pixel.alpha+=(*k)*
+                        GetPixelAlpha(image,p+(u+j)*GetPixelChannels(image));
+                      gamma+=(*k);
+                      k++;
+                    }
+                }
+                j+=(ssize_t) (image->columns+width);
+              }
+              if (gamma != 0.0)
+                {
+                  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 :
+                    gamma);
+                  SetPixelAlpha(blur_image,ClampToQuantum(pixel.alpha),q);
+                }
+            }
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(blur_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(blur_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SelectiveBlurImageChannel)
+#endif
+        proceed=SetImageProgress(image,SelectiveBlurImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  blur_image->type=image->type;
+  blur_view=DestroyCacheView(blur_view);
+  image_view=DestroyCacheView(image_view);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  if (status == MagickFalse)
+    blur_image=DestroyImage(blur_image);
+  return(blur_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S h a d e I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShadeImage() shines a distant light on an image to create a
+%  three-dimensional effect. You control the positioning of the light with
+%  azimuth and elevation; azimuth is measured in degrees off the x axis
+%  and elevation is measured in pixels above the Z axis.
+%
+%  The format of the ShadeImage method is:
+%
+%      Image *ShadeImage(const Image *image,const MagickBooleanType gray,
+%        const double azimuth,const double elevation,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o gray: A value other than zero shades the intensity of each pixel.
+%
+%    o azimuth, elevation:  Define the light source direction.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ShadeImage(const Image *image,const MagickBooleanType gray,
+  const double azimuth,const double elevation,ExceptionInfo *exception)
+{
+#define ShadeImageTag  "Shade/Image"
+
+  CacheView
+    *image_view,
+    *shade_view;
+
+  Image
+    *shade_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PrimaryInfo
+    light;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize shaded image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  shade_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (shade_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(shade_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&shade_image->exception);
+      shade_image=DestroyImage(shade_image);
+      return((Image *) NULL);
+    }
+  /*
+    Compute the light vector.
+  */
+  light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
+    cos(DegreesToRadians(elevation));
+  light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
+    cos(DegreesToRadians(elevation));
+  light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
+  /*
+    Shade image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  shade_view=AcquireCacheView(shade_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickRealType
+      distance,
+      normal_distance,
+      shade;
+
+    PrimaryInfo
+      normal;
+
+    register const Quantum
+      *restrict p,
+      *restrict s0,
+      *restrict s1,
+      *restrict s2;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-1,y-1,image->columns+2,3,exception);
+    q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    /*
+      Shade this row of pixels.
+    */
+    normal.z=2.0*(double) QuantumRange;  /* constant Z of surface normal */
+    s0=p+GetPixelChannels(image);
+    s1=s0+(image->columns+2)*GetPixelChannels(image);
+    s2=s1+(image->columns+2)*GetPixelChannels(image);
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      /*
+        Determine the surface normal and compute shading.
+      */
+      normal.x=(double) (GetPixelIntensity(image,s0-GetPixelChannels(image))+
+        GetPixelIntensity(image,s1-GetPixelChannels(image))+
+        GetPixelIntensity(image,s2-GetPixelChannels(image))-
+        GetPixelIntensity(image,s0+GetPixelChannels(image))-
+        GetPixelIntensity(image,s1+GetPixelChannels(image))-
+        GetPixelIntensity(image,s2+GetPixelChannels(image)));
+      normal.y=(double) (GetPixelIntensity(image,s2-GetPixelChannels(image))+
+        GetPixelIntensity(image,s2)+
+        GetPixelIntensity(image,s2+GetPixelChannels(image))-
+        GetPixelIntensity(image,s0-GetPixelChannels(image))-
+        GetPixelIntensity(image,s0)-
+        GetPixelIntensity(image,s0+GetPixelChannels(image)));
+      if ((normal.x == 0.0) && (normal.y == 0.0))
+        shade=light.z;
+      else
+        {
+          shade=0.0;
+          distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
+          if (distance > MagickEpsilon)
+            {
+              normal_distance=
+                normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
+              if (normal_distance > (MagickEpsilon*MagickEpsilon))
+                shade=distance/sqrt((double) normal_distance);
+            }
+        }
+      if (gray != MagickFalse)
+        {
+          SetPixelRed(shade_image,ClampToQuantum(shade),q);
+          SetPixelGreen(shade_image,ClampToQuantum(shade),q);
+          SetPixelBlue(shade_image,ClampToQuantum(shade),q);
+        }
+      else
+        {
+          SetPixelRed(shade_image,ClampToQuantum(QuantumScale*shade*
+            GetPixelRed(image,s1)),q);
+          SetPixelGreen(shade_image,ClampToQuantum(QuantumScale*shade*
+            GetPixelGreen(image,s1)),q);
+          SetPixelBlue(shade_image,ClampToQuantum(QuantumScale*shade*
+            GetPixelBlue(image,s1)),q);
+        }
+      SetPixelAlpha(shade_image,GetPixelAlpha(image,s1),q);
+      s0+=GetPixelChannels(image);
+      s1+=GetPixelChannels(image);
+      s2+=GetPixelChannels(image);
+      q+=GetPixelChannels(shade_image);
+    }
+    if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ShadeImage)
+#endif
+        proceed=SetImageProgress(image,ShadeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  shade_view=DestroyCacheView(shade_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    shade_image=DestroyImage(shade_image);
+  return(shade_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S h a r p e n I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SharpenImage() sharpens the image.  We convolve the image with a Gaussian
+%  operator of the given radius and standard deviation (sigma).  For
+%  reasonable results, radius should be larger than sigma.  Use a radius of 0
+%  and SharpenImage() selects a suitable radius for you.
+%
+%  Using a separable kernel would be faster, but the negative weights cancel
+%  out on the corners of the kernel producing often undesirable ringing in the
+%  filtered result; this can be avoided by using a 2D gaussian shaped image
+%  sharpening kernel instead.
+%
+%  The format of the SharpenImage method is:
+%
+%    Image *SharpenImage(const Image *image,const double radius,
+%      const double sigma,ExceptionInfo *exception)
+%    Image *SharpenImageChannel(const Image *image,const ChannelType channel,
+%      const double radius,const double sigma,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Laplacian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *SharpenImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  Image
+    *sharp_image;
+
+  sharp_image=SharpenImageChannel(image,DefaultChannels,radius,sigma,exception);
+  return(sharp_image);
+}
+
+MagickExport Image *SharpenImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  ExceptionInfo *exception)
+{
+  double
+    *kernel,
+    normalize;
+
+  Image
+    *sharp_image;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    u,
+    v;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  kernel=(double *) AcquireQuantumMemory((size_t) width*width,sizeof(*kernel));
+  if (kernel == (double *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  normalize=0.0;
+  j=(ssize_t) width/2;
+  i=0;
+  for (v=(-j); v <= j; v++)
+  {
+    for (u=(-j); u <= j; u++)
+    {
+      kernel[i]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
+        MagickSigma))/(2.0*MagickPI*MagickSigma*MagickSigma));
+      normalize+=kernel[i];
+      i++;
+    }
+  }
+  kernel[i/2]=(double) ((-2.0)*normalize);
+  sharp_image=ConvolveImageChannel(image,channel,width,kernel,exception);
+  kernel=(double *) RelinquishMagickMemory(kernel);
+  return(sharp_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S p r e a d I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SpreadImage() is a special effects method that randomly displaces each
+%  pixel in a block defined by the radius parameter.
+%
+%  The format of the SpreadImage method is:
+%
+%      Image *SpreadImage(const Image *image,const double radius,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius:  Choose a random pixel in a neighborhood of this extent.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SpreadImage(const Image *image,const double radius,
+  ExceptionInfo *exception)
+{
+#define SpreadImageTag  "Spread/Image"
+
+  CacheView
+    *image_view,
+    *spread_view;
+
+  Image
+    *spread_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  RandomInfo
+    **restrict random_info;
+
+  size_t
+    width;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize spread image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  spread_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (spread_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(spread_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&spread_image->exception);
+      spread_image=DestroyImage(spread_image);
+      return((Image *) NULL);
+    }
+  /*
+    Spread image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(spread_image,&bias);
+  width=GetOptimalKernelWidth1D(radius,0.5);
+  random_info=AcquireRandomInfoThreadSet();
+  image_view=AcquireCacheView(image);
+  spread_view=AcquireCacheView(spread_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) spread_image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    PixelInfo
+      pixel;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=bias;
+    for (x=0; x < (ssize_t) spread_image->columns; x++)
+    {
+      (void) InterpolatePixelInfo(image,image_view,
+        UndefinedInterpolatePixel,(double) x+width*(GetPseudoRandomValue(
+        random_info[id])-0.5),(double) y+width*(GetPseudoRandomValue(
+        random_info[id])-0.5),&pixel,exception);
+      SetPixelPixelInfo(spread_image,&pixel,q);
+      q+=GetPixelChannels(spread_image);
+    }
+    if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SpreadImage)
+#endif
+        proceed=SetImageProgress(image,SpreadImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  spread_view=DestroyCacheView(spread_view);
+  image_view=DestroyCacheView(image_view);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  return(spread_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S t a t i s t i c I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StatisticImage() makes each pixel the min / max / median / mode / etc. of
+%  the neighborhood of the specified width and height.
+%
+%  The format of the StatisticImage method is:
+%
+%      Image *StatisticImage(const Image *image,const StatisticType type,
+%        const size_t width,const size_t height,ExceptionInfo *exception)
+%      Image *StatisticImageChannel(const Image *image,
+%        const ChannelType channel,const StatisticType type,
+%        const size_t width,const size_t height,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the image channel.
+%
+%    o type: the statistic type (median, mode, etc.).
+%
+%    o width: the width of the pixel neighborhood.
+%
+%    o height: the height of the pixel neighborhood.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#define ListChannels  5
+
+typedef struct _ListNode
+{
+  size_t
+    next[9],
+    count,
+    signature;
+} ListNode;
+
+typedef struct _SkipList
+{
+  ssize_t
+    level;
+
+  ListNode
+    *nodes;
+} SkipList;
+
+typedef struct _PixelList
+{
+  size_t
+    length,
+    seed,
+    signature;
+
+  SkipList
+    lists[ListChannels];
+} PixelList;
+
+static PixelList *DestroyPixelList(PixelList *pixel_list)
+{
+  register ssize_t
+    i;
+
+  if (pixel_list == (PixelList *) NULL)
+    return((PixelList *) NULL);
+  for (i=0; i < ListChannels; i++)
+    if (pixel_list->lists[i].nodes != (ListNode *) NULL)
+      pixel_list->lists[i].nodes=(ListNode *) RelinquishMagickMemory(
+        pixel_list->lists[i].nodes);
+  pixel_list=(PixelList *) RelinquishMagickMemory(pixel_list);
+  return(pixel_list);
+}
+
+static PixelList **DestroyPixelListThreadSet(PixelList **pixel_list)
+{
+  register ssize_t
+    i;
+
+  assert(pixel_list != (PixelList **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (pixel_list[i] != (PixelList *) NULL)
+      pixel_list[i]=DestroyPixelList(pixel_list[i]);
+  pixel_list=(PixelList **) RelinquishMagickMemory(pixel_list);
+  return(pixel_list);
+}
+
+static PixelList *AcquirePixelList(const size_t width,const size_t height)
+{
+  PixelList
+    *pixel_list;
+
+  register ssize_t
+    i;
+
+  pixel_list=(PixelList *) AcquireMagickMemory(sizeof(*pixel_list));
+  if (pixel_list == (PixelList *) NULL)
+    return(pixel_list);
+  (void) ResetMagickMemory((void *) pixel_list,0,sizeof(*pixel_list));
+  pixel_list->length=width*height;
+  for (i=0; i < ListChannels; i++)
+  {
+    pixel_list->lists[i].nodes=(ListNode *) AcquireQuantumMemory(65537UL,
+      sizeof(*pixel_list->lists[i].nodes));
+    if (pixel_list->lists[i].nodes == (ListNode *) NULL)
+      return(DestroyPixelList(pixel_list));
+    (void) ResetMagickMemory(pixel_list->lists[i].nodes,0,65537UL*
+      sizeof(*pixel_list->lists[i].nodes));
+  }
+  pixel_list->signature=MagickSignature;
+  return(pixel_list);
+}
+
+static PixelList **AcquirePixelListThreadSet(const size_t width,
+  const size_t height)
+{
+  PixelList
+    **pixel_list;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixel_list=(PixelList **) AcquireQuantumMemory(number_threads,
+    sizeof(*pixel_list));
+  if (pixel_list == (PixelList **) NULL)
+    return((PixelList **) NULL);
+  (void) ResetMagickMemory(pixel_list,0,number_threads*sizeof(*pixel_list));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    pixel_list[i]=AcquirePixelList(width,height);
+    if (pixel_list[i] == (PixelList *) NULL)
+      return(DestroyPixelListThreadSet(pixel_list));
+  }
+  return(pixel_list);
+}
+
+static void AddNodePixelList(PixelList *pixel_list,const ssize_t channel,
+  const size_t color)
+{
+  register SkipList
+    *list;
+
+  register ssize_t
+    level;
+
+  size_t
+    search,
+    update[9];
+
+  /*
+    Initialize the node.
+  */
+  list=pixel_list->lists+channel;
+  list->nodes[color].signature=pixel_list->signature;
+  list->nodes[color].count=1;
+  /*
+    Determine where it belongs in the list.
+  */
+  search=65536UL;
+  for (level=list->level; level >= 0; level--)
+  {
+    while (list->nodes[search].next[level] < color)
+      search=list->nodes[search].next[level];
+    update[level]=search;
+  }
+  /*
+    Generate a pseudo-random level for this node.
+  */
+  for (level=0; ; level++)
+  {
+    pixel_list->seed=(pixel_list->seed*42893621L)+1L;
+    if ((pixel_list->seed & 0x300) != 0x300)
+      break;
+  }
+  if (level > 8)
+    level=8;
+  if (level > (list->level+2))
+    level=list->level+2;
+  /*
+    If we're raising the list's level, link back to the root node.
+  */
+  while (level > list->level)
+  {
+    list->level++;
+    update[list->level]=65536UL;
+  }
+  /*
+    Link the node into the skip-list.
+  */
+  do
+  {
+    list->nodes[color].next[level]=list->nodes[update[level]].next[level];
+    list->nodes[update[level]].next[level]=color;
+  } while (level-- > 0);
+}
+
+static PixelInfo GetMaximumPixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color,
+    maximum;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[ListChannels];
+
+  /*
+    Find the maximum value for each of the color.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536L;
+    count=0;
+    maximum=list->nodes[color].next[0];
+    do
+    {
+      color=list->nodes[color].next[0];
+      if (color > maximum)
+        maximum=color;
+      count+=list->nodes[color].count;
+    } while (count < (ssize_t) pixel_list->length);
+    channels[channel]=(unsigned short) maximum;
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  return(pixel);
+}
+
+static PixelInfo GetMeanPixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  MagickRealType
+    sum;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[ListChannels];
+
+  /*
+    Find the mean value for each of the color.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536L;
+    count=0;
+    sum=0.0;
+    do
+    {
+      color=list->nodes[color].next[0];
+      sum+=(MagickRealType) list->nodes[color].count*color;
+      count+=list->nodes[color].count;
+    } while (count < (ssize_t) pixel_list->length);
+    sum/=pixel_list->length;
+    channels[channel]=(unsigned short) sum;
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  return(pixel);
+}
+
+static PixelInfo GetMedianPixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[ListChannels];
+
+  /*
+    Find the median value for each of the color.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536L;
+    count=0;
+    do
+    {
+      color=list->nodes[color].next[0];
+      count+=list->nodes[color].count;
+    } while (count <= (ssize_t) (pixel_list->length >> 1));
+    channels[channel]=(unsigned short) color;
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  return(pixel);
+}
+
+static PixelInfo GetMinimumPixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color,
+    minimum;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[ListChannels];
+
+  /*
+    Find the minimum value for each of the color.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    count=0;
+    color=65536UL;
+    minimum=list->nodes[color].next[0];
+    do
+    {
+      color=list->nodes[color].next[0];
+      if (color < minimum)
+        minimum=color;
+      count+=list->nodes[color].count;
+    } while (count < (ssize_t) pixel_list->length);
+    channels[channel]=(unsigned short) minimum;
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  return(pixel);
+}
+
+static PixelInfo GetModePixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color,
+    max_count,
+    mode;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[5];
+
+  /*
+    Make each pixel the 'predominant color' of the specified neighborhood.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536L;
+    mode=color;
+    max_count=list->nodes[mode].count;
+    count=0;
+    do
+    {
+      color=list->nodes[color].next[0];
+      if (list->nodes[color].count > max_count)
+        {
+          mode=color;
+          max_count=list->nodes[mode].count;
+        }
+      count+=list->nodes[color].count;
+    } while (count < (ssize_t) pixel_list->length);
+    channels[channel]=(unsigned short) mode;
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  return(pixel);
+}
+
+static PixelInfo GetNonpeakPixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color,
+    next,
+    previous;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[5];
+
+  /*
+    Finds the non peak value for each of the colors.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536L;
+    next=list->nodes[color].next[0];
+    count=0;
+    do
+    {
+      previous=color;
+      color=next;
+      next=list->nodes[color].next[0];
+      count+=list->nodes[color].count;
+    } while (count <= (ssize_t) (pixel_list->length >> 1));
+    if ((previous == 65536UL) && (next != 65536UL))
+      color=next;
+    else
+      if ((previous != 65536UL) && (next == 65536UL))
+        color=previous;
+    channels[channel]=(unsigned short) color;
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  return(pixel);
+}
+
+static PixelInfo GetStandardDeviationPixelList(PixelList *pixel_list)
+{
+  PixelInfo
+    pixel;
+
+  MagickRealType
+    sum,
+    sum_squared;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  size_t
+    color;
+
+  ssize_t
+    count;
+
+  unsigned short
+    channels[ListChannels];
+
+  /*
+    Find the standard-deviation value for each of the color.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    color=65536L;
+    count=0;
+    sum=0.0;
+    sum_squared=0.0;
+    do
+    {
+      register ssize_t
+        i;
+
+      color=list->nodes[color].next[0];
+      sum+=(MagickRealType) list->nodes[color].count*color;
+      for (i=0; i < (ssize_t) list->nodes[color].count; i++)
+        sum_squared+=((MagickRealType) color)*((MagickRealType) color);
+      count+=list->nodes[color].count;
+    } while (count < (ssize_t) pixel_list->length);
+    sum/=pixel_list->length;
+    sum_squared/=pixel_list->length;
+    channels[channel]=(unsigned short) sqrt(sum_squared-(sum*sum));
+  }
+  GetPixelInfo((const Image *) NULL,&pixel);
+  pixel.red=(MagickRealType) ScaleShortToQuantum(channels[0]);
+  pixel.green=(MagickRealType) ScaleShortToQuantum(channels[1]);
+  pixel.blue=(MagickRealType) ScaleShortToQuantum(channels[2]);
+  pixel.alpha=(MagickRealType) ScaleShortToQuantum(channels[3]);
+  pixel.black=(MagickRealType) ScaleShortToQuantum(channels[4]);
+  return(pixel);
+}
+
+static inline void InsertPixelList(const Image *image,const Quantum *pixel,
+  PixelList *pixel_list)
+{
+  size_t
+    signature;
+
+  unsigned short
+    index;
+
+  index=ScaleQuantumToShort(GetPixelRed(image,pixel));
+  signature=pixel_list->lists[0].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[0].nodes[index].count++;
+  else
+    AddNodePixelList(pixel_list,0,index);
+  index=ScaleQuantumToShort(GetPixelGreen(image,pixel));
+  signature=pixel_list->lists[1].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[1].nodes[index].count++;
+  else
+    AddNodePixelList(pixel_list,1,index);
+  index=ScaleQuantumToShort(GetPixelBlue(image,pixel));
+  signature=pixel_list->lists[2].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[2].nodes[index].count++;
+  else
+    AddNodePixelList(pixel_list,2,index);
+  index=ScaleQuantumToShort(GetPixelAlpha(image,pixel));
+  signature=pixel_list->lists[3].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[3].nodes[index].count++;
+  else
+    AddNodePixelList(pixel_list,3,index);
+  if (image->colorspace == CMYKColorspace)
+    index=ScaleQuantumToShort(GetPixelBlack(image,pixel));
+  signature=pixel_list->lists[4].nodes[index].signature;
+  if (signature == pixel_list->signature)
+    pixel_list->lists[4].nodes[index].count++;
+  else
+    AddNodePixelList(pixel_list,4,index);
+}
+
+static inline MagickRealType MagickAbsoluteValue(const MagickRealType x)
+{
+  if (x < 0)
+    return(-x);
+  return(x);
+}
+
+static void ResetPixelList(PixelList *pixel_list)
+{
+  int
+    level;
+
+  register ListNode
+    *root;
+
+  register SkipList
+    *list;
+
+  register ssize_t
+    channel;
+
+  /*
+    Reset the skip-list.
+  */
+  for (channel=0; channel < 5; channel++)
+  {
+    list=pixel_list->lists+channel;
+    root=list->nodes+65536UL;
+    list->level=0;
+    for (level=0; level < 9; level++)
+      root->next[level]=65536UL;
+  }
+  pixel_list->seed=pixel_list->signature++;
+}
+
+MagickExport Image *StatisticImage(const Image *image,const StatisticType type,
+  const size_t width,const size_t height,ExceptionInfo *exception)
+{
+  Image
+    *statistic_image;
+
+  statistic_image=StatisticImageChannel(image,DefaultChannels,type,width,
+    height,exception);
+  return(statistic_image);
+}
+
+MagickExport Image *StatisticImageChannel(const Image *image,
+  const ChannelType channel,const StatisticType type,const size_t width,
+  const size_t height,ExceptionInfo *exception)
+{
+#define StatisticWidth \
+  (width == 0 ? GetOptimalKernelWidth2D((double) width,0.5) : width)
+#define StatisticHeight \
+  (height == 0 ? GetOptimalKernelWidth2D((double) height,0.5) : height)
+#define StatisticImageTag  "Statistic/Image"
+
+  CacheView
+    *image_view,
+    *statistic_view;
+
+  Image
+    *statistic_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelList
+    **restrict pixel_list;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize statistics image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  statistic_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (statistic_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(statistic_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&statistic_image->exception);
+      statistic_image=DestroyImage(statistic_image);
+      return((Image *) NULL);
+    }
+  pixel_list=AcquirePixelListThreadSet(StatisticWidth,StatisticHeight);
+  if (pixel_list == (PixelList **) NULL)
+    {
+      statistic_image=DestroyImage(statistic_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Make each pixel the min / max / median / mode / etc. of the neighborhood.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  statistic_view=AcquireCacheView(statistic_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) statistic_image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) StatisticWidth/2L),y-
+      (ssize_t) (StatisticHeight/2L),image->columns+StatisticWidth,
+      StatisticHeight,exception);
+    q=QueueCacheViewAuthenticPixels(statistic_view,0,y,statistic_image->columns,      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) statistic_image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      register const Quantum
+        *restrict r;
+
+      register ssize_t
+        u,
+        v;
+
+      r=p;
+      ResetPixelList(pixel_list[id]);
+      for (v=0; v < (ssize_t) StatisticHeight; v++)
+      {
+        for (u=0; u < (ssize_t) StatisticWidth; u++)
+          InsertPixelList(image,r+u*GetPixelChannels(image),pixel_list[id]);
+        r+=(image->columns+StatisticWidth)*GetPixelChannels(image);
+      }
+      GetPixelInfo(image,&pixel);
+      SetPixelInfo(image,p+StatisticWidth*StatisticHeight/2,&pixel);
+      switch (type)
+      {
+        case GradientStatistic:
+        {
+          PixelInfo
+            maximum,
+            minimum;
+
+          minimum=GetMinimumPixelList(pixel_list[id]);
+          maximum=GetMaximumPixelList(pixel_list[id]);
+          pixel.red=MagickAbsoluteValue(maximum.red-minimum.red);
+          pixel.green=MagickAbsoluteValue(maximum.green-minimum.green);
+          pixel.blue=MagickAbsoluteValue(maximum.blue-minimum.blue);
+          pixel.alpha=MagickAbsoluteValue(maximum.alpha-minimum.alpha);
+          if (image->colorspace == CMYKColorspace)
+            pixel.black=MagickAbsoluteValue(maximum.black-minimum.black);
+          break;
+        }
+        case MaximumStatistic:
+        {
+          pixel=GetMaximumPixelList(pixel_list[id]);
+          break;
+        }
+        case MeanStatistic:
+        {
+          pixel=GetMeanPixelList(pixel_list[id]);
+          break;
+        }
+        case MedianStatistic:
+        default:
+        {
+          pixel=GetMedianPixelList(pixel_list[id]);
+          break;
+        }
+        case MinimumStatistic:
+        {
+          pixel=GetMinimumPixelList(pixel_list[id]);
+          break;
+        }
+        case ModeStatistic:
+        {
+          pixel=GetModePixelList(pixel_list[id]);
+          break;
+        }
+        case NonpeakStatistic:
+        {
+          pixel=GetNonpeakPixelList(pixel_list[id]);
+          break;
+        }
+        case StandardDeviationStatistic:
+        {
+          pixel=GetStandardDeviationPixelList(pixel_list[id]);
+          break;
+        }
+      }
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(statistic_image,
+          ClampToQuantum(pixel.red),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(statistic_image,
+          ClampToQuantum(pixel.green),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(statistic_image,
+          ClampToQuantum(pixel.blue),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(statistic_image,
+          ClampToQuantum(pixel.black),q);
+      if (((channel & AlphaChannel) != 0) &&
+          (image->matte != MagickFalse))
+        SetPixelAlpha(statistic_image,
+          ClampToQuantum(pixel.alpha),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(statistic_image);
+    }
+    if (SyncCacheViewAuthenticPixels(statistic_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_StatisticImage)
+#endif
+        proceed=SetImageProgress(image,StatisticImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  statistic_view=DestroyCacheView(statistic_view);
+  image_view=DestroyCacheView(image_view);
+  pixel_list=DestroyPixelListThreadSet(pixel_list);
+  return(statistic_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     U n s h a r p M a s k I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnsharpMaskImage() sharpens one or more image channels.  We convolve the
+%  image with a Gaussian operator of the given radius and standard deviation
+%  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
+%  radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
+%
+%  The format of the UnsharpMaskImage method is:
+%
+%    Image *UnsharpMaskImage(const Image *image,const double radius,
+%      const double sigma,const double amount,const double threshold,
+%      ExceptionInfo *exception)
+%    Image *UnsharpMaskImageChannel(const Image *image,
+%      const ChannelType channel,const double radius,const double sigma,
+%      const double amount,const double threshold,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o amount: the percentage of the difference between the original and the
+%      blur image that is added back into the original.
+%
+%    o threshold: the threshold in pixels needed to apply the diffence amount.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
+  const double sigma,const double amount,const double threshold,
+  ExceptionInfo *exception)
+{
+  Image
+    *sharp_image;
+
+  sharp_image=UnsharpMaskImageChannel(image,DefaultChannels,radius,sigma,amount,
+    threshold,exception);
+  return(sharp_image);
+}
+
+MagickExport Image *UnsharpMaskImageChannel(const Image *image,
+  const ChannelType channel,const double radius,const double sigma,
+  const double amount,const double threshold,ExceptionInfo *exception)
+{
+#define SharpenImageTag  "Sharpen/Image"
+
+  CacheView
+    *image_view,
+    *unsharp_view;
+
+  Image
+    *unsharp_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    bias;
+
+  MagickRealType
+    quantum_threshold;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  unsharp_image=BlurImageChannel(image,channel,radius,sigma,exception);
+  if (unsharp_image == (Image *) NULL)
+    return((Image *) NULL);
+  quantum_threshold=(MagickRealType) QuantumRange*threshold;
+  /*
+    Unsharp-mask image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&bias);
+  image_view=AcquireCacheView(image);
+  unsharp_view=AcquireCacheView(unsharp_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=bias;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          pixel.red=GetPixelRed(image,p)-(MagickRealType) GetPixelRed(image,q);
+          if (fabs(2.0*pixel.red) < quantum_threshold)
+            pixel.red=(MagickRealType) GetPixelRed(image,p);
+          else
+            pixel.red=(MagickRealType) GetPixelRed(image,p)+(pixel.red*amount);
+          SetPixelRed(unsharp_image,ClampToQuantum(pixel.red),q);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          pixel.green=GetPixelGreen(image,p)-
+            (MagickRealType) GetPixelGreen(image,q);
+          if (fabs(2.0*pixel.green) < quantum_threshold)
+            pixel.green=(MagickRealType)
+              GetPixelGreen(image,p);
+          else
+            pixel.green=(MagickRealType)
+              GetPixelGreen(image,p)+
+              (pixel.green*amount);
+          SetPixelGreen(unsharp_image,
+            ClampToQuantum(pixel.green),q);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          pixel.blue=GetPixelBlue(image,p)-
+            (MagickRealType) GetPixelBlue(image,q);
+          if (fabs(2.0*pixel.blue) < quantum_threshold)
+            pixel.blue=(MagickRealType)
+              GetPixelBlue(image,p);
+          else
+            pixel.blue=(MagickRealType)
+              GetPixelBlue(image,p)+(pixel.blue*amount);
+          SetPixelBlue(unsharp_image,
+            ClampToQuantum(pixel.blue),q);
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          pixel.black=GetPixelBlack(image,p)-
+            (MagickRealType) GetPixelBlack(image,q);
+          if (fabs(2.0*pixel.black) < quantum_threshold)
+            pixel.black=(MagickRealType)
+              GetPixelBlack(image,p);
+          else
+            pixel.black=(MagickRealType)
+              GetPixelBlack(image,p)+(pixel.black*
+              amount);
+          SetPixelBlack(unsharp_image,
+            ClampToQuantum(pixel.black),q);
+        }
+      if ((channel & AlphaChannel) != 0)
+        {
+          pixel.alpha=GetPixelAlpha(image,p)-
+            (MagickRealType) GetPixelAlpha(image,q);
+          if (fabs(2.0*pixel.alpha) < quantum_threshold)
+            pixel.alpha=(MagickRealType)
+              GetPixelAlpha(image,p);
+          else
+            pixel.alpha=GetPixelAlpha(image,p)+
+              (pixel.alpha*amount);
+          SetPixelAlpha(unsharp_image,
+            ClampToQuantum(pixel.alpha),q);
+        }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(unsharp_image);
+    }
+    if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_UnsharpMaskImageChannel)
+#endif
+        proceed=SetImageProgress(image,SharpenImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  unsharp_image->type=image->type;
+  unsharp_view=DestroyCacheView(unsharp_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    unsharp_image=DestroyImage(unsharp_image);
+  return(unsharp_image);
+}
diff --git a/MagickCore/effect.h b/MagickCore/effect.h
new file mode 100644
index 0000000..d41ce88
--- /dev/null
+++ b/MagickCore/effect.h
@@ -0,0 +1,128 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image effects methods.
+*/
+#ifndef _MAGICKCORE_EFFECT_H
+#define _MAGICKCORE_EFFECT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/morphology.h>
+
+typedef enum
+{
+  UndefinedPreview,
+  RotatePreview,
+  ShearPreview,
+  RollPreview,
+  HuePreview,
+  SaturationPreview,
+  BrightnessPreview,
+  GammaPreview,
+  SpiffPreview,
+  DullPreview,
+  GrayscalePreview,
+  QuantizePreview,
+  DespecklePreview,
+  ReduceNoisePreview,
+  AddNoisePreview,
+  SharpenPreview,
+  BlurPreview,
+  ThresholdPreview,
+  EdgeDetectPreview,
+  SpreadPreview,
+  SolarizePreview,
+  ShadePreview,
+  RaisePreview,
+  SegmentPreview,
+  SwirlPreview,
+  ImplodePreview,
+  WavePreview,
+  OilPaintPreview,
+  CharcoalDrawingPreview,
+  JPEGPreview
+} PreviewType;
+
+typedef enum
+{
+  UndefinedStatistic,
+  GradientStatistic,
+  MaximumStatistic,
+  MeanStatistic,
+  MedianStatistic,
+  MinimumStatistic,
+  ModeStatistic,
+  NonpeakStatistic,
+  StandardDeviationStatistic
+} StatisticType;
+
+extern MagickExport Image
+  *AdaptiveBlurImage(const Image *,const double,const double,ExceptionInfo *),
+  *AdaptiveBlurImageChannel(const Image *,const ChannelType,const double,
+    const double,ExceptionInfo *),
+  *AdaptiveSharpenImage(const Image *,const double,const double,
+     ExceptionInfo *),
+  *AdaptiveSharpenImageChannel(const Image *,const ChannelType,const double,
+    const double,ExceptionInfo *),
+  *BlurImage(const Image *,const double,const double,ExceptionInfo *),
+  *BlurImageChannel(const Image *,const ChannelType,const double,const double,
+    ExceptionInfo *),
+  *ConvolveImage(const Image *,const size_t,const double *,ExceptionInfo *),
+  *ConvolveImageChannel(const Image *,const ChannelType,const size_t,
+    const double *,ExceptionInfo *),
+  *DespeckleImage(const Image *,ExceptionInfo *),
+  *EdgeImage(const Image *,const double,ExceptionInfo *),
+  *EmbossImage(const Image *,const double,const double,ExceptionInfo *),
+  *FilterImage(const Image *,const KernelInfo *,ExceptionInfo *),
+  *FilterImageChannel(const Image *,const ChannelType,const KernelInfo *,
+     ExceptionInfo *),
+  *GaussianBlurImage(const Image *,const double,const double,ExceptionInfo *),
+  *GaussianBlurImageChannel(const Image *,const ChannelType,const double,
+    const double,ExceptionInfo *),
+  *MotionBlurImage(const Image *,const double,const double,const double,
+    ExceptionInfo *),
+  *MotionBlurImageChannel(const Image *,const ChannelType,const double,
+    const double,const double,ExceptionInfo *),
+  *PreviewImage(const Image *,const PreviewType,ExceptionInfo *),
+  *RadialBlurImage(const Image *,const double,ExceptionInfo *),
+  *RadialBlurImageChannel(const Image *,const ChannelType,const double,
+    ExceptionInfo *),
+  *SelectiveBlurImage(const Image *,const double,const double,const double,
+    ExceptionInfo *),
+  *SelectiveBlurImageChannel(const Image *,const ChannelType,const double,
+    const double,const double,ExceptionInfo *),
+  *ShadeImage(const Image *,const MagickBooleanType,const double,const double,
+    ExceptionInfo *),
+  *SharpenImage(const Image *,const double,const double,ExceptionInfo *),
+  *SharpenImageChannel(const Image *,const ChannelType,const double,
+    const double,ExceptionInfo *),
+  *SpreadImage(const Image *,const double,ExceptionInfo *),
+  *StatisticImage(const Image *,const StatisticType,const size_t,const size_t,
+    ExceptionInfo *),
+  *StatisticImageChannel(const Image *,const ChannelType,const StatisticType,
+    const size_t,const size_t,ExceptionInfo *),
+  *UnsharpMaskImage(const Image *,const double,const double,const double,
+    const double,ExceptionInfo *),
+  *UnsharpMaskImageChannel(const Image *,const ChannelType,const double,
+    const double,const double,const double,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/enhance.c b/MagickCore/enhance.c
new file mode 100644
index 0000000..bff00db
--- /dev/null
+++ b/MagickCore/enhance.c
@@ -0,0 +1,3842 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%              EEEEE  N   N  H   H   AAA   N   N   CCCC  EEEEE                %
+%              E      NN  N  H   H  A   A  NN  N  C      E                    %
+%              EEE    N N N  HHHHH  AAAAA  N N N  C      EEE                  %
+%              E      N  NN  H   H  A   A  N  NN  C      E                    %
+%              EEEEE  N   N  H   H  A   A  N   N   CCCC  EEEEE                %
+%                                                                             %
+%                                                                             %
+%                    MagickCore Image Enhancement Methods                     %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resample-private.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A u t o G a m m a I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AutoGammaImage() extract the 'mean' from the image and adjust the image
+%  to try make set its gamma appropriatally.
+%
+%  The format of the AutoGammaImage method is:
+%
+%      MagickBooleanType AutoGammaImage(Image *image)
+%      MagickBooleanType AutoGammaImageChannel(Image *image,
+%        const ChannelType channel)
+%
+%  A description of each parameter follows:
+%
+%    o image: The image to auto-level
+%
+%    o channel: The channels to auto-level.  If the special 'SyncChannels'
+%      flag is set all given channels is adjusted in the same way using the
+%      mean average of those channels.
+%
+*/
+
+MagickExport MagickBooleanType AutoGammaImage(Image *image)
+{
+  return(AutoGammaImageChannel(image,DefaultChannels));
+}
+
+MagickExport MagickBooleanType AutoGammaImageChannel(Image *image,
+  const ChannelType channel)
+{
+  MagickStatusType
+    status;
+
+  double
+    gamma,
+    log_mean,
+    mean,
+    sans;
+
+  log_mean=log(0.5);
+
+  if ((channel & SyncChannels) != 0 )
+    {
+      /*
+        Apply gamma correction equally accross all given channels
+      */
+      (void) GetImageChannelMean(image,channel,&mean,&sans,&image->exception);
+      gamma=log(mean*QuantumScale)/log_mean;
+      return(LevelImageChannel(image,channel,0.0,(double)QuantumRange,gamma));
+    }
+
+  /*
+    Auto-gamma each channel separately.
+  */
+  status=MagickTrue;
+  if ((channel & RedChannel) != 0)
+    {
+      (void) GetImageChannelMean(image,RedChannel,&mean,&sans,
+        &image->exception);
+      gamma=log(mean*QuantumScale)/log_mean;
+      status=status && LevelImageChannel(image,RedChannel,0.0,(double)
+        QuantumRange, gamma);
+    }
+  if ((channel & GreenChannel) != 0)
+    {
+      (void) GetImageChannelMean(image,GreenChannel,&mean,&sans,
+        &image->exception);
+      gamma=log(mean*QuantumScale)/log_mean;
+      status=status && LevelImageChannel(image,GreenChannel,0.0,(double)
+        QuantumRange,gamma);
+    }
+  if ((channel & BlueChannel) != 0)
+    {
+      (void) GetImageChannelMean(image,BlueChannel,&mean,&sans,
+        &image->exception);
+      gamma=log(mean*QuantumScale)/log_mean;
+      status=status && LevelImageChannel(image,BlueChannel,0.0,(double)
+        QuantumRange,gamma);
+    }
+  if (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    {
+      (void) GetImageChannelMean(image,BlackChannel,&mean,&sans,
+        &image->exception);
+      gamma=log(mean*QuantumScale)/log_mean;
+      status=status && LevelImageChannel(image,BlackChannel,0.0,(double)
+        QuantumRange,gamma);
+    }
+  if (((channel & OpacityChannel) != 0) &&
+      (image->matte == MagickTrue))
+    {
+      (void) GetImageChannelMean(image,OpacityChannel,&mean,&sans,
+        &image->exception);
+      gamma=log(mean*QuantumScale)/log_mean;
+      status=status && LevelImageChannel(image,OpacityChannel,0.0,(double)
+        QuantumRange,gamma);
+    }
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A u t o L e v e l I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AutoLevelImage() adjusts the levels of a particular image channel by
+%  scaling the minimum and maximum values to the full quantum range.
+%
+%  The format of the LevelImage method is:
+%
+%      MagickBooleanType AutoLevelImage(Image *image)
+%      MagickBooleanType AutoLevelImageChannel(Image *image,
+%        const ChannelType channel)
+%
+%  A description of each parameter follows:
+%
+%    o image: The image to auto-level
+%
+%    o channel: The channels to auto-level.  If the special 'SyncChannels'
+%      flag is set the min/max/mean value of all given channels is used for
+%      all given channels, to all channels in the same way.
+%
+*/
+
+MagickExport MagickBooleanType AutoLevelImage(Image *image)
+{
+  return(AutoLevelImageChannel(image,DefaultChannels));
+}
+
+MagickExport MagickBooleanType AutoLevelImageChannel(Image *image,
+  const ChannelType channel)
+{
+  /*
+    This is simply a convenience function around a Min/Max Histogram Stretch
+  */
+  return MinMaxStretchImage(image, channel, 0.0, 0.0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     B r i g h t n e s s C o n t r a s t I m a g e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Use BrightnessContrastImage() to change the brightness and/or contrast of
+%  an image.  It converts the brightness and contrast parameters into slope
+%  and intercept and calls a polynomical function to apply to the image.
+%
+%  The format of the BrightnessContrastImage method is:
+%
+%      MagickBooleanType BrightnessContrastImage(Image *image,
+%        const double brightness,const double contrast)
+%      MagickBooleanType BrightnessContrastImageChannel(Image *image,
+%        const ChannelType channel,const double brightness,
+%        const double contrast)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o brightness: the brightness percent (-100 .. 100).
+%
+%    o contrast: the contrast percent (-100 .. 100).
+%
+*/
+
+MagickExport MagickBooleanType BrightnessContrastImage(Image *image,
+  const double brightness,const double contrast)
+{
+  MagickBooleanType
+    status;
+
+  status=BrightnessContrastImageChannel(image,DefaultChannels,brightness,
+    contrast);
+  return(status);
+}
+
+MagickExport MagickBooleanType BrightnessContrastImageChannel(Image *image,
+  const ChannelType channel,const double brightness,const double contrast)
+{
+#define BrightnessContastImageTag  "BrightnessContast/Image"
+
+  double
+    alpha,
+    intercept,
+    coefficients[2],
+    slope;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Compute slope and intercept.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  alpha=contrast;
+  slope=tan((double) (MagickPI*(alpha/100.0+1.0)/4.0));
+  if (slope < 0.0)
+    slope=0.0;
+  intercept=brightness/100.0+((100-brightness)/200.0)*(1.0-slope);
+  coefficients[0]=slope;
+  coefficients[1]=intercept;
+  status=FunctionImageChannel(image,channel,PolynomialFunction,2,coefficients,
+    &image->exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o l o r D e c i s i o n L i s t I m a g e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ColorDecisionListImage() accepts a lightweight Color Correction Collection
+%  (CCC) file which solely contains one or more color corrections and applies
+%  the correction to the image.  Here is a sample CCC file:
+%
+%    <ColorCorrectionCollection xmlns="urn:ASC:CDL:v1.2">
+%          <ColorCorrection id="cc03345">
+%                <SOPNode>
+%                     <Slope> 0.9 1.2 0.5 </Slope>
+%                     <Offset> 0.4 -0.5 0.6 </Offset>
+%                     <Power> 1.0 0.8 1.5 </Power>
+%                </SOPNode>
+%                <SATNode>
+%                     <Saturation> 0.85 </Saturation>
+%                </SATNode>
+%          </ColorCorrection>
+%    </ColorCorrectionCollection>
+%
+%  which includes the slop, offset, and power for each of the RGB channels
+%  as well as the saturation.
+%
+%  The format of the ColorDecisionListImage method is:
+%
+%      MagickBooleanType ColorDecisionListImage(Image *image,
+%        const char *color_correction_collection)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o color_correction_collection: the color correction collection in XML.
+%
+*/
+MagickExport MagickBooleanType ColorDecisionListImage(Image *image,
+  const char *color_correction_collection)
+{
+#define ColorDecisionListCorrectImageTag  "ColorDecisionList/Image"
+
+  typedef struct _Correction
+  {
+    double
+      slope,
+      offset,
+      power;
+  } Correction;
+
+  typedef struct _ColorCorrection
+  {
+    Correction
+      red,
+      green,
+      blue;
+
+    double
+      saturation;
+  } ColorCorrection;
+
+  CacheView
+    *image_view;
+
+  char
+    token[MaxTextExtent];
+
+  ColorCorrection
+    color_correction;
+
+  const char
+    *content,
+    *p;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelPacket
+    *cdl_map;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  XMLTreeInfo
+    *cc,
+    *ccc,
+    *sat,
+    *sop;
+
+  /*
+    Allocate and initialize cdl maps.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (color_correction_collection == (const char *) NULL)
+    return(MagickFalse);
+  ccc=NewXMLTree((const char *) color_correction_collection,&image->exception);
+  if (ccc == (XMLTreeInfo *) NULL)
+    return(MagickFalse);
+  cc=GetXMLTreeChild(ccc,"ColorCorrection");
+  if (cc == (XMLTreeInfo *) NULL)
+    {
+      ccc=DestroyXMLTree(ccc);
+      return(MagickFalse);
+    }
+  color_correction.red.slope=1.0;
+  color_correction.red.offset=0.0;
+  color_correction.red.power=1.0;
+  color_correction.green.slope=1.0;
+  color_correction.green.offset=0.0;
+  color_correction.green.power=1.0;
+  color_correction.blue.slope=1.0;
+  color_correction.blue.offset=0.0;
+  color_correction.blue.power=1.0;
+  color_correction.saturation=0.0;
+  sop=GetXMLTreeChild(cc,"SOPNode");
+  if (sop != (XMLTreeInfo *) NULL)
+    {
+      XMLTreeInfo
+        *offset,
+        *power,
+        *slope;
+
+      slope=GetXMLTreeChild(sop,"Slope");
+      if (slope != (XMLTreeInfo *) NULL)
+        {
+          content=GetXMLTreeContent(slope);
+          p=(const char *) content;
+          for (i=0; (*p != '\0') && (i < 3); i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            switch (i)
+            {
+              case 0:
+              {
+                color_correction.red.slope=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+              case 1:
+              {
+                color_correction.green.slope=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+              case 2:
+              {
+                color_correction.blue.slope=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+            }
+          }
+        }
+      offset=GetXMLTreeChild(sop,"Offset");
+      if (offset != (XMLTreeInfo *) NULL)
+        {
+          content=GetXMLTreeContent(offset);
+          p=(const char *) content;
+          for (i=0; (*p != '\0') && (i < 3); i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            switch (i)
+            {
+              case 0:
+              {
+                color_correction.red.offset=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+              case 1:
+              {
+                color_correction.green.offset=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+              case 2:
+              {
+                color_correction.blue.offset=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+            }
+          }
+        }
+      power=GetXMLTreeChild(sop,"Power");
+      if (power != (XMLTreeInfo *) NULL)
+        {
+          content=GetXMLTreeContent(power);
+          p=(const char *) content;
+          for (i=0; (*p != '\0') && (i < 3); i++)
+          {
+            GetMagickToken(p,&p,token);
+            if (*token == ',')
+              GetMagickToken(p,&p,token);
+            switch (i)
+            {
+              case 0:
+              {
+                color_correction.red.power=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+              case 1:
+              {
+                color_correction.green.power=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+              case 2:
+              {
+                color_correction.blue.power=InterpretLocaleValue(token,
+                  (char **) NULL);
+                break;
+              }
+            }
+          }
+        }
+    }
+  sat=GetXMLTreeChild(cc,"SATNode");
+  if (sat != (XMLTreeInfo *) NULL)
+    {
+      XMLTreeInfo
+        *saturation;
+
+      saturation=GetXMLTreeChild(sat,"Saturation");
+      if (saturation != (XMLTreeInfo *) NULL)
+        {
+          content=GetXMLTreeContent(saturation);
+          p=(const char *) content;
+          GetMagickToken(p,&p,token);
+          color_correction.saturation=InterpretLocaleValue(token,
+            (char **) NULL);
+        }
+    }
+  ccc=DestroyXMLTree(ccc);
+  if (image->debug != MagickFalse)
+    {
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  Color Correction Collection:");
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.red.slope: %g",color_correction.red.slope);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.red.offset: %g",color_correction.red.offset);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.red.power: %g",color_correction.red.power);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.green.slope: %g",color_correction.green.slope);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.green.offset: %g",color_correction.green.offset);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.green.power: %g",color_correction.green.power);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.blue.slope: %g",color_correction.blue.slope);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.blue.offset: %g",color_correction.blue.offset);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.blue.power: %g",color_correction.blue.power);
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  color_correction.saturation: %g",color_correction.saturation);
+    }
+  cdl_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*cdl_map));
+  if (cdl_map == (PixelPacket *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    cdl_map[i].red=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
+      MagickRealType) (MaxMap*(pow(color_correction.red.slope*i/MaxMap+
+      color_correction.red.offset,color_correction.red.power)))));
+    cdl_map[i].green=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
+      MagickRealType) (MaxMap*(pow(color_correction.green.slope*i/MaxMap+
+      color_correction.green.offset,color_correction.green.power)))));
+    cdl_map[i].blue=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
+      MagickRealType) (MaxMap*(pow(color_correction.blue.slope*i/MaxMap+
+      color_correction.blue.offset,color_correction.blue.power)))));
+  }
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Apply transfer function to colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        double
+          luma;
+
+        luma=0.2126*image->colormap[i].red+0.7152*image->colormap[i].green+
+          0.0722*image->colormap[i].blue;
+        image->colormap[i].red=ClampToQuantum(luma+color_correction.saturation*
+          cdl_map[ScaleQuantumToMap(image->colormap[i].red)].red-luma);
+        image->colormap[i].green=ClampToQuantum(luma+
+          color_correction.saturation*cdl_map[ScaleQuantumToMap(
+          image->colormap[i].green)].green-luma);
+        image->colormap[i].blue=ClampToQuantum(luma+color_correction.saturation*
+          cdl_map[ScaleQuantumToMap(image->colormap[i].blue)].blue-luma);
+      }
+    }
+  /*
+    Apply transfer function to image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      luma;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      luma=0.2126*GetPixelRed(image,q)+0.7152*GetPixelGreen(image,q)+0.0722*
+        GetPixelBlue(image,q);
+      SetPixelRed(image,ClampToQuantum(luma+color_correction.saturation*
+        (cdl_map[ScaleQuantumToMap(GetPixelRed(image,q))].red-luma)),q);
+      SetPixelGreen(image,ClampToQuantum(luma+color_correction.saturation*
+        (cdl_map[ScaleQuantumToMap(GetPixelGreen(image,q))].green-luma)),q);
+      SetPixelBlue(image,ClampToQuantum(luma+color_correction.saturation*
+        (cdl_map[ScaleQuantumToMap(GetPixelBlue(image,q))].blue-luma)),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ColorDecisionListImageChannel)
+#endif
+        proceed=SetImageProgress(image,ColorDecisionListCorrectImageTag,
+          progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  cdl_map=(PixelPacket *) RelinquishMagickMemory(cdl_map);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C l u t I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClutImage() replaces each color value in the given image, by using it as an
+%  index to lookup a replacement color value in a Color Look UP Table in the
+%  form of an image.  The values are extracted along a diagonal of the CLUT
+%  image so either a horizontal or vertial gradient image can be used.
+%
+%  Typically this is used to either re-color a gray-scale image according to a
+%  color gradient in the CLUT image, or to perform a freeform histogram
+%  (level) adjustment according to the (typically gray-scale) gradient in the
+%  CLUT image.
+%
+%  When the 'channel' mask includes the matte/alpha transparency channel but
+%  one image has no such channel it is assumed that that image is a simple
+%  gray-scale image that will effect the alpha channel values, either for
+%  gray-scale coloring (with transparent or semi-transparent colors), or
+%  a histogram adjustment of existing alpha channel values.   If both images
+%  have matte channels, direct and normal indexing is applied, which is rarely
+%  used.
+%
+%  The format of the ClutImage method is:
+%
+%      MagickBooleanType ClutImage(Image *image,Image *clut_image)
+%      MagickBooleanType ClutImageChannel(Image *image,
+%        const ChannelType channel,Image *clut_image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image, which is replaced by indexed CLUT values
+%
+%    o clut_image: the color lookup table image for replacement color values.
+%
+%    o channel: the channel.
+%
+*/
+
+MagickExport MagickBooleanType ClutImage(Image *image,const Image *clut_image)
+{
+  return(ClutImageChannel(image,DefaultChannels,clut_image));
+}
+
+MagickExport MagickBooleanType ClutImageChannel(Image *image,
+  const ChannelType channel,const Image *clut_image)
+{
+#define ClampAlphaPixelComponent(pixel) ClampToQuantum((pixel)->alpha)
+#define ClampBlackPixelComponent(pixel) ClampToQuantum((pixel)->black)
+#define ClampBluePixelComponent(pixel) ClampToQuantum((pixel)->blue)
+#define ClampGreenPixelComponent(pixel) ClampToQuantum((pixel)->green)
+#define ClampRedPixelComponent(pixel) ClampToQuantum((pixel)->red)
+#define ClutImageTag  "Clut/Image"
+
+  CacheView
+    *clut_view,
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    *clut_map;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    adjust,
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(clut_image != (Image *) NULL);
+  assert(clut_image->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  clut_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*clut_map));
+  if (clut_map == (PixelInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  /*
+    Clut image.
+  */
+  status=MagickTrue;
+  progress=0;
+  adjust=(ssize_t) (clut_image->interpolate == IntegerInterpolatePixel ? 0 : 1);
+  exception=(&image->exception);
+  clut_view=AcquireCacheView(clut_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    GetPixelInfo(clut_image,clut_map+i);
+    (void) InterpolatePixelInfo(clut_image,clut_view,
+      UndefinedInterpolatePixel,QuantumScale*i*(clut_image->columns-adjust),
+      QuantumScale*i*(clut_image->rows-adjust),clut_map+i,exception);
+  }
+  clut_view=DestroyCacheView(clut_view);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    GetPixelInfo(image,&pixel);
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,q,&pixel);
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,ClampRedPixelComponent(clut_map+
+          ScaleQuantumToMap(GetPixelRed(image,q))),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,ClampGreenPixelComponent(clut_map+
+          ScaleQuantumToMap(GetPixelGreen(image,q))),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,ClampBluePixelComponent(clut_map+
+          ScaleQuantumToMap(GetPixelBlue(image,q))),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,ClampBlackPixelComponent(clut_map+
+          ScaleQuantumToMap(GetPixelBlack(image,q))),q);
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (clut_image->matte == MagickFalse)
+            SetPixelAlpha(image,GetPixelInfoIntensity(clut_map+
+              ScaleQuantumToMap((Quantum) GetPixelAlpha(image,q))),q);
+          else
+            if (image->matte == MagickFalse)
+              SetPixelAlpha(image,ClampAlphaPixelComponent(clut_map+
+                ScaleQuantumToMap((Quantum) GetPixelInfoIntensity(&pixel))),q);
+            else
+              SetPixelAlpha(image,ClampAlphaPixelComponent(clut_map+
+                ScaleQuantumToMap(GetPixelAlpha(image,q))),q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ClutImageChannel)
+#endif
+        proceed=SetImageProgress(image,ClutImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  clut_map=(PixelInfo *) RelinquishMagickMemory(clut_map);
+  if ((clut_image->matte != MagickFalse) && ((channel & OpacityChannel) != 0))
+    (void) SetImageAlphaChannel(image,ActivateAlphaChannel);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o n t r a s t I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ContrastImage() enhances the intensity differences between the lighter and
+%  darker elements of the image.  Set sharpen to a MagickTrue to increase the
+%  image contrast otherwise the contrast is reduced.
+%
+%  The format of the ContrastImage method is:
+%
+%      MagickBooleanType ContrastImage(Image *image,
+%        const MagickBooleanType sharpen)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o sharpen: Increase or decrease image contrast.
+%
+*/
+
+static void Contrast(const int sign,Quantum *red,Quantum *green,Quantum *blue)
+{
+  double
+    brightness,
+    hue,
+    saturation;
+
+  /*
+    Enhance contrast: dark color become darker, light color become lighter.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  hue=0.0;
+  saturation=0.0;
+  brightness=0.0;
+  ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
+  brightness+=0.5*sign*(0.5*(sin((double) (MagickPI*(brightness-0.5)))+1.0)-
+    brightness);
+  if (brightness > 1.0)
+    brightness=1.0;
+  else
+    if (brightness < 0.0)
+      brightness=0.0;
+  ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
+}
+
+MagickExport MagickBooleanType ContrastImage(Image *image,
+  const MagickBooleanType sharpen)
+{
+#define ContrastImageTag  "Contrast/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  int
+    sign;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  sign=sharpen != MagickFalse ? 1 : -1;
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Contrast enhance colormap.
+      */
+      for (i=0; i < (ssize_t) image->colors; i++)
+        Contrast(sign,&image->colormap[i].red,&image->colormap[i].green,
+          &image->colormap[i].blue);
+    }
+  /*
+    Contrast enhance image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    Quantum
+      blue,
+      green,
+      red;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      red=GetPixelRed(image,q);
+      green=GetPixelGreen(image,q);
+      blue=GetPixelBlue(image,q);
+      Contrast(sign,&red,&green,&blue);
+      SetPixelRed(image,red,q);
+      SetPixelGreen(image,green,q);
+      SetPixelBlue(image,blue,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ContrastImage)
+#endif
+        proceed=SetImageProgress(image,ContrastImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o n t r a s t S t r e t c h I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The ContrastStretchImage() is a simple image enhancement technique that
+%  attempts to improve the contrast in an image by `stretching' the range of
+%  intensity values it contains to span a desired range of values. It differs
+%  from the more sophisticated histogram equalization in that it can only
+%  apply %  a linear scaling function to the image pixel values.  As a result
+%  the `enhancement' is less harsh.
+%
+%  The format of the ContrastStretchImage method is:
+%
+%      MagickBooleanType ContrastStretchImage(Image *image,
+%        const char *levels)
+%      MagickBooleanType ContrastStretchImageChannel(Image *image,
+%        const size_t channel,const double black_point,
+%        const double white_point)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o black_point: the black point.
+%
+%    o white_point: the white point.
+%
+%    o levels: Specify the levels where the black and white points have the
+%      range of 0 to number-of-pixels (e.g. 1%, 10x90%, etc.).
+%
+*/
+
+MagickExport MagickBooleanType ContrastStretchImage(Image *image,
+  const char *levels)
+{
+  double
+    black_point,
+    white_point;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  MagickStatusType
+    flags;
+
+  /*
+    Parse levels.
+  */
+  if (levels == (char *) NULL)
+    return(MagickFalse);
+  flags=ParseGeometry(levels,&geometry_info);
+  black_point=geometry_info.rho;
+  white_point=(double) image->columns*image->rows;
+  if ((flags & SigmaValue) != 0)
+    white_point=geometry_info.sigma;
+  if ((flags & PercentValue) != 0)
+    {
+      black_point*=(double) QuantumRange/100.0;
+      white_point*=(double) QuantumRange/100.0;
+    }
+  if ((flags & SigmaValue) == 0)
+    white_point=(double) image->columns*image->rows-black_point;
+  status=ContrastStretchImageChannel(image,DefaultChannels,black_point,
+    white_point);
+  return(status);
+}
+
+MagickExport MagickBooleanType ContrastStretchImageChannel(Image *image,
+  const ChannelType channel,const double black_point,const double white_point)
+{
+#define MaxRange(color)  ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
+#define ContrastStretchImageTag  "ContrastStretch/Image"
+
+  CacheView
+    *image_view;
+
+  double
+    intensity;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    black,
+    *histogram,
+    *stretch_map,
+    white;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate histogram and stretch map.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  histogram=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*histogram));
+  stretch_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*stretch_map));
+  if ((histogram == (PixelInfo *) NULL) ||
+      (stretch_map == (PixelInfo *) NULL))
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  /*
+    Form histogram.
+  */
+  status=MagickTrue;
+  exception=(&image->exception);
+  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    if (channel == DefaultChannels)
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        Quantum
+          intensity;
+
+        intensity=GetPixelIntensity(image,p);
+        histogram[ScaleQuantumToMap(intensity)].red++;
+        histogram[ScaleQuantumToMap(intensity)].green++;
+        histogram[ScaleQuantumToMap(intensity)].blue++;
+        histogram[ScaleQuantumToMap(intensity)].black++;
+        p+=GetPixelChannels(image);
+      }
+    else
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        if ((channel & RedChannel) != 0)
+          histogram[ScaleQuantumToMap(GetPixelRed(image,p))].red++;
+        if ((channel & GreenChannel) != 0)
+          histogram[ScaleQuantumToMap(GetPixelGreen(image,p))].green++;
+        if ((channel & BlueChannel) != 0)
+          histogram[ScaleQuantumToMap(GetPixelBlue(image,p))].blue++;
+        if (((channel & BlackChannel) != 0) &&
+            (image->colorspace == CMYKColorspace))
+          histogram[ScaleQuantumToMap(GetPixelBlack(image,p))].black++;
+        if ((channel & OpacityChannel) != 0)
+          histogram[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha++;
+        p+=GetPixelChannels(image);
+      }
+  }
+  /*
+    Find the histogram boundaries by locating the black/white levels.
+  */
+  black.red=0.0;
+  white.red=MaxRange(QuantumRange);
+  if ((channel & RedChannel) != 0)
+    {
+      intensity=0.0;
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        intensity+=histogram[i].red;
+        if (intensity > black_point)
+          break;
+      }
+      black.red=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(ssize_t) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].red;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.red=(MagickRealType) i;
+    }
+  black.green=0.0;
+  white.green=MaxRange(QuantumRange);
+  if ((channel & GreenChannel) != 0)
+    {
+      intensity=0.0;
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        intensity+=histogram[i].green;
+        if (intensity > black_point)
+          break;
+      }
+      black.green=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(ssize_t) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].green;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.green=(MagickRealType) i;
+    }
+  black.blue=0.0;
+  white.blue=MaxRange(QuantumRange);
+  if ((channel & BlueChannel) != 0)
+    {
+      intensity=0.0;
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        intensity+=histogram[i].blue;
+        if (intensity > black_point)
+          break;
+      }
+      black.blue=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(ssize_t) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].blue;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.blue=(MagickRealType) i;
+    }
+  black.alpha=0.0;
+  white.alpha=MaxRange(QuantumRange);
+  if ((channel & OpacityChannel) != 0)
+    {
+      intensity=0.0;
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        intensity+=histogram[i].alpha;
+        if (intensity > black_point)
+          break;
+      }
+      black.alpha=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(ssize_t) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].alpha;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.alpha=(MagickRealType) i;
+    }
+  black.black=0.0;
+  white.black=MaxRange(QuantumRange);
+  if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
+    {
+      intensity=0.0;
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        intensity+=histogram[i].black;
+        if (intensity > black_point)
+          break;
+      }
+      black.black=(MagickRealType) i;
+      intensity=0.0;
+      for (i=(ssize_t) MaxMap; i != 0; i--)
+      {
+        intensity+=histogram[i].black;
+        if (intensity > ((double) image->columns*image->rows-white_point))
+          break;
+      }
+      white.black=(MagickRealType) i;
+    }
+  histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
+  /*
+    Stretch the histogram to create the stretched image mapping.
+  */
+  (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map));
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    if ((channel & RedChannel) != 0)
+      {
+        if (i < (ssize_t) black.red)
+          stretch_map[i].red=0.0;
+        else
+          if (i > (ssize_t) white.red)
+            stretch_map[i].red=(MagickRealType) QuantumRange;
+          else
+            if (black.red != white.red)
+              stretch_map[i].red=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.red)/(white.red-black.red)));
+      }
+    if ((channel & GreenChannel) != 0)
+      {
+        if (i < (ssize_t) black.green)
+          stretch_map[i].green=0.0;
+        else
+          if (i > (ssize_t) white.green)
+            stretch_map[i].green=(MagickRealType) QuantumRange;
+          else
+            if (black.green != white.green)
+              stretch_map[i].green=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.green)/(white.green-
+                black.green)));
+      }
+    if ((channel & BlueChannel) != 0)
+      {
+        if (i < (ssize_t) black.blue)
+          stretch_map[i].blue=0.0;
+        else
+          if (i > (ssize_t) white.blue)
+            stretch_map[i].blue=(MagickRealType) QuantumRange;
+          else
+            if (black.blue != white.blue)
+              stretch_map[i].blue=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.blue)/(white.blue-
+                black.blue)));
+      }
+    if ((channel & OpacityChannel) != 0)
+      {
+        if (i < (ssize_t) black.alpha)
+          stretch_map[i].alpha=0.0;
+        else
+          if (i > (ssize_t) white.alpha)
+            stretch_map[i].alpha=(MagickRealType) QuantumRange;
+          else
+            if (black.alpha != white.alpha)
+              stretch_map[i].alpha=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.alpha)/(white.alpha-
+                black.alpha)));
+      }
+    if (((channel & BlackChannel) != 0) &&
+        (image->colorspace == CMYKColorspace))
+      {
+        if (i < (ssize_t) black.black)
+          stretch_map[i].black=0.0;
+        else
+          if (i > (ssize_t) white.black)
+            stretch_map[i].black=(MagickRealType) QuantumRange;
+          else
+            if (black.black != white.black)
+              stretch_map[i].black=(MagickRealType) ScaleMapToQuantum(
+                (MagickRealType) (MaxMap*(i-black.black)/(white.black-
+                black.black)));
+      }
+  }
+  /*
+    Stretch the image.
+  */
+  if (((channel & OpacityChannel) != 0) || (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace)))
+    image->storage_class=DirectClass;
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Stretch colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if ((channel & RedChannel) != 0)
+          {
+            if (black.red != white.red)
+              image->colormap[i].red=ClampToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].red)].red);
+          }
+        if ((channel & GreenChannel) != 0)
+          {
+            if (black.green != white.green)
+              image->colormap[i].green=ClampToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].green)].green);
+          }
+        if ((channel & BlueChannel) != 0)
+          {
+            if (black.blue != white.blue)
+              image->colormap[i].blue=ClampToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].blue)].blue);
+          }
+        if ((channel & OpacityChannel) != 0)
+          {
+            if (black.alpha != white.alpha)
+              image->colormap[i].alpha=ClampToQuantum(stretch_map[
+                ScaleQuantumToMap(image->colormap[i].alpha)].alpha);
+          }
+      }
+    }
+  /*
+    Stretch image.
+  */
+  status=MagickTrue;
+  progress=0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          if (black.red != white.red)
+            SetPixelRed(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
+              GetPixelRed(image,q))].red),q);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          if (black.green != white.green)
+            SetPixelGreen(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
+              GetPixelGreen(image,q))].green),q);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          if (black.blue != white.blue)
+            SetPixelBlue(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
+              GetPixelBlue(image,q))].blue),q);
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          if (black.black != white.black)
+            SetPixelBlack(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
+              GetPixelBlack(image,q))].black),q);
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          if (black.alpha != white.alpha)
+            SetPixelAlpha(image,ClampToQuantum(stretch_map[ScaleQuantumToMap(
+              GetPixelAlpha(image,q))].alpha),q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ContrastStretchImageChannel)
+#endif
+        proceed=SetImageProgress(image,ContrastStretchImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  stretch_map=(PixelInfo *) RelinquishMagickMemory(stretch_map);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     E n h a n c e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EnhanceImage() applies a digital filter that improves the quality of a
+%  noisy image.
+%
+%  The format of the EnhanceImage method is:
+%
+%      Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *EnhanceImage(const Image *image,ExceptionInfo *exception)
+{
+#define Enhance(weight) \
+  mean=((MagickRealType) GetPixelRed(image,r)+pixel.red)/2; \
+  distance=(MagickRealType) GetPixelRed(image,r)-(MagickRealType) pixel.red; \
+  distance_squared=QuantumScale*(2.0*((MagickRealType) QuantumRange+1.0)+ \
+     mean)*distance*distance; \
+  mean=((MagickRealType) GetPixelGreen(image,r)+pixel.green)/2; \
+  distance=(MagickRealType) GetPixelGreen(image,r)- \
+    (MagickRealType) pixel.green; \
+  distance_squared+=4.0*distance*distance; \
+  mean=((MagickRealType) GetPixelBlue(image,r)+pixel.blue)/2; \
+  distance=(MagickRealType) GetPixelBlue(image,r)- \
+    (MagickRealType) pixel.blue; \
+  distance_squared+=QuantumScale*(3.0*((MagickRealType) \
+    QuantumRange+1.0)-1.0-mean)*distance*distance; \
+  mean=((MagickRealType) GetPixelAlpha(image,r)+pixel.alpha)/2; \
+  distance=(MagickRealType) GetPixelAlpha(image,r)-(MagickRealType) pixel.alpha; \
+  distance_squared+=QuantumScale*(3.0*((MagickRealType) \
+    QuantumRange+1.0)-1.0-mean)*distance*distance; \
+  if (distance_squared < ((MagickRealType) QuantumRange*(MagickRealType) \
+      QuantumRange/25.0f)) \
+    { \
+      aggregate.red+=(weight)*GetPixelRed(image,r); \
+      aggregate.green+=(weight)*GetPixelGreen(image,r); \
+      aggregate.blue+=(weight)*GetPixelBlue(image,r); \
+      aggregate.alpha+=(weight)*GetPixelAlpha(image,r); \
+      total_weight+=(weight); \
+    } \
+  r++;
+#define EnhanceImageTag  "Enhance/Image"
+
+  CacheView
+    *enhance_view,
+    *image_view;
+
+  Image
+    *enhance_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize enhanced image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((image->columns < 5) || (image->rows < 5))
+    return((Image *) NULL);
+  enhance_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (enhance_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(enhance_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&enhance_image->exception);
+      enhance_image=DestroyImage(enhance_image);
+      return((Image *) NULL);
+    }
+  /*
+    Enhance image.
+  */
+  status=MagickTrue;
+  progress=0;
+  (void) ResetMagickMemory(&zero,0,sizeof(zero));
+  image_view=AcquireCacheView(image);
+  enhance_view=AcquireCacheView(enhance_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    /*
+      Read another scan line.
+    */
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-2,y-2,image->columns+4,5,exception);
+    q=QueueCacheViewAuthenticPixels(enhance_view,0,y,enhance_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        aggregate;
+
+      MagickRealType
+        distance,
+        distance_squared,
+        mean,
+        total_weight;
+
+      PixelPacket
+        pixel;
+
+      register const Quantum
+        *restrict r;
+
+      /*
+        Compute weighted average of target pixel color components.
+      */
+      aggregate=zero;
+      total_weight=0.0;
+      r=p+2*(image->columns+4)+2;
+      GetPixelPacket(image,r,&pixel);
+      r=p;
+      Enhance(5.0); Enhance(8.0); Enhance(10.0); Enhance(8.0); Enhance(5.0);
+      r=p+(image->columns+4);
+      Enhance(8.0); Enhance(20.0); Enhance(40.0); Enhance(20.0); Enhance(8.0);
+      r=p+2*(image->columns+4);
+      Enhance(10.0); Enhance(40.0); Enhance(80.0); Enhance(40.0); Enhance(10.0);
+      r=p+3*(image->columns+4);
+      Enhance(8.0); Enhance(20.0); Enhance(40.0); Enhance(20.0); Enhance(8.0);
+      r=p+4*(image->columns+4);
+      Enhance(5.0); Enhance(8.0); Enhance(10.0); Enhance(8.0); Enhance(5.0);
+      SetPixelRed(enhance_image,(Quantum) ((aggregate.red+
+        (total_weight/2)-1)/total_weight),q);
+      SetPixelGreen(enhance_image,(Quantum) ((aggregate.green+
+        (total_weight/2)-1)/total_weight),q);
+      SetPixelBlue(enhance_image,(Quantum) ((aggregate.blue+
+        (total_weight/2)-1)/total_weight),q);
+      SetPixelAlpha(enhance_image,(Quantum) ((aggregate.alpha+
+        (total_weight/2)-1)/total_weight),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(enhance_image);
+    }
+    if (SyncCacheViewAuthenticPixels(enhance_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_EnhanceImage)
+#endif
+        proceed=SetImageProgress(image,EnhanceImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  enhance_view=DestroyCacheView(enhance_view);
+  image_view=DestroyCacheView(image_view);
+  return(enhance_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     E q u a l i z e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EqualizeImage() applies a histogram equalization to the image.
+%
+%  The format of the EqualizeImage method is:
+%
+%      MagickBooleanType EqualizeImage(Image *image)
+%      MagickBooleanType EqualizeImageChannel(Image *image,
+%        const ChannelType channel)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+*/
+
+MagickExport MagickBooleanType EqualizeImage(Image *image)
+{
+  return(EqualizeImageChannel(image,DefaultChannels));
+}
+
+MagickExport MagickBooleanType EqualizeImageChannel(Image *image,
+  const ChannelType channel)
+{
+#define EqualizeImageTag  "Equalize/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    black,
+    *equalize_map,
+    *histogram,
+    intensity,
+    *map,
+    white;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate and initialize histogram arrays.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  equalize_map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*equalize_map));
+  histogram=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*histogram));
+  map=(PixelInfo *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
+  if ((equalize_map == (PixelInfo *) NULL) ||
+      (histogram == (PixelInfo *) NULL) ||
+      (map == (PixelInfo *) NULL))
+    {
+      if (map != (PixelInfo *) NULL)
+        map=(PixelInfo *) RelinquishMagickMemory(map);
+      if (histogram != (PixelInfo *) NULL)
+        histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
+      if (equalize_map != (PixelInfo *) NULL)
+        equalize_map=(PixelInfo *) RelinquishMagickMemory(equalize_map);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  /*
+    Form histogram.
+  */
+  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
+  exception=(&image->exception);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        histogram[ScaleQuantumToMap(GetPixelRed(image,p))].red++;
+      if ((channel & GreenChannel) != 0)
+        histogram[ScaleQuantumToMap(GetPixelGreen(image,p))].green++;
+      if ((channel & BlueChannel) != 0)
+        histogram[ScaleQuantumToMap(GetPixelBlue(image,p))].blue++;
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        histogram[ScaleQuantumToMap(GetPixelBlack(image,p))].black++;
+      if ((channel & OpacityChannel) != 0)
+        histogram[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha++;
+      p+=GetPixelChannels(image);
+    }
+  }
+  /*
+    Integrate the histogram to get the equalization map.
+  */
+  (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    if ((channel & RedChannel) != 0)
+      intensity.red+=histogram[i].red;
+    if ((channel & GreenChannel) != 0)
+      intensity.green+=histogram[i].green;
+    if ((channel & BlueChannel) != 0)
+      intensity.blue+=histogram[i].blue;
+    if (((channel & BlackChannel) != 0) &&
+        (image->colorspace == CMYKColorspace))
+      intensity.black+=histogram[i].black;
+    if ((channel & OpacityChannel) != 0)
+      intensity.alpha+=histogram[i].alpha;
+    map[i]=intensity;
+  }
+  black=map[0];
+  white=map[(int) MaxMap];
+  (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map));
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    if (((channel & RedChannel) != 0) && (white.red != black.red))
+      equalize_map[i].red=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+        ((MaxMap*(map[i].red-black.red))/(white.red-black.red)));
+    if (((channel & GreenChannel) != 0) && (white.green != black.green))
+      equalize_map[i].green=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+        ((MaxMap*(map[i].green-black.green))/(white.green-black.green)));
+    if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
+      equalize_map[i].blue=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+        ((MaxMap*(map[i].blue-black.blue))/(white.blue-black.blue)));
+    if ((((channel & BlackChannel) != 0) &&
+        (image->colorspace == CMYKColorspace)) &&
+        (white.black != black.black))
+      equalize_map[i].black=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+        ((MaxMap*(map[i].black-black.black))/(white.black-black.black)));
+    if (((channel & OpacityChannel) != 0) && (white.alpha != black.alpha))
+      equalize_map[i].alpha=(MagickRealType) ScaleMapToQuantum(
+        (MagickRealType) ((MaxMap*(map[i].alpha-black.alpha))/
+        (white.alpha-black.alpha)));
+  }
+  histogram=(PixelInfo *) RelinquishMagickMemory(histogram);
+  map=(PixelInfo *) RelinquishMagickMemory(map);
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Equalize colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if (((channel & RedChannel) != 0) && (white.red != black.red))
+          image->colormap[i].red=ClampToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].red)].red);
+        if (((channel & GreenChannel) != 0) && (white.green != black.green))
+          image->colormap[i].green=ClampToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].green)].green);
+        if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
+          image->colormap[i].blue=ClampToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].blue)].blue);
+        if (((channel & OpacityChannel) != 0) &&
+            (white.alpha != black.alpha))
+          image->colormap[i].alpha=ClampToQuantum(equalize_map[
+            ScaleQuantumToMap(image->colormap[i].alpha)].alpha);
+      }
+    }
+  /*
+    Equalize image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (((channel & RedChannel) != 0) && (white.red != black.red))
+        SetPixelRed(image,ClampToQuantum(equalize_map[
+          ScaleQuantumToMap(GetPixelRed(image,q))].red),q);
+      if (((channel & GreenChannel) != 0) && (white.green != black.green))
+        SetPixelGreen(image,ClampToQuantum(equalize_map[
+          ScaleQuantumToMap(GetPixelGreen(image,q))].green),q);
+      if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
+        SetPixelBlue(image,ClampToQuantum(equalize_map[
+          ScaleQuantumToMap(GetPixelBlue(image,q))].blue),q);
+      if ((((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace)) &&
+          (white.black != black.black))
+        SetPixelBlack(image,ClampToQuantum(equalize_map[
+          ScaleQuantumToMap(GetPixelBlack(image,q))].black),q);
+      if (((channel & OpacityChannel) != 0) && (white.alpha != black.alpha))
+        SetPixelAlpha(image,ClampToQuantum(equalize_map[
+          ScaleQuantumToMap(GetPixelAlpha(image,q))].alpha),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_EqualizeImageChannel)
+#endif
+        proceed=SetImageProgress(image,EqualizeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  equalize_map=(PixelInfo *) RelinquishMagickMemory(equalize_map);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     G a m m a I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GammaImage() gamma-corrects a particular image channel.  The same
+%  image viewed on different devices will have perceptual differences in the
+%  way the image's intensities are represented on the screen.  Specify
+%  individual gamma levels for the red, green, and blue channels, or adjust
+%  all three with the gamma parameter.  Values typically range from 0.8 to 2.3.
+%
+%  You can also reduce the influence of a particular channel with a gamma
+%  value of 0.
+%
+%  The format of the GammaImage method is:
+%
+%      MagickBooleanType GammaImage(Image *image,const char *level)
+%      MagickBooleanType GammaImageChannel(Image *image,
+%        const ChannelType channel,const double gamma)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o level: the image gamma as a string (e.g. 1.6,1.2,1.0).
+%
+%    o gamma: the image gamma.
+%
+*/
+MagickExport MagickBooleanType GammaImage(Image *image,const char *level)
+{
+  GeometryInfo
+    geometry_info;
+
+  PixelInfo
+    gamma;
+
+  MagickStatusType
+    flags,
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (level == (char *) NULL)
+    return(MagickFalse);
+  flags=ParseGeometry(level,&geometry_info);
+  gamma.red=geometry_info.rho;
+  gamma.green=geometry_info.sigma;
+  if ((flags & SigmaValue) == 0)
+    gamma.green=gamma.red;
+  gamma.blue=geometry_info.xi;
+  if ((flags & XiValue) == 0)
+    gamma.blue=gamma.red;
+  if ((gamma.red == 1.0) && (gamma.green == 1.0) && (gamma.blue == 1.0))
+    return(MagickTrue);
+  if ((gamma.red == gamma.green) && (gamma.green == gamma.blue))
+    status=GammaImageChannel(image,(const ChannelType) (RedChannel |
+      GreenChannel | BlueChannel),(double) gamma.red);
+  else
+    {
+      status=GammaImageChannel(image,RedChannel,(double) gamma.red);
+      status|=GammaImageChannel(image,GreenChannel,(double) gamma.green);
+      status|=GammaImageChannel(image,BlueChannel,(double) gamma.blue);
+    }
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+MagickExport MagickBooleanType GammaImageChannel(Image *image,
+  const ChannelType channel,const double gamma)
+{
+#define GammaCorrectImageTag  "GammaCorrect/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  Quantum
+    *gamma_map;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate and initialize gamma maps.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (gamma == 1.0)
+    return(MagickTrue);
+  gamma_map=(Quantum *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*gamma_map));
+  if (gamma_map == (Quantum *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  (void) ResetMagickMemory(gamma_map,0,(MaxMap+1)*sizeof(*gamma_map));
+  if (gamma != 0.0)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+    for (i=0; i <= (ssize_t) MaxMap; i++)
+      gamma_map[i]=ClampToQuantum((MagickRealType) ScaleMapToQuantum((
+        MagickRealType) (MaxMap*pow((double) i/MaxMap,1.0/gamma))));
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Gamma-correct colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if ((channel & RedChannel) != 0)
+          image->colormap[i].red=gamma_map[
+            ScaleQuantumToMap(image->colormap[i].red)];
+        if ((channel & GreenChannel) != 0)
+          image->colormap[i].green=gamma_map[
+            ScaleQuantumToMap(image->colormap[i].green)];
+        if ((channel & BlueChannel) != 0)
+          image->colormap[i].blue=gamma_map[
+            ScaleQuantumToMap(image->colormap[i].blue)];
+        if ((channel & OpacityChannel) != 0)
+          image->colormap[i].alpha=gamma_map[
+            ScaleQuantumToMap(image->colormap[i].alpha)];
+      }
+    }
+  /*
+    Gamma-correct image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (channel == DefaultChannels)
+        {
+          SetPixelRed(image,gamma_map[
+            ScaleQuantumToMap(GetPixelRed(image,q))],q);
+          SetPixelGreen(image,gamma_map[
+            ScaleQuantumToMap(GetPixelGreen(image,q))],q);
+          SetPixelBlue(image,gamma_map[ScaleQuantumToMap(
+            GetPixelBlue(image,q))],q);
+        }
+      else
+        {
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(image,gamma_map[ScaleQuantumToMap(
+              GetPixelRed(image,q))],q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(image,gamma_map[
+              ScaleQuantumToMap(GetPixelGreen(image,q))],q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(image,gamma_map[
+              ScaleQuantumToMap(GetPixelBlue(image,q))],q);
+          if ((channel & OpacityChannel) != 0)
+            {
+              if (image->matte == MagickFalse)
+                SetPixelAlpha(image,gamma_map[
+                  ScaleQuantumToMap(GetPixelAlpha(image,q))],q);
+              else
+                SetPixelAlpha(image,gamma_map[
+                  ScaleQuantumToMap(GetPixelAlpha(image,q))],q);
+            }
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (((channel & BlackChannel) != 0) &&
+        (image->colorspace == CMYKColorspace))
+      for (x=0; x < (ssize_t) image->columns; x++)
+        SetPixelBlack(image,gamma_map[ScaleQuantumToMap(
+          GetPixelBlack(image,q))],q);
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GammaImageChannel)
+#endif
+        proceed=SetImageProgress(image,GammaCorrectImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  gamma_map=(Quantum *) RelinquishMagickMemory(gamma_map);
+  if (image->gamma != 0.0)
+    image->gamma*=gamma;
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     H a l d C l u t I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  HaldClutImage() applies a Hald color lookup table to the image.  A Hald
+%  color lookup table is a 3-dimensional color cube mapped to 2 dimensions.
+%  Create it with the HALD coder.  You can apply any color transformation to
+%  the Hald image and then use this method to apply the transform to the
+%  image.
+%
+%  The format of the HaldClutImage method is:
+%
+%      MagickBooleanType HaldClutImage(Image *image,Image *hald_image)
+%      MagickBooleanType HaldClutImageChannel(Image *image,
+%        const ChannelType channel,Image *hald_image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image, which is replaced by indexed CLUT values
+%
+%    o hald_image: the color lookup table image for replacement color values.
+%
+%    o channel: the channel.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType HaldClutImage(Image *image,
+  const Image *hald_image)
+{
+  return(HaldClutImageChannel(image,DefaultChannels,hald_image));
+}
+
+MagickExport MagickBooleanType HaldClutImageChannel(Image *image,
+  const ChannelType channel,const Image *hald_image)
+{
+#define HaldClutImageTag  "Clut/Image"
+
+  typedef struct _HaldInfo
+  {
+    MagickRealType
+      x,
+      y,
+      z;
+  } HaldInfo;
+
+  CacheView
+    *hald_view,
+    *image_view;
+
+  double
+    width;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  size_t
+    cube_size,
+    length,
+    level;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(hald_image != (Image *) NULL);
+  assert(hald_image->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  /*
+    Hald clut image.
+  */
+  status=MagickTrue;
+  progress=0;
+  length=MagickMin(hald_image->columns,hald_image->rows);
+  for (level=2; (level*level*level) < length; level++) ;
+  level*=level;
+  cube_size=level*level;
+  width=(double) hald_image->columns;
+  GetPixelInfo(hald_image,&zero);
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  hald_view=AcquireCacheView(hald_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      offset;
+
+    HaldInfo
+      point;
+
+    PixelInfo
+      pixel,
+      pixel1,
+      pixel2,
+      pixel3,
+      pixel4;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    pixel1=zero;
+    pixel2=zero;
+    pixel3=zero;
+    pixel4=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      point.x=QuantumScale*(level-1.0)*GetPixelRed(image,q);
+      point.y=QuantumScale*(level-1.0)*GetPixelGreen(image,q);
+      point.z=QuantumScale*(level-1.0)*GetPixelBlue(image,q);
+      offset=point.x+level*floor(point.y)+cube_size*floor(point.z);
+      point.x-=floor(point.x);
+      point.y-=floor(point.y);
+      point.z-=floor(point.z);
+      (void) InterpolatePixelInfo(image,hald_view,
+        UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
+        &pixel1,exception);
+      (void) InterpolatePixelInfo(image,hald_view,
+        UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
+        width),&pixel2,exception);
+      CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,
+        pixel2.alpha,point.y,&pixel3);
+      offset+=cube_size;
+      (void) InterpolatePixelInfo(image,hald_view,
+        UndefinedInterpolatePixel,fmod(offset,width),floor(offset/width),
+        &pixel1,exception);
+      (void) InterpolatePixelInfo(image,hald_view,
+        UndefinedInterpolatePixel,fmod(offset+level,width),floor((offset+level)/
+        width),&pixel2,exception);
+      CompositePixelInfoAreaBlend(&pixel1,pixel1.alpha,&pixel2,
+        pixel2.alpha,point.y,&pixel4);
+      CompositePixelInfoAreaBlend(&pixel3,pixel3.alpha,&pixel4,
+        pixel4.alpha,point.z,&pixel);
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,
+          ClampToQuantum(pixel.red),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,
+          ClampToQuantum(pixel.green),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,
+          ClampToQuantum(pixel.blue),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,
+          ClampToQuantum(pixel.black),q);
+      if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
+        SetPixelAlpha(image,
+          ClampToQuantum(pixel.alpha),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_HaldClutImageChannel)
+#endif
+        proceed=SetImageProgress(image,HaldClutImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  hald_view=DestroyCacheView(hald_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L e v e l I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LevelImage() adjusts the levels of a particular image channel by
+%  scaling the colors falling between specified white and black points to
+%  the full available quantum range.
+%
+%  The parameters provided represent the black, and white points.  The black
+%  point specifies the darkest color in the image. Colors darker than the
+%  black point are set to zero.  White point specifies the lightest color in
+%  the image.  Colors brighter than the white point are set to the maximum
+%  quantum value.
+%
+%  If a '!' flag is given, map black and white colors to the given levels
+%  rather than mapping those levels to black and white.  See
+%  LevelizeImageChannel() and LevelizeImageChannel(), below.
+%
+%  Gamma specifies a gamma correction to apply to the image.
+%
+%  The format of the LevelImage method is:
+%
+%      MagickBooleanType LevelImage(Image *image,const char *levels)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o levels: Specify the levels where the black and white points have the
+%      range of 0-QuantumRange, and gamma has the range 0-10 (e.g. 10x90%+2).
+%      A '!' flag inverts the re-mapping.
+%
+*/
+
+MagickExport MagickBooleanType LevelImage(Image *image,const char *levels)
+{
+  double
+    black_point,
+    gamma,
+    white_point;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  MagickStatusType
+    flags;
+
+  /*
+    Parse levels.
+  */
+  if (levels == (char *) NULL)
+    return(MagickFalse);
+  flags=ParseGeometry(levels,&geometry_info);
+  black_point=geometry_info.rho;
+  white_point=(double) QuantumRange;
+  if ((flags & SigmaValue) != 0)
+    white_point=geometry_info.sigma;
+  gamma=1.0;
+  if ((flags & XiValue) != 0)
+    gamma=geometry_info.xi;
+  if ((flags & PercentValue) != 0)
+    {
+      black_point*=(double) image->columns*image->rows/100.0;
+      white_point*=(double) image->columns*image->rows/100.0;
+    }
+  if ((flags & SigmaValue) == 0)
+    white_point=(double) QuantumRange-black_point;
+  if ((flags & AspectValue ) == 0)
+    status=LevelImageChannel(image,DefaultChannels,black_point,white_point,
+      gamma);
+  else
+    status=LevelizeImage(image,black_point,white_point,gamma);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L e v e l i z e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LevelizeImage() applies the normal level operation to the image, spreading
+%  out the values between the black and white points over the entire range of
+%  values.  Gamma correction is also applied after the values has been mapped.
+%
+%  It is typically used to improve image contrast, or to provide a controlled
+%  linear threshold for the image. If the black and white points are set to
+%  the minimum and maximum values found in the image, the image can be
+%  normalized.  or by swapping black and white values, negate the image.
+%
+%  The format of the LevelizeImage method is:
+%
+%      MagickBooleanType LevelizeImage(Image *image,const double black_point,
+%        const double white_point,const double gamma)
+%      MagickBooleanType LevelizeImageChannel(Image *image,
+%        const ChannelType channel,const double black_point,
+%        const double white_point,const double gamma)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o black_point: The level which is to be mapped to zero (black)
+%
+%    o white_point: The level which is to be mapped to QuantiumRange (white)
+%
+%    o gamma: adjust gamma by this factor before mapping values.
+%             use 1.0 for purely linear stretching of image color values
+%
+*/
+MagickExport MagickBooleanType LevelImageChannel(Image *image,
+  const ChannelType channel,const double black_point,const double white_point,
+  const double gamma)
+{
+#define LevelImageTag  "Level/Image"
+#define LevelQuantum(x) (ClampToQuantum((MagickRealType) QuantumRange* \
+  pow(scale*((double) (x)-black_point),1.0/gamma)))
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register double
+    scale;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate and initialize levels map.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  scale=(white_point != black_point) ? 1.0/(white_point-black_point) : 1.0;
+  if (image->storage_class == PseudoClass)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (i=0; i < (ssize_t) image->colors; i++)
+    {
+      /*
+        Level colormap.
+      */
+      if ((channel & RedChannel) != 0)
+        image->colormap[i].red=LevelQuantum(image->colormap[i].red);
+      if ((channel & GreenChannel) != 0)
+        image->colormap[i].green=LevelQuantum(image->colormap[i].green);
+      if ((channel & BlueChannel) != 0)
+        image->colormap[i].blue=LevelQuantum(image->colormap[i].blue);
+      if ((channel & OpacityChannel) != 0)
+        image->colormap[i].alpha=LevelQuantum(image->colormap[i].alpha);
+      }
+  /*
+    Level image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,LevelQuantum(
+          GetPixelRed(image,q)),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,
+          LevelQuantum(GetPixelGreen(image,q)),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,
+          LevelQuantum(GetPixelBlue(image,q)),q);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        SetPixelAlpha(image,
+          LevelQuantum(GetPixelAlpha(image,q)),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,
+          LevelQuantum(GetPixelBlack(image,q)),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_LevelImageChannel)
+#endif
+        proceed=SetImageProgress(image,LevelImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L e v e l i z e I m a g e C h a n n e l                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LevelizeImageChannel() applies the reversed LevelImage() operation to just
+%  the specific channels specified.  It compresses the full range of color
+%  values, so that they lie between the given black and white points. Gamma is
+%  applied before the values are mapped.
+%
+%  LevelizeImageChannel() can be called with by using a +level command line
+%  API option, or using a '!' on a -level or LevelImage() geometry string.
+%
+%  It can be used for example de-contrast a greyscale image to the exact
+%  levels specified.  Or by using specific levels for each channel of an image
+%  you can convert a gray-scale image to any linear color gradient, according
+%  to those levels.
+%
+%  The format of the LevelizeImageChannel method is:
+%
+%      MagickBooleanType LevelizeImageChannel(Image *image,
+%        const ChannelType channel,const char *levels)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o black_point: The level to map zero (black) to.
+%
+%    o white_point: The level to map QuantiumRange (white) to.
+%
+%    o gamma: adjust gamma by this factor before mapping values.
+%
+*/
+
+MagickExport MagickBooleanType LevelizeImage(Image *image,
+  const double black_point,const double white_point,const double gamma)
+{
+  MagickBooleanType
+    status;
+
+  status=LevelizeImageChannel(image,DefaultChannels,black_point,white_point,
+    gamma);
+  return(status);
+}
+
+MagickExport MagickBooleanType LevelizeImageChannel(Image *image,
+  const ChannelType channel,const double black_point,const double white_point,
+  const double gamma)
+{
+#define LevelizeImageTag  "Levelize/Image"
+#define LevelizeValue(x) (ClampToQuantum(((MagickRealType) \
+  pow((double)(QuantumScale*(x)),1.0/gamma))*(white_point-black_point)+ \
+  black_point))
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate and initialize levels map.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->storage_class == PseudoClass)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (i=0; i < (ssize_t) image->colors; i++)
+    {
+      /*
+        Level colormap.
+      */
+      if ((channel & RedChannel) != 0)
+        image->colormap[i].red=LevelizeValue(image->colormap[i].red);
+      if ((channel & GreenChannel) != 0)
+        image->colormap[i].green=LevelizeValue(image->colormap[i].green);
+      if ((channel & BlueChannel) != 0)
+        image->colormap[i].blue=LevelizeValue(image->colormap[i].blue);
+      if ((channel & OpacityChannel) != 0)
+        image->colormap[i].alpha=LevelizeValue(image->colormap[i].alpha);
+    }
+  /*
+    Level image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,LevelizeValue(GetPixelRed(image,q)),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,LevelizeValue(GetPixelGreen(image,q)),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,LevelizeValue(GetPixelBlue(image,q)),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,LevelizeValue(GetPixelBlack(image,q)),q);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        SetPixelAlpha(image,LevelizeValue(GetPixelAlpha(image,q)),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_LevelizeImageChannel)
+#endif
+        proceed=SetImageProgress(image,LevelizeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L e v e l I m a g e C o l o r s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LevelImageColor() maps the given color to "black" and "white" values,
+%  linearly spreading out the colors, and level values on a channel by channel
+%  bases, as per LevelImage().  The given colors allows you to specify
+%  different level ranges for each of the color channels separately.
+%
+%  If the boolean 'invert' is set true the image values will modifyed in the
+%  reverse direction. That is any existing "black" and "white" colors in the
+%  image will become the color values given, with all other values compressed
+%  appropriatally.  This effectivally maps a greyscale gradient into the given
+%  color gradient.
+%
+%  The format of the LevelColorsImageChannel method is:
+%
+%    MagickBooleanType LevelColorsImage(Image *image,
+%      const PixelInfo *black_color,
+%      const PixelInfo *white_color,const MagickBooleanType invert)
+%    MagickBooleanType LevelColorsImageChannel(Image *image,
+%      const ChannelType channel,const PixelInfo *black_color,
+%      const PixelInfo *white_color,const MagickBooleanType invert)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o black_color: The color to map black to/from
+%
+%    o white_point: The color to map white to/from
+%
+%    o invert: if true map the colors (levelize), rather than from (level)
+%
+*/
+
+MagickExport MagickBooleanType LevelColorsImage(Image *image,
+  const PixelInfo *black_color,const PixelInfo *white_color,
+  const MagickBooleanType invert)
+{
+  MagickBooleanType
+    status;
+
+  status=LevelColorsImageChannel(image,DefaultChannels,black_color,white_color,
+    invert);
+  return(status);
+}
+
+MagickExport MagickBooleanType LevelColorsImageChannel(Image *image,
+  const ChannelType channel,const PixelInfo *black_color,
+  const PixelInfo *white_color,const MagickBooleanType invert)
+{
+  MagickStatusType
+    status;
+
+  /*
+    Allocate and initialize levels map.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  status=MagickFalse;
+  if (invert == MagickFalse)
+    {
+      if ((channel & RedChannel) != 0)
+        status|=LevelImageChannel(image,RedChannel,
+          black_color->red,white_color->red,(double) 1.0);
+      if ((channel & GreenChannel) != 0)
+        status|=LevelImageChannel(image,GreenChannel,
+          black_color->green,white_color->green,(double) 1.0);
+      if ((channel & BlueChannel) != 0)
+        status|=LevelImageChannel(image,BlueChannel,
+          black_color->blue,white_color->blue,(double) 1.0);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        status|=LevelImageChannel(image,BlackChannel,
+          black_color->black,white_color->black,(double) 1.0);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        status|=LevelImageChannel(image,OpacityChannel,
+          black_color->alpha,white_color->alpha,(double) 1.0);
+    }
+  else
+    {
+      if ((channel & RedChannel) != 0)
+        status|=LevelizeImageChannel(image,RedChannel,
+          black_color->red,white_color->red,(double) 1.0);
+      if ((channel & GreenChannel) != 0)
+        status|=LevelizeImageChannel(image,GreenChannel,
+          black_color->green,white_color->green,(double) 1.0);
+      if ((channel & BlueChannel) != 0)
+        status|=LevelizeImageChannel(image,BlueChannel,
+          black_color->blue,white_color->blue,(double) 1.0);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        status|=LevelizeImageChannel(image,BlackChannel,
+          black_color->black,white_color->black,(double) 1.0);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        status|=LevelizeImageChannel(image,OpacityChannel,
+          black_color->alpha,white_color->alpha,(double) 1.0);
+    }
+  return(status == 0 ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     L i n e a r S t r e t c h I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The LinearStretchImage() discards any pixels below the black point and
+%  above the white point and levels the remaining pixels.
+%
+%  The format of the LinearStretchImage method is:
+%
+%      MagickBooleanType LinearStretchImage(Image *image,
+%        const double black_point,const double white_point)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o black_point: the black point.
+%
+%    o white_point: the white point.
+%
+*/
+MagickExport MagickBooleanType LinearStretchImage(Image *image,
+  const double black_point,const double white_point)
+{
+#define LinearStretchImageTag  "LinearStretch/Image"
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    *histogram,
+    intensity;
+
+  ssize_t
+    black,
+    white,
+    y;
+
+  /*
+    Allocate histogram and linear map.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  histogram=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*histogram));
+  if (histogram == (MagickRealType *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  /*
+    Form histogram.
+  */
+  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
+  exception=(&image->exception);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=(ssize_t) image->columns-1; x >= 0; x--)
+    {
+      histogram[ScaleQuantumToMap(GetPixelIntensity(image,p))]++;
+      p+=GetPixelChannels(image);
+    }
+  }
+  /*
+    Find the histogram boundaries by locating the black and white point levels.
+  */
+  intensity=0.0;
+  for (black=0; black < (ssize_t) MaxMap; black++)
+  {
+    intensity+=histogram[black];
+    if (intensity >= black_point)
+      break;
+  }
+  intensity=0.0;
+  for (white=(ssize_t) MaxMap; white != 0; white--)
+  {
+    intensity+=histogram[white];
+    if (intensity >= white_point)
+      break;
+  }
+  histogram=(MagickRealType *) RelinquishMagickMemory(histogram);
+  status=LevelImageChannel(image,DefaultChannels,(double) black,(double) white,
+    1.0);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M o d u l a t e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ModulateImage() lets you control the brightness, saturation, and hue
+%  of an image.  Modulate represents the brightness, saturation, and hue
+%  as one parameter (e.g. 90,150,100).  If the image colorspace is HSL, the
+%  modulation is lightness, saturation, and hue.  And if the colorspace is
+%  HWB, use blackness, whiteness, and hue.
+%
+%  The format of the ModulateImage method is:
+%
+%      MagickBooleanType ModulateImage(Image *image,const char *modulate)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o modulate: Define the percent change in brightness, saturation, and
+%      hue.
+%
+*/
+
+static void ModulateHSB(const double percent_hue,
+  const double percent_saturation,const double percent_brightness,
+  Quantum *red,Quantum *green,Quantum *blue)
+{
+  double
+    brightness,
+    hue,
+    saturation;
+
+  /*
+    Increase or decrease color brightness, saturation, or hue.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  ConvertRGBToHSB(*red,*green,*blue,&hue,&saturation,&brightness);
+  hue+=0.5*(0.01*percent_hue-1.0);
+  while (hue < 0.0)
+    hue+=1.0;
+  while (hue > 1.0)
+    hue-=1.0;
+  saturation*=0.01*percent_saturation;
+  brightness*=0.01*percent_brightness;
+  ConvertHSBToRGB(hue,saturation,brightness,red,green,blue);
+}
+
+static void ModulateHSL(const double percent_hue,
+  const double percent_saturation,const double percent_lightness,
+  Quantum *red,Quantum *green,Quantum *blue)
+{
+  double
+    hue,
+    lightness,
+    saturation;
+
+  /*
+    Increase or decrease color lightness, saturation, or hue.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  ConvertRGBToHSL(*red,*green,*blue,&hue,&saturation,&lightness);
+  hue+=0.5*(0.01*percent_hue-1.0);
+  while (hue < 0.0)
+    hue+=1.0;
+  while (hue > 1.0)
+    hue-=1.0;
+  saturation*=0.01*percent_saturation;
+  lightness*=0.01*percent_lightness;
+  ConvertHSLToRGB(hue,saturation,lightness,red,green,blue);
+}
+
+static void ModulateHWB(const double percent_hue,const double percent_whiteness,  const double percent_blackness,Quantum *red,Quantum *green,Quantum *blue)
+{
+  double
+    blackness,
+    hue,
+    whiteness;
+
+  /*
+    Increase or decrease color blackness, whiteness, or hue.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  ConvertRGBToHWB(*red,*green,*blue,&hue,&whiteness,&blackness);
+  hue+=0.5*(0.01*percent_hue-1.0);
+  while (hue < 0.0)
+    hue+=1.0;
+  while (hue > 1.0)
+    hue-=1.0;
+  blackness*=0.01*percent_blackness;
+  whiteness*=0.01*percent_whiteness;
+  ConvertHWBToRGB(hue,whiteness,blackness,red,green,blue);
+}
+
+MagickExport MagickBooleanType ModulateImage(Image *image,const char *modulate)
+{
+#define ModulateImageTag  "Modulate/Image"
+
+  CacheView
+    *image_view;
+
+  ColorspaceType
+    colorspace;
+
+  const char
+    *artifact;
+
+  double
+    percent_brightness,
+    percent_hue,
+    percent_saturation;
+
+  ExceptionInfo
+    *exception;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  MagickStatusType
+    flags;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize modulate table.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (modulate == (char *) NULL)
+    return(MagickFalse);
+  flags=ParseGeometry(modulate,&geometry_info);
+  percent_brightness=geometry_info.rho;
+  percent_saturation=geometry_info.sigma;
+  if ((flags & SigmaValue) == 0)
+    percent_saturation=100.0;
+  percent_hue=geometry_info.xi;
+  if ((flags & XiValue) == 0)
+    percent_hue=100.0;
+  colorspace=UndefinedColorspace;
+  artifact=GetImageArtifact(image,"modulate:colorspace");
+  if (artifact != (const char *) NULL)
+    colorspace=(ColorspaceType) ParseCommandOption(MagickColorspaceOptions,
+      MagickFalse,artifact);
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Modulate colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+        switch (colorspace)
+        {
+          case HSBColorspace:
+          {
+            ModulateHSB(percent_hue,percent_saturation,percent_brightness,
+              &image->colormap[i].red,&image->colormap[i].green,
+              &image->colormap[i].blue);
+            break;
+          }
+          case HSLColorspace:
+          default:
+          {
+            ModulateHSL(percent_hue,percent_saturation,percent_brightness,
+              &image->colormap[i].red,&image->colormap[i].green,
+              &image->colormap[i].blue);
+            break;
+          }
+          case HWBColorspace:
+          {
+            ModulateHWB(percent_hue,percent_saturation,percent_brightness,
+              &image->colormap[i].red,&image->colormap[i].green,
+              &image->colormap[i].blue);
+            break;
+          }
+        }
+    }
+  /*
+    Modulate image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    Quantum
+      blue,
+      green,
+      red;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      red=GetPixelRed(image,q);
+      green=GetPixelGreen(image,q);
+      blue=GetPixelBlue(image,q);
+      switch (colorspace)
+      {
+        case HSBColorspace:
+        {
+          ModulateHSB(percent_hue,percent_saturation,percent_brightness,
+            &red,&green,&blue);
+          break;
+        }
+        case HSLColorspace:
+        default:
+        {
+          ModulateHSL(percent_hue,percent_saturation,percent_brightness,
+            &red,&green,&blue);
+          break;
+        }
+        case HWBColorspace:
+        {
+          ModulateHWB(percent_hue,percent_saturation,percent_brightness,
+            &red,&green,&blue);
+          break;
+        }
+      }
+      SetPixelRed(image,red,q);
+      SetPixelGreen(image,green,q);
+      SetPixelBlue(image,blue,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ModulateImage)
+#endif
+        proceed=SetImageProgress(image,ModulateImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     N e g a t e I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NegateImage() negates the colors in the reference image.  The grayscale
+%  option means that only grayscale values within the image are negated.
+%
+%  The format of the NegateImageChannel method is:
+%
+%      MagickBooleanType NegateImage(Image *image,
+%        const MagickBooleanType grayscale)
+%      MagickBooleanType NegateImageChannel(Image *image,
+%        const ChannelType channel,const MagickBooleanType grayscale)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o grayscale: If MagickTrue, only negate grayscale pixels within the image.
+%
+*/
+
+MagickExport MagickBooleanType NegateImage(Image *image,
+  const MagickBooleanType grayscale)
+{
+  MagickBooleanType
+    status;
+
+  status=NegateImageChannel(image,DefaultChannels,grayscale);
+  return(status);
+}
+
+MagickExport MagickBooleanType NegateImageChannel(Image *image,
+  const ChannelType channel,const MagickBooleanType grayscale)
+{
+#define NegateImageTag  "Negate/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Negate colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if (grayscale != MagickFalse)
+          if ((image->colormap[i].red != image->colormap[i].green) ||
+              (image->colormap[i].green != image->colormap[i].blue))
+            continue;
+        if ((channel & RedChannel) != 0)
+          image->colormap[i].red=(Quantum) QuantumRange-
+            image->colormap[i].red;
+        if ((channel & GreenChannel) != 0)
+          image->colormap[i].green=(Quantum) QuantumRange-
+            image->colormap[i].green;
+        if ((channel & BlueChannel) != 0)
+          image->colormap[i].blue=(Quantum) QuantumRange-
+            image->colormap[i].blue;
+      }
+    }
+  /*
+    Negate image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  if (grayscale != MagickFalse)
+    {
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register Quantum
+          *restrict q;
+
+        register ssize_t
+          x;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          if ((GetPixelRed(image,q) != GetPixelGreen(image,q)) ||
+              (GetPixelGreen(image,q) != GetPixelBlue(image,q)))
+            {
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(image,QuantumRange-GetPixelRed(image,q),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(image,QuantumRange-GetPixelGreen(image,q),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(image,QuantumRange-GetPixelBlue(image,q),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(image,QuantumRange-GetPixelBlack(image,q),q);
+          if ((channel & OpacityChannel) != 0)
+            SetPixelAlpha(image,QuantumRange-GetPixelAlpha(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_NegateImageChannel)
+#endif
+            proceed=SetImageProgress(image,NegateImageTag,progress++,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      image_view=DestroyCacheView(image_view);
+      return(MagickTrue);
+    }
+  /*
+    Negate image.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,QuantumRange-GetPixelRed(image,q),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,QuantumRange-GetPixelGreen(image,q),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,QuantumRange-GetPixelBlue(image,q),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,QuantumRange-GetPixelBlack(image,q),q);
+      if ((channel & OpacityChannel) != 0)
+        SetPixelAlpha(image,QuantumRange-GetPixelAlpha(image,q),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_NegateImageChannel)
+#endif
+        proceed=SetImageProgress(image,NegateImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     N o r m a l i z e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The NormalizeImage() method enhances the contrast of a color image by
+%  mapping the darkest 2 percent of all pixel to black and the brightest
+%  1 percent to white.
+%
+%  The format of the NormalizeImage method is:
+%
+%      MagickBooleanType NormalizeImage(Image *image)
+%      MagickBooleanType NormalizeImageChannel(Image *image,
+%        const ChannelType channel)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+*/
+
+MagickExport MagickBooleanType NormalizeImage(Image *image)
+{
+  MagickBooleanType
+    status;
+
+  status=NormalizeImageChannel(image,DefaultChannels);
+  return(status);
+}
+
+MagickExport MagickBooleanType NormalizeImageChannel(Image *image,
+  const ChannelType channel)
+{
+  double
+    black_point,
+    white_point;
+
+  black_point=(double) image->columns*image->rows*0.0015;
+  white_point=(double) image->columns*image->rows*0.9995;
+  return(ContrastStretchImageChannel(image,channel,black_point,white_point));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S i g m o i d a l C o n t r a s t I m a g e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SigmoidalContrastImage() adjusts the contrast of an image with a non-linear
+%  sigmoidal contrast algorithm.  Increase the contrast of the image using a
+%  sigmoidal transfer function without saturating highlights or shadows.
+%  Contrast indicates how much to increase the contrast (0 is none; 3 is
+%  typical; 20 is pushing it); mid-point indicates where midtones fall in the
+%  resultant image (0 is white; 50% is middle-gray; 100% is black).  Set
+%  sharpen to MagickTrue to increase the image contrast otherwise the contrast
+%  is reduced.
+%
+%  The format of the SigmoidalContrastImage method is:
+%
+%      MagickBooleanType SigmoidalContrastImage(Image *image,
+%        const MagickBooleanType sharpen,const char *levels)
+%      MagickBooleanType SigmoidalContrastImageChannel(Image *image,
+%        const ChannelType channel,const MagickBooleanType sharpen,
+%        const double contrast,const double midpoint)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o sharpen: Increase or decrease image contrast.
+%
+%    o alpha: strength of the contrast, the larger the number the more
+%      'threshold-like' it becomes.
+%
+%    o beta: midpoint of the function as a color value 0 to QuantumRange.
+%
+*/
+
+MagickExport MagickBooleanType SigmoidalContrastImage(Image *image,
+  const MagickBooleanType sharpen,const char *levels)
+{
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  MagickStatusType
+    flags;
+
+  flags=ParseGeometry(levels,&geometry_info);
+  if ((flags & SigmaValue) == 0)
+    geometry_info.sigma=1.0*QuantumRange/2.0;
+  if ((flags & PercentValue) != 0)
+    geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
+  status=SigmoidalContrastImageChannel(image,DefaultChannels,sharpen,
+    geometry_info.rho,geometry_info.sigma);
+  return(status);
+}
+
+MagickExport MagickBooleanType SigmoidalContrastImageChannel(Image *image,
+  const ChannelType channel,const MagickBooleanType sharpen,
+  const double contrast,const double midpoint)
+{
+#define SigmoidalContrastImageTag  "SigmoidalContrast/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  MagickRealType
+    *sigmoidal_map;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate and initialize sigmoidal maps.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  sigmoidal_map=(MagickRealType *) AcquireQuantumMemory(MaxMap+1UL,
+    sizeof(*sigmoidal_map));
+  if (sigmoidal_map == (MagickRealType *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  (void) ResetMagickMemory(sigmoidal_map,0,(MaxMap+1)*sizeof(*sigmoidal_map));
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    if (sharpen != MagickFalse)
+      {
+        sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+          (MaxMap*((1.0/(1.0+exp(contrast*(midpoint/(double) QuantumRange-
+          (double) i/MaxMap))))-(1.0/(1.0+exp(contrast*(midpoint/
+          (double) QuantumRange)))))/((1.0/(1.0+exp(contrast*(midpoint/
+          (double) QuantumRange-1.0))))-(1.0/(1.0+exp(contrast*(midpoint/
+          (double) QuantumRange)))))+0.5));
+        continue;
+      }
+    sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
+      (MaxMap*(QuantumScale*midpoint-log((1.0-(1.0/(1.0+exp(midpoint/
+      (double) QuantumRange*contrast))+((double) i/MaxMap)*((1.0/
+      (1.0+exp(contrast*(midpoint/(double) QuantumRange-1.0))))-(1.0/
+      (1.0+exp(midpoint/(double) QuantumRange*contrast))))))/
+      (1.0/(1.0+exp(midpoint/(double) QuantumRange*contrast))+
+      ((double) i/MaxMap)*((1.0/(1.0+exp(contrast*(midpoint/
+      (double) QuantumRange-1.0))))-(1.0/(1.0+exp(midpoint/
+      (double) QuantumRange*contrast))))))/contrast)));
+  }
+  if (image->storage_class == PseudoClass)
+    {
+      /*
+        Sigmoidal-contrast enhance colormap.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if ((channel & RedChannel) != 0)
+          image->colormap[i].red=ClampToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].red)]);
+        if ((channel & GreenChannel) != 0)
+          image->colormap[i].green=ClampToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].green)]);
+        if ((channel & BlueChannel) != 0)
+          image->colormap[i].blue=ClampToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].blue)]);
+        if ((channel & OpacityChannel) != 0)
+          image->colormap[i].alpha=ClampToQuantum(sigmoidal_map[
+            ScaleQuantumToMap(image->colormap[i].alpha)]);
+      }
+    }
+  /*
+    Sigmoidal-contrast enhance image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
+          GetPixelRed(image,q))]),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
+          GetPixelGreen(image,q))]),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
+          GetPixelBlue(image,q))]),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
+          GetPixelBlack(image,q))]),q);
+      if ((channel & OpacityChannel) != 0)
+        SetPixelAlpha(image,ClampToQuantum(sigmoidal_map[ScaleQuantumToMap(
+          GetPixelAlpha(image,q))]),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SigmoidalContrastImageChannel)
+#endif
+        proceed=SetImageProgress(image,SigmoidalContrastImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  sigmoidal_map=(MagickRealType *) RelinquishMagickMemory(sigmoidal_map);
+  return(status);
+}
diff --git a/MagickCore/enhance.h b/MagickCore/enhance.h
new file mode 100644
index 0000000..fb5d39b
--- /dev/null
+++ b/MagickCore/enhance.h
@@ -0,0 +1,73 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image enhance methods.
+*/
+#ifndef _MAGICKCORE_ENHANCE_H
+#define _MAGICKCORE_ENHANCE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  AutoGammaImage(Image *),
+  AutoGammaImageChannel(Image *,const ChannelType),
+  AutoLevelImage(Image *),
+  AutoLevelImageChannel(Image *,const ChannelType),
+  BrightnessContrastImage(Image *,const double,const double),
+  BrightnessContrastImageChannel(Image *,const ChannelType,const double,
+    const double),
+  ClutImage(Image *,const Image *),
+  ClutImageChannel(Image *,const ChannelType,const Image *),
+  ColorDecisionListImage(Image *,const char *),
+  ContrastImage(Image *,const MagickBooleanType),
+  ContrastStretchImage(Image *,const char *),
+  ContrastStretchImageChannel(Image *,const ChannelType,const double,
+    const double),
+  EqualizeImage(Image *image),
+  EqualizeImageChannel(Image *image,const ChannelType),
+  GammaImage(Image *,const char *),
+  GammaImageChannel(Image *,const ChannelType,const double),
+  HaldClutImage(Image *,const Image *),
+  HaldClutImageChannel(Image *,const ChannelType,const Image *),
+  LevelImage(Image *,const char *),
+  LevelImageChannel(Image *,const ChannelType,const double,const double,
+    const double),
+  LevelizeImage(Image *,const double,const double,const double),
+  LevelizeImageChannel(Image *,const ChannelType,const double,const double,
+    const double),
+  LevelColorsImage(Image *,const PixelInfo *,const PixelInfo *,
+    const MagickBooleanType),
+  LevelColorsImageChannel(Image *,const ChannelType,const PixelInfo *,
+    const PixelInfo *,const MagickBooleanType),
+  LinearStretchImage(Image *,const double,const double),
+  ModulateImage(Image *,const char *),
+  NegateImage(Image *,const MagickBooleanType),
+  NegateImageChannel(Image *,const ChannelType,const MagickBooleanType),
+  NormalizeImage(Image *),
+  NormalizeImageChannel(Image *,const ChannelType),
+  SigmoidalContrastImage(Image *,const MagickBooleanType,const char *),
+  SigmoidalContrastImageChannel(Image *,const ChannelType,
+    const MagickBooleanType,const double,const double);
+
+extern MagickExport Image
+  *EnhanceImage(const Image *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/exception-private.h b/MagickCore/exception-private.h
new file mode 100644
index 0000000..8fef7e9
--- /dev/null
+++ b/MagickCore/exception-private.h
@@ -0,0 +1,94 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore exception private methods.
+*/
+#ifndef _MAGICKCORE_EXCEPTION_PRIVATE_H
+#define _MAGICKCORE_EXCEPTION_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/log.h"
+#include "MagickCore/string_.h"
+
+#define ThrowBinaryException(severity,tag,context) \
+{ \
+  if (image != (Image *) NULL) \
+    (void) ThrowMagickException(&image->exception,GetMagickModule(),severity, \
+      tag == (const char *) NULL ? "unknown" : tag,"`%s'",context); \
+  return(MagickFalse); \
+}
+#define ThrowFatalException(severity,tag) \
+{ \
+  char \
+    *message; \
+ \
+  ExceptionInfo \
+    exception; \
+ \
+  GetExceptionInfo(&exception); \
+  message=GetExceptionMessage(errno); \
+  (void) ThrowMagickException(&exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s'",message); \
+  message=DestroyString(message); \
+  CatchException(&exception); \
+  (void) DestroyExceptionInfo(&exception); \
+  _exit(1); \
+}
+#define ThrowFileException(exception,severity,tag,context) \
+{ \
+  char \
+    *message; \
+ \
+  message=GetExceptionMessage(errno); \
+  (void) ThrowMagickException(exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s': %s",context,message); \
+  message=DestroyString(message); \
+}
+#define ThrowImageException(severity,tag) \
+{ \
+  (void) ThrowMagickException(exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s'",image->filename); \
+  return((Image *) NULL); \
+}
+#define ThrowReaderException(severity,tag) \
+{ \
+  (void) ThrowMagickException(exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s'",image_info->filename); \
+  if ((image) != (Image *) NULL) \
+    { \
+      (void) CloseBlob(image); \
+      image=DestroyImageList(image); \
+    } \
+  return((Image *) NULL); \
+}
+#define ThrowWriterException(severity,tag) \
+{ \
+  (void) ThrowMagickException(&image->exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s'",image->filename); \
+  if (image_info->adjoin != MagickFalse) \
+    while (image->previous != (Image *) NULL) \
+      image=image->previous; \
+  (void) CloseBlob(image); \
+  return(MagickFalse); \
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/exception.c b/MagickCore/exception.c
new file mode 100644
index 0000000..509a585
--- /dev/null
+++ b/MagickCore/exception.c
@@ -0,0 +1,1005 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        EEEEE  X   X   CCCC  EEEEE  PPPP  TTTTT  IIIII   OOO   N   N         %
+%        E       X X   C      E      P   P   T      I    O   O  NN  N         %
+%        EEE      X    C      EEE    PPPP    T      I    O   O  N N N         %
+%        E       X X   C      E      P       T      I    O   O  N  NN         %
+%        EEEEE   X  X   CCCC  EEEEE  P       T    IIIII   OOO   N   N         %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Exception Methods                         %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                                July 1993                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/client.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+
+/*
+  Forward declarations.
+*/
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static void
+  DefaultErrorHandler(const ExceptionType,const char *,const char *),
+  DefaultFatalErrorHandler(const ExceptionType,const char *,const char *),
+  DefaultWarningHandler(const ExceptionType,const char *,const char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+/*
+  Global declarations.
+*/
+static ErrorHandler
+  error_handler = DefaultErrorHandler;
+
+static FatalErrorHandler
+  fatal_error_handler = DefaultFatalErrorHandler;
+
+static WarningHandler
+  warning_handler = DefaultWarningHandler;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e E x c e p t i o n I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireExceptionInfo() allocates the ExceptionInfo structure.
+%
+%  The format of the AcquireExceptionInfo method is:
+%
+%      ExceptionInfo *AcquireExceptionInfo(void)
+%
+*/
+MagickExport ExceptionInfo *AcquireExceptionInfo(void)
+{
+  ExceptionInfo
+    *exception;
+
+  exception=(ExceptionInfo *) AcquireMagickMemory(sizeof(*exception));
+  if (exception == (ExceptionInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetExceptionInfo(exception);
+  exception->relinquish=MagickTrue;
+  return(exception);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l e a r M a g i c k E x c e p t i o n                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClearMagickException() clears any exception that may not have been caught
+%  yet.
+%
+%  The format of the ClearMagickException method is:
+%
+%      ClearMagickException(ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+*/
+
+static void *DestroyExceptionElement(void *exception)
+{
+  register ExceptionInfo
+    *p;
+
+  p=(ExceptionInfo *) exception;
+  if (p->reason != (char *) NULL)
+    p->reason=DestroyString(p->reason);
+  if (p->description != (char *) NULL)
+    p->description=DestroyString(p->description);
+  p=(ExceptionInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void ClearMagickException(ExceptionInfo *exception)
+{
+  register ExceptionInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (exception->exceptions  == (void *) NULL)
+    return;
+  LockSemaphoreInfo(exception->semaphore);
+  p=(ExceptionInfo *) RemoveLastElementFromLinkedList((LinkedListInfo *)
+    exception->exceptions);
+  while (p != (ExceptionInfo *) NULL)
+  {
+    (void) DestroyExceptionElement(p);
+    p=(ExceptionInfo *) RemoveLastElementFromLinkedList((LinkedListInfo *)
+      exception->exceptions);
+  }
+  exception->severity=UndefinedException;
+  exception->reason=(char *) NULL;
+  exception->description=(char *) NULL;
+  UnlockSemaphoreInfo(exception->semaphore);
+  errno=0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C a t c h E x c e p t i o n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CatchException() returns if no exceptions is found otherwise it reports
+%  the exception as a warning, error, or fatal depending on the severity.
+%
+%  The format of the CatchException method is:
+%
+%      CatchException(ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+*/
+MagickExport void CatchException(ExceptionInfo *exception)
+{
+  register const ExceptionInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (exception->exceptions  == (void *) NULL)
+    return;
+  LockSemaphoreInfo(exception->semaphore);
+  ResetLinkedListIterator((LinkedListInfo *) exception->exceptions);
+  p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
+    exception->exceptions);
+  while (p != (const ExceptionInfo *) NULL)
+  {
+    if ((p->severity >= WarningException) && (p->severity < ErrorException))
+      MagickWarning(p->severity,p->reason,p->description);
+    if ((p->severity >= ErrorException) && (p->severity < FatalErrorException))
+      MagickError(p->severity,p->reason,p->description);
+    if (p->severity >= FatalErrorException)
+      MagickFatalError(p->severity,p->reason,p->description);
+    p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
+      exception->exceptions);
+  }
+  UnlockSemaphoreInfo(exception->semaphore);
+  ClearMagickException(exception);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f a u l t E r r o r H a n d l e r                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefaultErrorHandler() displays an error reason.
+%
+%  The format of the DefaultErrorHandler method is:
+%
+%      void MagickError(const ExceptionType severity,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o severity: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+static void DefaultErrorHandler(const ExceptionType magick_unused(severity),
+  const char *reason,const char *description)
+{
+  if (reason == (char *) NULL)
+    return;
+  (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) FormatLocaleFile(stderr," (%s)",description);
+  (void) FormatLocaleFile(stderr,".\n");
+  (void) fflush(stderr);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f a u l t F a t a l E r r o r H a n d l e r                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefaultFatalErrorHandler() displays an error reason and then terminates the
+%  program.
+%
+%  The format of the DefaultFatalErrorHandler method is:
+%
+%      void MagickFatalError(const ExceptionType severity,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o severity: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+static void DefaultFatalErrorHandler(
+  const ExceptionType magick_unused(severity),
+  const char *reason,const char *description)
+{
+  if (reason == (char *) NULL)
+    return;
+  (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) FormatLocaleFile(stderr," (%s)",description);
+  (void) FormatLocaleFile(stderr,".\n");
+  (void) fflush(stderr);
+  MagickCoreTerminus();
+  exit(1);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f a u l t W a r n i n g H a n d l e r                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefaultWarningHandler() displays a warning reason.
+%
+%  The format of the DefaultWarningHandler method is:
+%
+%      void DefaultWarningHandler(const ExceptionType severity,
+%        const char *reason,const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o severity: Specifies the numeric warning category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+static void DefaultWarningHandler(const ExceptionType magick_unused(severity),
+  const char *reason,const char *description)
+{
+  if (reason == (char *) NULL)
+    return;
+  (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) FormatLocaleFile(stderr," (%s)",description);
+  (void) FormatLocaleFile(stderr,".\n");
+  (void) fflush(stderr);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y E x c e p t i o n I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyExceptionInfo() deallocates memory associated with an exception.
+%
+%  The format of the DestroyExceptionInfo method is:
+%
+%      ExceptionInfo *DestroyExceptionInfo(ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+*/
+MagickExport ExceptionInfo *DestroyExceptionInfo(ExceptionInfo *exception)
+{
+  MagickBooleanType
+    relinquish;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (exception->semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&exception->semaphore);
+  LockSemaphoreInfo(exception->semaphore);
+  exception->severity=UndefinedException;
+  if (exception->exceptions != (void *) NULL)
+    exception->exceptions=(void *) DestroyLinkedList((LinkedListInfo *)
+      exception->exceptions,DestroyExceptionElement);
+  relinquish=exception->relinquish;
+  if (exception->relinquish != MagickFalse)
+    exception->signature=(~MagickSignature);
+  UnlockSemaphoreInfo(exception->semaphore);
+  DestroySemaphoreInfo(&exception->semaphore);
+  if (relinquish != MagickFalse)
+    exception=(ExceptionInfo *) RelinquishMagickMemory(exception);
+  return(exception);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t E x c e p t i o n I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetExceptionInfo() initializes an exception to default values.
+%
+%  The format of the GetExceptionInfo method is:
+%
+%      GetExceptionInfo(ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+*/
+MagickExport void GetExceptionInfo(ExceptionInfo *exception)
+{
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) ResetMagickMemory(exception,0,sizeof(*exception));
+  exception->severity=UndefinedException;
+  exception->exceptions=(void *) NewLinkedList(0);
+  exception->semaphore=AllocateSemaphoreInfo();
+  exception->signature=MagickSignature;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t E x c e p t i o n M e s s a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetExceptionMessage() returns the error message defined by the specified
+%  error code.
+%
+%  The format of the GetExceptionMessage method is:
+%
+%      char *GetExceptionMessage(const int error)
+%
+%  A description of each parameter follows:
+%
+%    o error: the error code.
+%
+*/
+MagickExport char *GetExceptionMessage(const int error)
+{
+  char
+    exception[MaxTextExtent];
+
+  *exception='\0';
+#if defined(MAGICKCORE_HAVE_STRERROR_R)
+  (void) strerror_r(error,exception,sizeof(exception));
+#else
+  (void) CopyMagickString(exception,strerror(error),sizeof(exception));
+#endif
+  return(ConstantString(exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o c a l e E x c e p t i o n M e s s a g e                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleExceptionMessage() converts a enumerated exception severity and tag
+%  to a message in the current locale.
+%
+%  The format of the GetLocaleExceptionMessage method is:
+%
+%      const char *GetLocaleExceptionMessage(const ExceptionType severity,
+%        const char *tag)
+%
+%  A description of each parameter follows:
+%
+%    o severity: the severity of the exception.
+%
+%    o tag: the message tag.
+%
+*/
+
+static const char *ExceptionSeverityToTag(const ExceptionType severity)
+{
+  switch (severity)
+  {
+    case ResourceLimitWarning: return("Resource/Limit/Warning/");
+    case TypeWarning: return("Type/Warning/");
+    case OptionWarning: return("Option/Warning/");
+    case DelegateWarning: return("Delegate/Warning/");
+    case MissingDelegateWarning: return("Missing/Delegate/Warning/");
+    case CorruptImageWarning: return("Corrupt/Image/Warning/");
+    case FileOpenWarning: return("File/Open/Warning/");
+    case BlobWarning: return("Blob/Warning/");
+    case StreamWarning: return("Stream/Warning/");
+    case CacheWarning: return("Cache/Warning/");
+    case CoderWarning: return("Coder/Warning/");
+    case FilterWarning: return("Filter/Warning/");
+    case ModuleWarning: return("Module/Warning/");
+    case DrawWarning: return("Draw/Warning/");
+    case ImageWarning: return("Image/Warning/");
+    case WandWarning: return("Wand/Warning/");
+    case XServerWarning: return("XServer/Warning/");
+    case MonitorWarning: return("Monitor/Warning/");
+    case RegistryWarning: return("Registry/Warning/");
+    case ConfigureWarning: return("Configure/Warning/");
+    case PolicyWarning: return("Policy/Warning/");
+    case ResourceLimitError: return("Resource/Limit/Error/");
+    case TypeError: return("Type/Error/");
+    case OptionError: return("Option/Error/");
+    case DelegateError: return("Delegate/Error/");
+    case MissingDelegateError: return("Missing/Delegate/Error/");
+    case CorruptImageError: return("Corrupt/Image/Error/");
+    case FileOpenError: return("File/Open/Error/");
+    case BlobError: return("Blob/Error/");
+    case StreamError: return("Stream/Error/");
+    case CacheError: return("Cache/Error/");
+    case CoderError: return("Coder/Error/");
+    case FilterError: return("Filter/Error/");
+    case ModuleError: return("Module/Error/");
+    case DrawError: return("Draw/Error/");
+    case ImageError: return("Image/Error/");
+    case WandError: return("Wand/Error/");
+    case XServerError: return("XServer/Error/");
+    case MonitorError: return("Monitor/Error/");
+    case RegistryError: return("Registry/Error/");
+    case ConfigureError: return("Configure/Error/");
+    case PolicyError: return("Policy/Error/");
+    case ResourceLimitFatalError: return("Resource/Limit/FatalError/");
+    case TypeFatalError: return("Type/FatalError/");
+    case OptionFatalError: return("Option/FatalError/");
+    case DelegateFatalError: return("Delegate/FatalError/");
+    case MissingDelegateFatalError: return("Missing/Delegate/FatalError/");
+    case CorruptImageFatalError: return("Corrupt/Image/FatalError/");
+    case FileOpenFatalError: return("File/Open/FatalError/");
+    case BlobFatalError: return("Blob/FatalError/");
+    case StreamFatalError: return("Stream/FatalError/");
+    case CacheFatalError: return("Cache/FatalError/");
+    case CoderFatalError: return("Coder/FatalError/");
+    case FilterFatalError: return("Filter/FatalError/");
+    case ModuleFatalError: return("Module/FatalError/");
+    case DrawFatalError: return("Draw/FatalError/");
+    case ImageFatalError: return("Image/FatalError/");
+    case WandFatalError: return("Wand/FatalError/");
+    case XServerFatalError: return("XServer/FatalError/");
+    case MonitorFatalError: return("Monitor/FatalError/");
+    case RegistryFatalError: return("Registry/FatalError/");
+    case ConfigureFatalError: return("Configure/FatalError/");
+    case PolicyFatalError: return("Policy/FatalError/");
+    default: break;
+  }
+  return("");
+}
+
+MagickExport const char *GetLocaleExceptionMessage(const ExceptionType severity,
+  const char *tag)
+{
+  char
+    message[MaxTextExtent];
+
+  const char
+    *locale_message;
+
+  assert(tag != (const char *) NULL);
+  (void) FormatLocaleString(message,MaxTextExtent,"Exception/%s%s",
+    ExceptionSeverityToTag(severity),tag);
+  locale_message=GetLocaleMessage(message);
+  if (locale_message == (const char *) NULL)
+    return(tag);
+  if (locale_message == message)
+    return(tag);
+  return(locale_message);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n h e r i t E x c e p t i o n                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InheritException() inherits an exception from a related exception.
+%
+%  The format of the InheritException method is:
+%
+%      InheritException(ExceptionInfo *exception,const ExceptionInfo *relative)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+%    o relative: the related exception info.
+%
+*/
+MagickExport void InheritException(ExceptionInfo *exception,
+  const ExceptionInfo *relative)
+{
+  register const ExceptionInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert(relative != (ExceptionInfo *) NULL);
+  assert(relative->signature == MagickSignature);
+  if (relative->exceptions == (void *) NULL)
+    return;
+  LockSemaphoreInfo(exception->semaphore);
+  ResetLinkedListIterator((LinkedListInfo *) relative->exceptions);
+  p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
+    relative->exceptions);
+  while (p != (const ExceptionInfo *) NULL)
+  {
+    (void) ThrowException(exception,p->severity,p->reason,p->description);
+    p=(const ExceptionInfo *) GetNextValueInLinkedList((LinkedListInfo *)
+      relative->exceptions);
+  }
+  UnlockSemaphoreInfo(exception->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k E r r o r                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickError() calls the exception handler methods with an error reason.
+%
+%  The format of the MagickError method is:
+%
+%      void MagickError(const ExceptionType error,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o exception: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+MagickExport void MagickError(const ExceptionType error,const char *reason,
+  const char *description)
+{
+  if (error_handler != (ErrorHandler) NULL)
+    (*error_handler)(error,reason,description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k F a t al E r r o r                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickFatalError() calls the fatal exception handler methods with an error
+%  reason.
+%
+%  The format of the MagickError method is:
+%
+%      void MagickFatalError(const ExceptionType error,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o exception: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+MagickExport void MagickFatalError(const ExceptionType error,const char *reason,
+  const char *description)
+{
+  if (fatal_error_handler != (ErrorHandler) NULL)
+    (*fatal_error_handler)(error,reason,description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k W a r n i n g                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickWarning() calls the warning handler methods with a warning reason.
+%
+%  The format of the MagickWarning method is:
+%
+%      void MagickWarning(const ExceptionType warning,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o warning: the warning severity.
+%
+%    o reason: Define the reason for the warning.
+%
+%    o description: Describe the warning.
+%
+*/
+MagickExport void MagickWarning(const ExceptionType warning,const char *reason,
+  const char *description)
+{
+  if (warning_handler != (WarningHandler) NULL)
+    (*warning_handler)(warning,reason,description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t E r r o r H a n d l e r                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetErrorHandler() sets the exception handler to the specified method
+%  and returns the previous exception handler.
+%
+%  The format of the SetErrorHandler method is:
+%
+%      ErrorHandler SetErrorHandler(ErrorHandler handler)
+%
+%  A description of each parameter follows:
+%
+%    o handler: the method to handle errors.
+%
+*/
+MagickExport ErrorHandler SetErrorHandler(ErrorHandler handler)
+{
+  ErrorHandler
+    previous_handler;
+
+  previous_handler=error_handler;
+  error_handler=handler;
+  return(previous_handler);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t F a t a l E r r o r H a n d l e r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetFatalErrorHandler() sets the fatal exception handler to the specified
+%  method and returns the previous fatal exception handler.
+%
+%  The format of the SetErrorHandler method is:
+%
+%      ErrorHandler SetErrorHandler(ErrorHandler handler)
+%
+%  A description of each parameter follows:
+%
+%    o handler: the method to handle errors.
+%
+*/
+MagickExport FatalErrorHandler SetFatalErrorHandler(FatalErrorHandler handler)
+{
+  FatalErrorHandler
+    previous_handler;
+
+  previous_handler=fatal_error_handler;
+  fatal_error_handler=handler;
+  return(previous_handler);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t W a r n i n g H a n d l e r                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetWarningHandler() sets the warning handler to the specified method
+%  and returns the previous warning handler.
+%
+%  The format of the SetWarningHandler method is:
+%
+%      ErrorHandler SetWarningHandler(ErrorHandler handler)
+%
+%  A description of each parameter follows:
+%
+%    o handler: the method to handle warnings.
+%
+*/
+MagickExport WarningHandler SetWarningHandler(WarningHandler handler)
+{
+  WarningHandler
+    previous_handler;
+
+  previous_handler=warning_handler;
+  warning_handler=handler;
+  return(previous_handler);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T h r o w E x c e p t i o n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ThrowException() throws an exception with the specified severity code,
+%  reason, and optional description.
+%
+%  The format of the ThrowException method is:
+%
+%      MagickBooleanType ThrowException(ExceptionInfo *exception,
+%        const ExceptionType severity,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+%    o severity: the severity of the exception.
+%
+%    o reason: the reason for the exception.
+%
+%    o description: the exception description.
+%
+*/
+MagickExport MagickBooleanType ThrowException(ExceptionInfo *exception,
+  const ExceptionType severity,const char *reason,const char *description)
+{
+  register ExceptionInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  p=(ExceptionInfo *) GetLastValueInLinkedList((LinkedListInfo *)
+    exception->exceptions);
+  if ((p != (ExceptionInfo *) NULL) && (p->severity == severity) &&
+      (LocaleCompare(exception->reason,reason) == 0) &&
+      (LocaleCompare(exception->description,description) == 0))
+    return(MagickTrue);
+  p=(ExceptionInfo *) AcquireMagickMemory(sizeof(*p));
+  if (p == (ExceptionInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(p,0,sizeof(*p));
+  p->severity=severity;
+  if (reason != (const char *) NULL)
+    p->reason=ConstantString(reason);
+  if (description != (const char *) NULL)
+    p->description=ConstantString(description);
+  p->signature=MagickSignature;
+  (void) AppendValueToLinkedList((LinkedListInfo *) exception->exceptions,p);
+  exception->severity=p->severity;
+  exception->reason=p->reason;
+  exception->description=p->description;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T h r o w M a g i c k E x c e p t i o n                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ThrowMagickException logs an exception as determined by the log configuration
+%  file.  If an error occurs, MagickFalse is returned otherwise MagickTrue.
+%
+%  The format of the ThrowMagickException method is:
+%
+%      MagickBooleanType ThrowFileException(ExceptionInfo *exception,
+%        const char *module,const char *function,const size_t line,
+%        const ExceptionType severity,const char *tag,const char *format,...)
+%
+%  A description of each parameter follows:
+%
+%    o exception: the exception info.
+%
+%    o filename: the source module filename.
+%
+%    o function: the function name.
+%
+%    o line: the line number of the source module.
+%
+%    o severity: Specifies the numeric error category.
+%
+%    o tag: the locale tag.
+%
+%    o format: the output format.
+%
+*/
+
+MagickExport MagickBooleanType ThrowMagickExceptionList(
+  ExceptionInfo *exception,const char *module,const char *function,
+  const size_t line,const ExceptionType severity,const char *tag,
+  const char *format,va_list operands)
+{
+  char
+    message[MaxTextExtent],
+    path[MaxTextExtent],
+    reason[MaxTextExtent];
+
+  const char
+    *locale,
+    *type;
+
+  int
+    n;
+
+  MagickBooleanType
+    status;
+
+  size_t
+    length;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  locale=GetLocaleExceptionMessage(severity,tag);
+  (void) CopyMagickString(reason,locale,MaxTextExtent);
+  (void) ConcatenateMagickString(reason," ",MaxTextExtent);
+  length=strlen(reason);
+#if defined(MAGICKCORE_HAVE_VSNPRINTF)
+  n=vsnprintf(reason+length,MaxTextExtent-length,format,operands);
+#else
+  n=vsprintf(reason+length,format,operands);
+#endif
+  if (n < 0)
+    reason[MaxTextExtent-1]='\0';
+  status=LogMagickEvent(ExceptionEvent,module,function,line,"%s",reason);
+  GetPathComponent(module,TailPath,path);
+  type="undefined";
+  if ((severity >= WarningException) && (severity < ErrorException))
+    type="warning";
+  if ((severity >= ErrorException) && (severity < FatalErrorException))
+    type="error";
+  if (severity >= FatalErrorException)
+    type="fatal";
+  (void) FormatLocaleString(message,MaxTextExtent,"%s @ %s/%s/%s/%.20g",reason,
+    type,path,function,(double) line);
+  (void) ThrowException(exception,severity,message,(char *) NULL);
+  return(status);
+}
+
+MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception,
+  const char *module,const char *function,const size_t line,
+  const ExceptionType severity,const char *tag,const char *format,...)
+{
+  MagickBooleanType
+    status;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
+    format,operands);
+  va_end(operands);
+  return(status);
+}
diff --git a/MagickCore/exception.h b/MagickCore/exception.h
new file mode 100644
index 0000000..de24d7e
--- /dev/null
+++ b/MagickCore/exception.h
@@ -0,0 +1,178 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore exception methods.
+*/
+#ifndef _MAGICKCORE_EXCEPTION_H
+#define _MAGICKCORE_EXCEPTION_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include "MagickCore/semaphore.h"
+
+typedef enum
+{
+  UndefinedException,
+  WarningException = 300,
+  ResourceLimitWarning = 300,
+  TypeWarning = 305,
+  OptionWarning = 310,
+  DelegateWarning = 315,
+  MissingDelegateWarning = 320,
+  CorruptImageWarning = 325,
+  FileOpenWarning = 330,
+  BlobWarning = 335,
+  StreamWarning = 340,
+  CacheWarning = 345,
+  CoderWarning = 350,
+  FilterWarning = 352,
+  ModuleWarning = 355,
+  DrawWarning = 360,
+  ImageWarning = 365,
+  WandWarning = 370,
+  RandomWarning = 375,
+  XServerWarning = 380,
+  MonitorWarning = 385,
+  RegistryWarning = 390,
+  ConfigureWarning = 395,
+  PolicyWarning = 399,
+  ErrorException = 400,
+  ResourceLimitError = 400,
+  TypeError = 405,
+  OptionError = 410,
+  DelegateError = 415,
+  MissingDelegateError = 420,
+  CorruptImageError = 425,
+  FileOpenError = 430,
+  BlobError = 435,
+  StreamError = 440,
+  CacheError = 445,
+  CoderError = 450,
+  FilterError = 452,
+  ModuleError = 455,
+  DrawError = 460,
+  ImageError = 465,
+  WandError = 470,
+  RandomError = 475,
+  XServerError = 480,
+  MonitorError = 485,
+  RegistryError = 490,
+  ConfigureError = 495,
+  PolicyError = 499,
+  FatalErrorException = 700,
+  ResourceLimitFatalError = 700,
+  TypeFatalError = 705,
+  OptionFatalError = 710,
+  DelegateFatalError = 715,
+  MissingDelegateFatalError = 720,
+  CorruptImageFatalError = 725,
+  FileOpenFatalError = 730,
+  BlobFatalError = 735,
+  StreamFatalError = 740,
+  CacheFatalError = 745,
+  CoderFatalError = 750,
+  FilterFatalError = 752,
+  ModuleFatalError = 755,
+  DrawFatalError = 760,
+  ImageFatalError = 765,
+  WandFatalError = 770,
+  RandomFatalError = 775,
+  XServerFatalError = 780,
+  MonitorFatalError = 785,
+  RegistryFatalError = 790,
+  ConfigureFatalError = 795,
+  PolicyFatalError = 799
+} ExceptionType;
+
+struct _ExceptionInfo
+{
+  ExceptionType
+    severity;
+
+  int
+    error_number;
+
+  char
+    *reason,
+    *description;
+
+  void
+    *exceptions;
+
+  MagickBooleanType
+    relinquish;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+typedef void
+  (*ErrorHandler)(const ExceptionType,const char *,const char *);
+
+typedef void
+  (*FatalErrorHandler)(const ExceptionType,const char *,const char *);
+
+typedef void
+  (*WarningHandler)(const ExceptionType,const char *,const char *);
+
+extern MagickExport char
+  *GetExceptionMessage(const int);
+
+extern MagickExport const char
+  *GetLocaleExceptionMessage(const ExceptionType,const char *);
+
+extern MagickExport ErrorHandler
+  SetErrorHandler(ErrorHandler);
+
+extern MagickExport ExceptionInfo
+  *AcquireExceptionInfo(void),
+  *DestroyExceptionInfo(ExceptionInfo *);
+
+extern MagickExport FatalErrorHandler
+  SetFatalErrorHandler(FatalErrorHandler);
+
+extern MagickExport MagickBooleanType
+  ThrowException(ExceptionInfo *,const ExceptionType,const char *,
+    const char *),
+  ThrowMagickException(ExceptionInfo *,const char *,const char *,const size_t,
+    const ExceptionType,const char *,const char *,...)
+    magick_attribute((format (printf,7,8))),
+  ThrowMagickExceptionList(ExceptionInfo *,const char *,const char *,
+    const size_t,const ExceptionType,const char *,const char *,va_list)
+    magick_attribute((format (printf,7,0)));
+
+extern MagickExport void
+  CatchException(ExceptionInfo *),
+  ClearMagickException(ExceptionInfo *),
+  GetExceptionInfo(ExceptionInfo *),
+  InheritException(ExceptionInfo *,const ExceptionInfo *),
+  MagickError(const ExceptionType,const char *,const char *),
+  MagickFatalError(const ExceptionType,const char *,const char *),
+  MagickWarning(const ExceptionType,const char *,const char *);
+
+extern MagickExport WarningHandler
+  SetWarningHandler(WarningHandler);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/feature.c b/MagickCore/feature.c
new file mode 100644
index 0000000..f2b54f4
--- /dev/null
+++ b/MagickCore/feature.c
@@ -0,0 +1,1226 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               FFFFF  EEEEE   AAA   TTTTT  U   U  RRRR   EEEEE               %
+%               F      E      A   A    T    U   U  R   R  E                   %
+%               FFF    EEE    AAAAA    T    U   U  RRRR   EEE                 %
+%               F      E      A   A    T    U   U  R R    E                   %
+%               F      EEEEE  A   A    T     UUU   R  R   EEEEE               %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Feature Methods                       %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/animate.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/compress.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/display.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/feature.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l F e a t u r e s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelFeatures() returns features for each channel in the image in
+%  each of four directions (horizontal, vertical, left and right diagonals)
+%  for the specified distance.  The features include the angular second
+%  moment, contrast, correlation, sum of squares: variance, inverse difference
+%  moment, sum average, sum varience, sum entropy, entropy, difference variance,%  difference entropy, information measures of correlation 1, information
+%  measures of correlation 2, and maximum correlation coefficient.  You can
+%  access the red channel contrast, for example, like this:
+%
+%      channel_features=GetImageChannelFeatures(image,1,exception);
+%      contrast=channel_features[RedChannel].contrast[0];
+%
+%  Use MagickRelinquishMemory() to free the features buffer.
+%
+%  The format of the GetImageChannelFeatures method is:
+%
+%      ChannelFeatures *GetImageChannelFeatures(const Image *image,
+%        const size_t distance,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o distance: the distance.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline ssize_t MagickAbsoluteValue(const ssize_t x)
+{
+  if (x < 0)
+    return(-x);
+  return(x);
+}
+
+MagickExport ChannelFeatures *GetImageChannelFeatures(const Image *image,
+  const size_t distance,ExceptionInfo *exception)
+{
+  typedef struct _ChannelStatistics
+  {
+    DoublePixelPacket
+      direction[4];  /* horizontal, vertical, left and right diagonals */
+  } ChannelStatistics;
+
+  CacheView
+    *image_view;
+
+  ChannelFeatures
+    *channel_features;
+
+  ChannelStatistics
+    **cooccurrence,
+    correlation,
+    *density_x,
+    *density_xy,
+    *density_y,
+    entropy_x,
+    entropy_xy,
+    entropy_xy1,
+    entropy_xy2,
+    entropy_y,
+    mean,
+    **Q,
+    *sum,
+    sum_squares,
+    variance;
+
+  LongPixelPacket
+    gray,
+    *grays;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  ssize_t
+    y,
+    z;
+
+  unsigned int
+    number_grays;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((image->columns < (distance+1)) || (image->rows < (distance+1)))
+    return((ChannelFeatures *) NULL);
+  length=CompositeChannels+1UL;
+  channel_features=(ChannelFeatures *) AcquireQuantumMemory(length,
+    sizeof(*channel_features));
+  if (channel_features == (ChannelFeatures *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(channel_features,0,length*
+    sizeof(*channel_features));
+  /*
+    Form grays.
+  */
+  grays=(LongPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*grays));
+  if (grays == (LongPixelPacket *) NULL)
+    {
+      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
+        channel_features);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(channel_features);
+    }
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    grays[i].red=(~0U);
+    grays[i].green=(~0U);
+    grays[i].blue=(~0U);
+    grays[i].alpha=(~0U);
+    grays[i].black=(~0U);
+  }
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      grays[ScaleQuantumToMap(GetPixelRed(image,p))].red=
+        ScaleQuantumToMap(GetPixelRed(image,p));
+      grays[ScaleQuantumToMap(GetPixelGreen(image,p))].green=
+        ScaleQuantumToMap(GetPixelGreen(image,p));
+      grays[ScaleQuantumToMap(GetPixelBlue(image,p))].blue=
+        ScaleQuantumToMap(GetPixelBlue(image,p));
+      if (image->colorspace == CMYKColorspace)
+        grays[ScaleQuantumToMap(GetPixelBlack(image,p))].black=
+          ScaleQuantumToMap(GetPixelBlack(image,p));
+      if (image->matte != MagickFalse)
+        grays[ScaleQuantumToMap(GetPixelAlpha(image,p))].alpha=
+          ScaleQuantumToMap(GetPixelAlpha(image,p));
+      p+=GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    {
+      grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
+      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
+        channel_features);
+      return(channel_features);
+    }
+  (void) ResetMagickMemory(&gray,0,sizeof(gray));
+  for (i=0; i <= (ssize_t) MaxMap; i++)
+  {
+    if (grays[i].red != ~0U)
+      grays[gray.red++].red=grays[i].red;
+    if (grays[i].green != ~0U)
+      grays[gray.green++].green=grays[i].green;
+    if (grays[i].blue != ~0U)
+      grays[gray.blue++].blue=grays[i].blue;
+    if (image->colorspace == CMYKColorspace)
+      if (grays[i].black != ~0U)
+        grays[gray.black++].black=grays[i].black;
+    if (image->matte != MagickFalse)
+      if (grays[i].alpha != ~0U)
+        grays[gray.alpha++].alpha=grays[i].alpha;
+  }
+  /*
+    Allocate spatial dependence matrix.
+  */
+  number_grays=gray.red;
+  if (gray.green > number_grays)
+    number_grays=gray.green;
+  if (gray.blue > number_grays)
+    number_grays=gray.blue;
+  if (image->colorspace == CMYKColorspace)
+    if (gray.black > number_grays)
+      number_grays=gray.black;
+  if (image->matte != MagickFalse)
+    if (gray.alpha > number_grays)
+      number_grays=gray.alpha;
+  cooccurrence=(ChannelStatistics **) AcquireQuantumMemory(number_grays,
+    sizeof(*cooccurrence));
+  density_x=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
+    sizeof(*density_x));
+  density_xy=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
+    sizeof(*density_xy));
+  density_y=(ChannelStatistics *) AcquireQuantumMemory(2*(number_grays+1),
+    sizeof(*density_y));
+  Q=(ChannelStatistics **) AcquireQuantumMemory(number_grays,sizeof(*Q));
+  sum=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(*sum));
+  if ((cooccurrence == (ChannelStatistics **) NULL) ||
+      (density_x == (ChannelStatistics *) NULL) ||
+      (density_xy == (ChannelStatistics *) NULL) ||
+      (density_y == (ChannelStatistics *) NULL) ||
+      (Q == (ChannelStatistics **) NULL) ||
+      (sum == (ChannelStatistics *) NULL))
+    {
+      if (Q != (ChannelStatistics **) NULL)
+        {
+          for (i=0; i < (ssize_t) number_grays; i++)
+            Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
+          Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
+        }
+      if (sum != (ChannelStatistics *) NULL)
+        sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
+      if (density_y != (ChannelStatistics *) NULL)
+        density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
+      if (density_xy != (ChannelStatistics *) NULL)
+        density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
+      if (density_x != (ChannelStatistics *) NULL)
+        density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
+      if (cooccurrence != (ChannelStatistics **) NULL)
+        {
+          for (i=0; i < (ssize_t) number_grays; i++)
+            cooccurrence[i]=(ChannelStatistics *)
+              RelinquishMagickMemory(cooccurrence[i]);
+          cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(
+            cooccurrence);
+        }
+      grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
+      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
+        channel_features);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(channel_features);
+    }
+  (void) ResetMagickMemory(&correlation,0,sizeof(correlation));
+  (void) ResetMagickMemory(density_x,0,2*(number_grays+1)*sizeof(*density_x));
+  (void) ResetMagickMemory(density_xy,0,2*(number_grays+1)*sizeof(*density_xy));
+  (void) ResetMagickMemory(density_y,0,2*(number_grays+1)*sizeof(*density_y));
+  (void) ResetMagickMemory(&mean,0,sizeof(mean));
+  (void) ResetMagickMemory(sum,0,number_grays*sizeof(*sum));
+  (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares));
+  (void) ResetMagickMemory(density_xy,0,2*number_grays*sizeof(*density_xy));
+  (void) ResetMagickMemory(&entropy_x,0,sizeof(entropy_x));
+  (void) ResetMagickMemory(&entropy_xy,0,sizeof(entropy_xy));
+  (void) ResetMagickMemory(&entropy_xy1,0,sizeof(entropy_xy1));
+  (void) ResetMagickMemory(&entropy_xy2,0,sizeof(entropy_xy2));
+  (void) ResetMagickMemory(&entropy_y,0,sizeof(entropy_y));
+  (void) ResetMagickMemory(&variance,0,sizeof(variance));
+  for (i=0; i < (ssize_t) number_grays; i++)
+  {
+    cooccurrence[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,
+      sizeof(**cooccurrence));
+    Q[i]=(ChannelStatistics *) AcquireQuantumMemory(number_grays,sizeof(**Q));
+    if ((cooccurrence[i] == (ChannelStatistics *) NULL) ||
+        (Q[i] == (ChannelStatistics *) NULL))
+      break;
+    (void) ResetMagickMemory(cooccurrence[i],0,number_grays*
+      sizeof(**cooccurrence));
+    (void) ResetMagickMemory(Q[i],0,number_grays*sizeof(**Q));
+  }
+  if (i < (ssize_t) number_grays)
+    {
+      for (i--; i >= 0; i--)
+      {
+        if (Q[i] != (ChannelStatistics *) NULL)
+          Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
+        if (cooccurrence[i] != (ChannelStatistics *) NULL)
+          cooccurrence[i]=(ChannelStatistics *)
+            RelinquishMagickMemory(cooccurrence[i]);
+      }
+      Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
+      cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
+      sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
+      density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
+      density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
+      density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
+      grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
+      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
+        channel_features);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(channel_features);
+    }
+  /*
+    Initialize spatial dependence matrix.
+  */
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    ssize_t
+      i,
+      offset,
+      u,
+      v;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-(ssize_t) distance,y,image->columns+
+      2*distance,distance+1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    p+=distance*GetPixelChannels(image);;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      for (i=0; i < 4; i++)
+      {
+        switch (i)
+        {
+          case 0:
+          default:
+          {
+            /*
+              Horizontal adjacency.
+            */
+            offset=(ssize_t) distance;
+            break;
+          }
+          case 1:
+          {
+            /*
+              Vertical adjacency.
+            */
+            offset=(ssize_t) (image->columns+2*distance);
+            break;
+          }
+          case 2:
+          {
+            /*
+              Right diagonal adjacency.
+            */
+            offset=(ssize_t) ((image->columns+2*distance)-distance);
+            break;
+          }
+          case 3:
+          {
+            /*
+              Left diagonal adjacency.
+            */
+            offset=(ssize_t) ((image->columns+2*distance)+distance);
+            break;
+          }
+        }
+        u=0;
+        v=0;
+        while (grays[u].red != ScaleQuantumToMap(GetPixelRed(image,p)))
+          u++;
+        while (grays[v].red != ScaleQuantumToMap(GetPixelRed(image,p+offset*GetPixelChannels(image))))
+          v++;
+        cooccurrence[u][v].direction[i].red++;
+        cooccurrence[v][u].direction[i].red++;
+        u=0;
+        v=0;
+        while (grays[u].green != ScaleQuantumToMap(GetPixelGreen(image,p)))
+          u++;
+        while (grays[v].green != ScaleQuantumToMap(GetPixelGreen(image,p+offset*GetPixelChannels(image))))
+          v++;
+        cooccurrence[u][v].direction[i].green++;
+        cooccurrence[v][u].direction[i].green++;
+        u=0;
+        v=0;
+        while (grays[u].blue != ScaleQuantumToMap(GetPixelBlue(image,p)))
+          u++;
+        while (grays[v].blue != ScaleQuantumToMap(GetPixelBlue(image,p+offset*GetPixelChannels(image))))
+          v++;
+        cooccurrence[u][v].direction[i].blue++;
+        cooccurrence[v][u].direction[i].blue++;
+        if (image->colorspace == CMYKColorspace)
+          {
+            u=0;
+            v=0;
+            while (grays[u].black != ScaleQuantumToMap(GetPixelBlack(image,p)))
+              u++;
+            while (grays[v].black != ScaleQuantumToMap(GetPixelBlack(image,p+offset*GetPixelChannels(image))))
+              v++;
+            cooccurrence[u][v].direction[i].black++;
+            cooccurrence[v][u].direction[i].black++;
+          }
+        if (image->matte != MagickFalse)
+          {
+            u=0;
+            v=0;
+            while (grays[u].alpha != ScaleQuantumToMap(GetPixelAlpha(image,p)))
+              u++;
+            while (grays[v].alpha != ScaleQuantumToMap(GetPixelAlpha(image,p+offset*GetPixelChannels(image))))
+              v++;
+            cooccurrence[u][v].direction[i].alpha++;
+            cooccurrence[v][u].direction[i].alpha++;
+          }
+      }
+      p+=GetPixelChannels(image);
+    }
+  }
+  grays=(LongPixelPacket *) RelinquishMagickMemory(grays);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    {
+      for (i=0; i < (ssize_t) number_grays; i++)
+        cooccurrence[i]=(ChannelStatistics *)
+          RelinquishMagickMemory(cooccurrence[i]);
+      cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
+      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
+        channel_features);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(channel_features);
+    }
+  /*
+    Normalize spatial dependence matrix.
+  */
+  for (i=0; i < 4; i++)
+  {
+    double
+      normalize;
+
+    register ssize_t
+      y;
+
+    switch (i)
+    {
+      case 0:
+      default:
+      {
+        /*
+          Horizontal adjacency.
+        */
+        normalize=2.0*image->rows*(image->columns-distance);
+        break;
+      }
+      case 1:
+      {
+        /*
+          Vertical adjacency.
+        */
+        normalize=2.0*(image->rows-distance)*image->columns;
+        break;
+      }
+      case 2:
+      {
+        /*
+          Right diagonal adjacency.
+        */
+        normalize=2.0*(image->rows-distance)*(image->columns-distance);
+        break;
+      }
+      case 3:
+      {
+        /*
+          Left diagonal adjacency.
+        */
+        normalize=2.0*(image->rows-distance)*(image->columns-distance);
+        break;
+      }
+    }
+    normalize=1.0/(fabs((double) normalize) <= MagickEpsilon ? 1.0 : normalize);
+    for (y=0; y < (ssize_t) number_grays; y++)
+    {
+      register ssize_t
+        x;
+
+      for (x=0; x < (ssize_t) number_grays; x++)
+      {
+        cooccurrence[x][y].direction[i].red*=normalize;
+        cooccurrence[x][y].direction[i].green*=normalize;
+        cooccurrence[x][y].direction[i].blue*=normalize;
+        if (image->colorspace == CMYKColorspace)
+          cooccurrence[x][y].direction[i].black*=normalize;
+        if (image->matte != MagickFalse)
+          cooccurrence[x][y].direction[i].alpha*=normalize;
+      }
+    }
+  }
+  /*
+    Compute texture features.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < 4; i++)
+  {
+    register ssize_t
+      y;
+
+    for (y=0; y < (ssize_t) number_grays; y++)
+    {
+      register ssize_t
+        x;
+
+      for (x=0; x < (ssize_t) number_grays; x++)
+      {
+        /*
+          Angular second moment:  measure of homogeneity of the image.
+        */
+        channel_features[RedChannel].angular_second_moment[i]+=
+          cooccurrence[x][y].direction[i].red*
+          cooccurrence[x][y].direction[i].red;
+        channel_features[GreenChannel].angular_second_moment[i]+=
+          cooccurrence[x][y].direction[i].green*
+          cooccurrence[x][y].direction[i].green;
+        channel_features[BlueChannel].angular_second_moment[i]+=
+          cooccurrence[x][y].direction[i].blue*
+          cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          channel_features[BlackChannel].angular_second_moment[i]+=
+            cooccurrence[x][y].direction[i].black*
+            cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          channel_features[OpacityChannel].angular_second_moment[i]+=
+            cooccurrence[x][y].direction[i].alpha*
+            cooccurrence[x][y].direction[i].alpha;
+        /*
+          Correlation: measure of linear-dependencies in the image.
+        */
+        sum[y].direction[i].red+=cooccurrence[x][y].direction[i].red;
+        sum[y].direction[i].green+=cooccurrence[x][y].direction[i].green;
+        sum[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          sum[y].direction[i].black+=cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          sum[y].direction[i].alpha+=cooccurrence[x][y].direction[i].alpha;
+        correlation.direction[i].red+=x*y*cooccurrence[x][y].direction[i].red;
+        correlation.direction[i].green+=x*y*
+          cooccurrence[x][y].direction[i].green;
+        correlation.direction[i].blue+=x*y*
+          cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          correlation.direction[i].black+=x*y*
+            cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          correlation.direction[i].alpha+=x*y*
+            cooccurrence[x][y].direction[i].alpha;
+        /*
+          Inverse Difference Moment.
+        */
+        channel_features[RedChannel].inverse_difference_moment[i]+=
+          cooccurrence[x][y].direction[i].red/((y-x)*(y-x)+1);
+        channel_features[GreenChannel].inverse_difference_moment[i]+=
+          cooccurrence[x][y].direction[i].green/((y-x)*(y-x)+1);
+        channel_features[BlueChannel].inverse_difference_moment[i]+=
+          cooccurrence[x][y].direction[i].blue/((y-x)*(y-x)+1);
+        if (image->colorspace == CMYKColorspace)
+          channel_features[BlackChannel].inverse_difference_moment[i]+=
+            cooccurrence[x][y].direction[i].black/((y-x)*(y-x)+1);
+        if (image->matte != MagickFalse)
+          channel_features[OpacityChannel].inverse_difference_moment[i]+=
+            cooccurrence[x][y].direction[i].alpha/((y-x)*(y-x)+1);
+        /*
+          Sum average.
+        */
+        density_xy[y+x+2].direction[i].red+=
+          cooccurrence[x][y].direction[i].red;
+        density_xy[y+x+2].direction[i].green+=
+          cooccurrence[x][y].direction[i].green;
+        density_xy[y+x+2].direction[i].blue+=
+          cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          density_xy[y+x+2].direction[i].black+=
+            cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          density_xy[y+x+2].direction[i].alpha+=
+            cooccurrence[x][y].direction[i].alpha;
+        /*
+          Entropy.
+        */
+        channel_features[RedChannel].entropy[i]-=
+          cooccurrence[x][y].direction[i].red*
+          log10(cooccurrence[x][y].direction[i].red+MagickEpsilon);
+        channel_features[GreenChannel].entropy[i]-=
+          cooccurrence[x][y].direction[i].green*
+          log10(cooccurrence[x][y].direction[i].green+MagickEpsilon);
+        channel_features[BlueChannel].entropy[i]-=
+          cooccurrence[x][y].direction[i].blue*
+          log10(cooccurrence[x][y].direction[i].blue+MagickEpsilon);
+        if (image->colorspace == CMYKColorspace)
+          channel_features[BlackChannel].entropy[i]-=
+            cooccurrence[x][y].direction[i].black*
+            log10(cooccurrence[x][y].direction[i].black+MagickEpsilon);
+        if (image->matte != MagickFalse)
+          channel_features[OpacityChannel].entropy[i]-=
+            cooccurrence[x][y].direction[i].alpha*
+            log10(cooccurrence[x][y].direction[i].alpha+MagickEpsilon);
+        /*
+          Information Measures of Correlation.
+        */
+        density_x[x].direction[i].red+=cooccurrence[x][y].direction[i].red;
+        density_x[x].direction[i].green+=cooccurrence[x][y].direction[i].green;
+        density_x[x].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
+        if (image->matte != MagickFalse)
+          density_x[x].direction[i].alpha+=
+            cooccurrence[x][y].direction[i].alpha;
+        if (image->colorspace == CMYKColorspace)
+          density_x[x].direction[i].black+=
+            cooccurrence[x][y].direction[i].black;
+        density_y[y].direction[i].red+=cooccurrence[x][y].direction[i].red;
+        density_y[y].direction[i].green+=cooccurrence[x][y].direction[i].green;
+        density_y[y].direction[i].blue+=cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          density_y[y].direction[i].black+=
+            cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          density_y[y].direction[i].alpha+=
+            cooccurrence[x][y].direction[i].alpha;
+      }
+      mean.direction[i].red+=y*sum[y].direction[i].red;
+      sum_squares.direction[i].red+=y*y*sum[y].direction[i].red;
+      mean.direction[i].green+=y*sum[y].direction[i].green;
+      sum_squares.direction[i].green+=y*y*sum[y].direction[i].green;
+      mean.direction[i].blue+=y*sum[y].direction[i].blue;
+      sum_squares.direction[i].blue+=y*y*sum[y].direction[i].blue;
+      if (image->colorspace == CMYKColorspace)
+        {
+          mean.direction[i].black+=y*sum[y].direction[i].black;
+          sum_squares.direction[i].black+=y*y*sum[y].direction[i].black;
+        }
+      if (image->matte != MagickFalse)
+        {
+          mean.direction[i].alpha+=y*sum[y].direction[i].alpha;
+          sum_squares.direction[i].alpha+=y*y*sum[y].direction[i].alpha;
+        }
+    }
+    /*
+      Correlation: measure of linear-dependencies in the image.
+    */
+    channel_features[RedChannel].correlation[i]=
+      (correlation.direction[i].red-mean.direction[i].red*
+      mean.direction[i].red)/(sqrt(sum_squares.direction[i].red-
+      (mean.direction[i].red*mean.direction[i].red))*sqrt(
+      sum_squares.direction[i].red-(mean.direction[i].red*
+      mean.direction[i].red)));
+    channel_features[GreenChannel].correlation[i]=
+      (correlation.direction[i].green-mean.direction[i].green*
+      mean.direction[i].green)/(sqrt(sum_squares.direction[i].green-
+      (mean.direction[i].green*mean.direction[i].green))*sqrt(
+      sum_squares.direction[i].green-(mean.direction[i].green*
+      mean.direction[i].green)));
+    channel_features[BlueChannel].correlation[i]=
+      (correlation.direction[i].blue-mean.direction[i].blue*
+      mean.direction[i].blue)/(sqrt(sum_squares.direction[i].blue-
+      (mean.direction[i].blue*mean.direction[i].blue))*sqrt(
+      sum_squares.direction[i].blue-(mean.direction[i].blue*
+      mean.direction[i].blue)));
+    if (image->colorspace == CMYKColorspace)
+      channel_features[BlackChannel].correlation[i]=
+        (correlation.direction[i].black-mean.direction[i].black*
+        mean.direction[i].black)/(sqrt(sum_squares.direction[i].black-
+        (mean.direction[i].black*mean.direction[i].black))*sqrt(
+        sum_squares.direction[i].black-(mean.direction[i].black*
+        mean.direction[i].black)));
+    if (image->matte != MagickFalse)
+      channel_features[OpacityChannel].correlation[i]=
+        (correlation.direction[i].alpha-mean.direction[i].alpha*
+        mean.direction[i].alpha)/(sqrt(sum_squares.direction[i].alpha-
+        (mean.direction[i].alpha*mean.direction[i].alpha))*sqrt(
+        sum_squares.direction[i].alpha-(mean.direction[i].alpha*
+        mean.direction[i].alpha)));
+  }
+  /*
+    Compute more texture features.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < 4; i++)
+  {
+    register ssize_t
+      x;
+
+    for (x=2; x < (ssize_t) (2*number_grays); x++)
+    {
+      /*
+        Sum average.
+      */
+      channel_features[RedChannel].sum_average[i]+=
+        x*density_xy[x].direction[i].red;
+      channel_features[GreenChannel].sum_average[i]+=
+        x*density_xy[x].direction[i].green;
+      channel_features[BlueChannel].sum_average[i]+=
+        x*density_xy[x].direction[i].blue;
+      if (image->colorspace == CMYKColorspace)
+        channel_features[BlackChannel].sum_average[i]+=
+          x*density_xy[x].direction[i].black;
+      if (image->matte != MagickFalse)
+        channel_features[OpacityChannel].sum_average[i]+=
+          x*density_xy[x].direction[i].alpha;
+      /*
+        Sum entropy.
+      */
+      channel_features[RedChannel].sum_entropy[i]-=
+        density_xy[x].direction[i].red*
+        log10(density_xy[x].direction[i].red+MagickEpsilon);
+      channel_features[GreenChannel].sum_entropy[i]-=
+        density_xy[x].direction[i].green*
+        log10(density_xy[x].direction[i].green+MagickEpsilon);
+      channel_features[BlueChannel].sum_entropy[i]-=
+        density_xy[x].direction[i].blue*
+        log10(density_xy[x].direction[i].blue+MagickEpsilon);
+      if (image->colorspace == CMYKColorspace)
+        channel_features[BlackChannel].sum_entropy[i]-=
+          density_xy[x].direction[i].black*
+          log10(density_xy[x].direction[i].black+MagickEpsilon);
+      if (image->matte != MagickFalse)
+        channel_features[OpacityChannel].sum_entropy[i]-=
+          density_xy[x].direction[i].alpha*
+          log10(density_xy[x].direction[i].alpha+MagickEpsilon);
+      /*
+        Sum variance.
+      */
+      channel_features[RedChannel].sum_variance[i]+=
+        (x-channel_features[RedChannel].sum_entropy[i])*
+        (x-channel_features[RedChannel].sum_entropy[i])*
+        density_xy[x].direction[i].red;
+      channel_features[GreenChannel].sum_variance[i]+=
+        (x-channel_features[GreenChannel].sum_entropy[i])*
+        (x-channel_features[GreenChannel].sum_entropy[i])*
+        density_xy[x].direction[i].green;
+      channel_features[BlueChannel].sum_variance[i]+=
+        (x-channel_features[BlueChannel].sum_entropy[i])*
+        (x-channel_features[BlueChannel].sum_entropy[i])*
+        density_xy[x].direction[i].blue;
+      if (image->colorspace == CMYKColorspace)
+        channel_features[BlackChannel].sum_variance[i]+=
+          (x-channel_features[BlackChannel].sum_entropy[i])*
+          (x-channel_features[BlackChannel].sum_entropy[i])*
+          density_xy[x].direction[i].black;
+      if (image->matte != MagickFalse)
+        channel_features[OpacityChannel].sum_variance[i]+=
+          (x-channel_features[OpacityChannel].sum_entropy[i])*
+          (x-channel_features[OpacityChannel].sum_entropy[i])*
+          density_xy[x].direction[i].alpha;
+    }
+  }
+  /*
+    Compute more texture features.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < 4; i++)
+  {
+    register ssize_t
+      y;
+
+    for (y=0; y < (ssize_t) number_grays; y++)
+    {
+      register ssize_t
+        x;
+
+      for (x=0; x < (ssize_t) number_grays; x++)
+      {
+        /*
+          Sum of Squares: Variance
+        */
+        variance.direction[i].red+=(y-mean.direction[i].red+1)*
+          (y-mean.direction[i].red+1)*cooccurrence[x][y].direction[i].red;
+        variance.direction[i].green+=(y-mean.direction[i].green+1)*
+          (y-mean.direction[i].green+1)*cooccurrence[x][y].direction[i].green;
+        variance.direction[i].blue+=(y-mean.direction[i].blue+1)*
+          (y-mean.direction[i].blue+1)*cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          variance.direction[i].black+=(y-mean.direction[i].black+1)*
+            (y-mean.direction[i].black+1)*cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          variance.direction[i].alpha+=(y-mean.direction[i].alpha+1)*
+            (y-mean.direction[i].alpha+1)*
+            cooccurrence[x][y].direction[i].alpha;
+        /*
+          Sum average / Difference Variance.
+        */
+        density_xy[MagickAbsoluteValue(y-x)].direction[i].red+=
+          cooccurrence[x][y].direction[i].red;
+        density_xy[MagickAbsoluteValue(y-x)].direction[i].green+=
+          cooccurrence[x][y].direction[i].green;
+        density_xy[MagickAbsoluteValue(y-x)].direction[i].blue+=
+          cooccurrence[x][y].direction[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          density_xy[MagickAbsoluteValue(y-x)].direction[i].black+=
+            cooccurrence[x][y].direction[i].black;
+        if (image->matte != MagickFalse)
+          density_xy[MagickAbsoluteValue(y-x)].direction[i].alpha+=
+            cooccurrence[x][y].direction[i].alpha;
+        /*
+          Information Measures of Correlation.
+        */
+        entropy_xy.direction[i].red-=cooccurrence[x][y].direction[i].red*
+          log10(cooccurrence[x][y].direction[i].red+MagickEpsilon);
+        entropy_xy.direction[i].green-=cooccurrence[x][y].direction[i].green*
+          log10(cooccurrence[x][y].direction[i].green+MagickEpsilon);
+        entropy_xy.direction[i].blue-=cooccurrence[x][y].direction[i].blue*
+          log10(cooccurrence[x][y].direction[i].blue+MagickEpsilon);
+        if (image->colorspace == CMYKColorspace)
+          entropy_xy.direction[i].black-=cooccurrence[x][y].direction[i].black*
+            log10(cooccurrence[x][y].direction[i].black+MagickEpsilon);
+        if (image->matte != MagickFalse)
+          entropy_xy.direction[i].alpha-=
+            cooccurrence[x][y].direction[i].alpha*log10(
+            cooccurrence[x][y].direction[i].alpha+MagickEpsilon);
+        entropy_xy1.direction[i].red-=(cooccurrence[x][y].direction[i].red*
+          log10(density_x[x].direction[i].red*density_y[y].direction[i].red+
+          MagickEpsilon));
+        entropy_xy1.direction[i].green-=(cooccurrence[x][y].direction[i].green*
+          log10(density_x[x].direction[i].green*density_y[y].direction[i].green+
+          MagickEpsilon));
+        entropy_xy1.direction[i].blue-=(cooccurrence[x][y].direction[i].blue*
+          log10(density_x[x].direction[i].blue*density_y[y].direction[i].blue+
+          MagickEpsilon));
+        if (image->colorspace == CMYKColorspace)
+          entropy_xy1.direction[i].black-=(
+            cooccurrence[x][y].direction[i].black*log10(
+            density_x[x].direction[i].black*density_y[y].direction[i].black+
+            MagickEpsilon));
+        if (image->matte != MagickFalse)
+          entropy_xy1.direction[i].alpha-=(
+            cooccurrence[x][y].direction[i].alpha*log10(
+            density_x[x].direction[i].alpha*density_y[y].direction[i].alpha+
+            MagickEpsilon));
+        entropy_xy2.direction[i].red-=(density_x[x].direction[i].red*
+          density_y[y].direction[i].red*log10(density_x[x].direction[i].red*
+          density_y[y].direction[i].red+MagickEpsilon));
+        entropy_xy2.direction[i].green-=(density_x[x].direction[i].green*
+          density_y[y].direction[i].green*log10(density_x[x].direction[i].green*
+          density_y[y].direction[i].green+MagickEpsilon));
+        entropy_xy2.direction[i].blue-=(density_x[x].direction[i].blue*
+          density_y[y].direction[i].blue*log10(density_x[x].direction[i].blue*
+          density_y[y].direction[i].blue+MagickEpsilon));
+        if (image->colorspace == CMYKColorspace)
+          entropy_xy2.direction[i].black-=(density_x[x].direction[i].black*
+            density_y[y].direction[i].black*log10(
+            density_x[x].direction[i].black*density_y[y].direction[i].black+
+            MagickEpsilon));
+        if (image->matte != MagickFalse)
+          entropy_xy2.direction[i].alpha-=(density_x[x].direction[i].alpha*
+            density_y[y].direction[i].alpha*log10(
+            density_x[x].direction[i].alpha*density_y[y].direction[i].alpha+
+            MagickEpsilon));
+      }
+    }
+    channel_features[RedChannel].variance_sum_of_squares[i]=
+      variance.direction[i].red;
+    channel_features[GreenChannel].variance_sum_of_squares[i]=
+      variance.direction[i].green;
+    channel_features[BlueChannel].variance_sum_of_squares[i]=
+      variance.direction[i].blue;
+    if (image->colorspace == CMYKColorspace)
+      channel_features[RedChannel].variance_sum_of_squares[i]=
+        variance.direction[i].black;
+    if (image->matte != MagickFalse)
+      channel_features[RedChannel].variance_sum_of_squares[i]=
+        variance.direction[i].alpha;
+  }
+  /*
+    Compute more texture features.
+  */
+  (void) ResetMagickMemory(&variance,0,sizeof(variance));
+  (void) ResetMagickMemory(&sum_squares,0,sizeof(sum_squares));
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < 4; i++)
+  {
+    register ssize_t
+      x;
+
+    for (x=0; x < (ssize_t) number_grays; x++)
+    {
+      /*
+        Difference variance.
+      */
+      variance.direction[i].red+=density_xy[x].direction[i].red;
+      variance.direction[i].green+=density_xy[x].direction[i].green;
+      variance.direction[i].blue+=density_xy[x].direction[i].blue;
+      if (image->colorspace == CMYKColorspace)
+        variance.direction[i].black+=density_xy[x].direction[i].black;
+      if (image->matte != MagickFalse)
+        variance.direction[i].alpha+=density_xy[x].direction[i].alpha;
+      sum_squares.direction[i].red+=density_xy[x].direction[i].red*
+        density_xy[x].direction[i].red;
+      sum_squares.direction[i].green+=density_xy[x].direction[i].green*
+        density_xy[x].direction[i].green;
+      sum_squares.direction[i].blue+=density_xy[x].direction[i].blue*
+        density_xy[x].direction[i].blue;
+      if (image->colorspace == CMYKColorspace)
+        sum_squares.direction[i].black+=density_xy[x].direction[i].black*
+          density_xy[x].direction[i].black;
+      if (image->matte != MagickFalse)
+        sum_squares.direction[i].alpha+=density_xy[x].direction[i].alpha*
+          density_xy[x].direction[i].alpha;
+      /*
+        Difference entropy.
+      */
+      channel_features[RedChannel].difference_entropy[i]-=
+        density_xy[x].direction[i].red*
+        log10(density_xy[x].direction[i].red+MagickEpsilon);
+      channel_features[GreenChannel].difference_entropy[i]-=
+        density_xy[x].direction[i].green*
+        log10(density_xy[x].direction[i].green+MagickEpsilon);
+      channel_features[BlueChannel].difference_entropy[i]-=
+        density_xy[x].direction[i].blue*
+        log10(density_xy[x].direction[i].blue+MagickEpsilon);
+      if (image->colorspace == CMYKColorspace)
+        channel_features[BlackChannel].difference_entropy[i]-=
+          density_xy[x].direction[i].black*
+          log10(density_xy[x].direction[i].black+MagickEpsilon);
+      if (image->matte != MagickFalse)
+        channel_features[OpacityChannel].difference_entropy[i]-=
+          density_xy[x].direction[i].alpha*
+          log10(density_xy[x].direction[i].alpha+MagickEpsilon);
+      /*
+        Information Measures of Correlation.
+      */
+      entropy_x.direction[i].red-=(density_x[x].direction[i].red*
+        log10(density_x[x].direction[i].red+MagickEpsilon));
+      entropy_x.direction[i].green-=(density_x[x].direction[i].green*
+        log10(density_x[x].direction[i].green+MagickEpsilon));
+      entropy_x.direction[i].blue-=(density_x[x].direction[i].blue*
+        log10(density_x[x].direction[i].blue+MagickEpsilon));
+      if (image->colorspace == CMYKColorspace)
+        entropy_x.direction[i].black-=(density_x[x].direction[i].black*
+          log10(density_x[x].direction[i].black+MagickEpsilon));
+      if (image->matte != MagickFalse)
+        entropy_x.direction[i].alpha-=(density_x[x].direction[i].alpha*
+          log10(density_x[x].direction[i].alpha+MagickEpsilon));
+      entropy_y.direction[i].red-=(density_y[x].direction[i].red*
+        log10(density_y[x].direction[i].red+MagickEpsilon));
+      entropy_y.direction[i].green-=(density_y[x].direction[i].green*
+        log10(density_y[x].direction[i].green+MagickEpsilon));
+      entropy_y.direction[i].blue-=(density_y[x].direction[i].blue*
+        log10(density_y[x].direction[i].blue+MagickEpsilon));
+      if (image->colorspace == CMYKColorspace)
+        entropy_y.direction[i].black-=(density_y[x].direction[i].black*
+          log10(density_y[x].direction[i].black+MagickEpsilon));
+      if (image->matte != MagickFalse)
+        entropy_y.direction[i].alpha-=(density_y[x].direction[i].alpha*
+          log10(density_y[x].direction[i].alpha+MagickEpsilon));
+    }
+    /*
+      Difference variance.
+    */
+    channel_features[RedChannel].difference_variance[i]=
+      (((double) number_grays*number_grays*sum_squares.direction[i].red)-
+      (variance.direction[i].red*variance.direction[i].red))/
+      ((double) number_grays*number_grays*number_grays*number_grays);
+    channel_features[GreenChannel].difference_variance[i]=
+      (((double) number_grays*number_grays*sum_squares.direction[i].green)-
+      (variance.direction[i].green*variance.direction[i].green))/
+      ((double) number_grays*number_grays*number_grays*number_grays);
+    channel_features[BlueChannel].difference_variance[i]=
+      (((double) number_grays*number_grays*sum_squares.direction[i].blue)-
+      (variance.direction[i].blue*variance.direction[i].blue))/
+      ((double) number_grays*number_grays*number_grays*number_grays);
+    if (image->colorspace == CMYKColorspace)
+      channel_features[BlackChannel].difference_variance[i]=
+        (((double) number_grays*number_grays*sum_squares.direction[i].black)-
+        (variance.direction[i].black*variance.direction[i].black))/
+        ((double) number_grays*number_grays*number_grays*number_grays);
+    if (image->matte != MagickFalse)
+      channel_features[OpacityChannel].difference_variance[i]=
+        (((double) number_grays*number_grays*sum_squares.direction[i].alpha)-
+        (variance.direction[i].alpha*variance.direction[i].alpha))/
+        ((double) number_grays*number_grays*number_grays*number_grays);
+    /*
+      Information Measures of Correlation.
+    */
+    channel_features[RedChannel].measure_of_correlation_1[i]=
+      (entropy_xy.direction[i].red-entropy_xy1.direction[i].red)/
+      (entropy_x.direction[i].red > entropy_y.direction[i].red ?
+       entropy_x.direction[i].red : entropy_y.direction[i].red);
+    channel_features[GreenChannel].measure_of_correlation_1[i]=
+      (entropy_xy.direction[i].green-entropy_xy1.direction[i].green)/
+      (entropy_x.direction[i].green > entropy_y.direction[i].green ?
+       entropy_x.direction[i].green : entropy_y.direction[i].green);
+    channel_features[BlueChannel].measure_of_correlation_1[i]=
+      (entropy_xy.direction[i].blue-entropy_xy1.direction[i].blue)/
+      (entropy_x.direction[i].blue > entropy_y.direction[i].blue ?
+       entropy_x.direction[i].blue : entropy_y.direction[i].blue);
+    if (image->colorspace == CMYKColorspace)
+      channel_features[BlackChannel].measure_of_correlation_1[i]=
+        (entropy_xy.direction[i].black-entropy_xy1.direction[i].black)/
+        (entropy_x.direction[i].black > entropy_y.direction[i].black ?
+         entropy_x.direction[i].black : entropy_y.direction[i].black);
+    if (image->matte != MagickFalse)
+      channel_features[OpacityChannel].measure_of_correlation_1[i]=
+        (entropy_xy.direction[i].alpha-entropy_xy1.direction[i].alpha)/
+        (entropy_x.direction[i].alpha > entropy_y.direction[i].alpha ?
+         entropy_x.direction[i].alpha : entropy_y.direction[i].alpha);
+    channel_features[RedChannel].measure_of_correlation_2[i]=
+      (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].red-
+      entropy_xy.direction[i].red)))));
+    channel_features[GreenChannel].measure_of_correlation_2[i]=
+      (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].green-
+      entropy_xy.direction[i].green)))));
+    channel_features[BlueChannel].measure_of_correlation_2[i]=
+      (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].blue-
+      entropy_xy.direction[i].blue)))));
+    if (image->colorspace == CMYKColorspace)
+      channel_features[BlackChannel].measure_of_correlation_2[i]=
+        (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].black-
+        entropy_xy.direction[i].black)))));
+    if (image->matte != MagickFalse)
+      channel_features[OpacityChannel].measure_of_correlation_2[i]=
+        (sqrt(fabs(1.0-exp(-2.0*(entropy_xy2.direction[i].alpha-
+        entropy_xy.direction[i].alpha)))));
+  }
+  /*
+    Compute more texture features.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (i=0; i < 4; i++)
+  {
+    for (z=0; z < (ssize_t) number_grays; z++)
+    {
+      register ssize_t
+        y;
+
+      ChannelStatistics
+        pixel;
+
+      (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
+      for (y=0; y < (ssize_t) number_grays; y++)
+      {
+        register ssize_t
+          x;
+
+        for (x=0; x < (ssize_t) number_grays; x++)
+        {
+          /*
+            Contrast:  amount of local variations present in an image.
+          */
+          if (((y-x) == z) || ((x-y) == z))
+            {
+              pixel.direction[i].red+=cooccurrence[x][y].direction[i].red;
+              pixel.direction[i].green+=cooccurrence[x][y].direction[i].green;
+              pixel.direction[i].blue+=cooccurrence[x][y].direction[i].blue;
+              if (image->colorspace == CMYKColorspace)
+                pixel.direction[i].black+=cooccurrence[x][y].direction[i].black;
+              if (image->matte != MagickFalse)
+                pixel.direction[i].alpha+=
+                  cooccurrence[x][y].direction[i].alpha;
+            }
+          /*
+            Maximum Correlation Coefficient.
+          */
+          Q[z][y].direction[i].red+=cooccurrence[z][x].direction[i].red*
+            cooccurrence[y][x].direction[i].red/density_x[z].direction[i].red/
+            density_y[x].direction[i].red;
+          Q[z][y].direction[i].green+=cooccurrence[z][x].direction[i].green*
+            cooccurrence[y][x].direction[i].green/
+            density_x[z].direction[i].green/density_y[x].direction[i].red;
+          Q[z][y].direction[i].blue+=cooccurrence[z][x].direction[i].blue*
+            cooccurrence[y][x].direction[i].blue/density_x[z].direction[i].blue/
+            density_y[x].direction[i].blue;
+          if (image->colorspace == CMYKColorspace)
+            Q[z][y].direction[i].black+=cooccurrence[z][x].direction[i].black*
+              cooccurrence[y][x].direction[i].black/
+              density_x[z].direction[i].black/density_y[x].direction[i].black;
+          if (image->matte != MagickFalse)
+            Q[z][y].direction[i].alpha+=
+              cooccurrence[z][x].direction[i].alpha*
+              cooccurrence[y][x].direction[i].alpha/
+              density_x[z].direction[i].alpha/
+              density_y[x].direction[i].alpha;
+        }
+      }
+      channel_features[RedChannel].contrast[i]+=z*z*pixel.direction[i].red;
+      channel_features[GreenChannel].contrast[i]+=z*z*pixel.direction[i].green;
+      channel_features[BlueChannel].contrast[i]+=z*z*pixel.direction[i].blue;
+      if (image->colorspace == CMYKColorspace)
+        channel_features[BlackChannel].contrast[i]+=z*z*
+          pixel.direction[i].black;
+      if (image->matte != MagickFalse)
+        channel_features[OpacityChannel].contrast[i]+=z*z*
+          pixel.direction[i].alpha;
+    }
+    /*
+      Maximum Correlation Coefficient.
+      Future: return second largest eigenvalue of Q.
+    */
+    channel_features[RedChannel].maximum_correlation_coefficient[i]=
+      sqrt((double) -1.0);
+    channel_features[GreenChannel].maximum_correlation_coefficient[i]=
+      sqrt((double) -1.0);
+    channel_features[BlueChannel].maximum_correlation_coefficient[i]=
+      sqrt((double) -1.0);
+    if (image->colorspace == CMYKColorspace)
+      channel_features[BlackChannel].maximum_correlation_coefficient[i]=
+        sqrt((double) -1.0);
+    if (image->matte != MagickFalse)
+      channel_features[OpacityChannel].maximum_correlation_coefficient[i]=
+        sqrt((double) -1.0);
+  }
+  /*
+    Relinquish resources.
+  */
+  sum=(ChannelStatistics *) RelinquishMagickMemory(sum);
+  for (i=0; i < (ssize_t) number_grays; i++)
+    Q[i]=(ChannelStatistics *) RelinquishMagickMemory(Q[i]);
+  Q=(ChannelStatistics **) RelinquishMagickMemory(Q);
+  density_y=(ChannelStatistics *) RelinquishMagickMemory(density_y);
+  density_xy=(ChannelStatistics *) RelinquishMagickMemory(density_xy);
+  density_x=(ChannelStatistics *) RelinquishMagickMemory(density_x);
+  for (i=0; i < (ssize_t) number_grays; i++)
+    cooccurrence[i]=(ChannelStatistics *)
+      RelinquishMagickMemory(cooccurrence[i]);
+  cooccurrence=(ChannelStatistics **) RelinquishMagickMemory(cooccurrence);
+  return(channel_features);
+}
diff --git a/MagickCore/feature.h b/MagickCore/feature.h
new file mode 100644
index 0000000..7f8d1e5
--- /dev/null
+++ b/MagickCore/feature.h
@@ -0,0 +1,54 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore feature methods.
+*/
+#ifndef _MAGICKCORE_FEATURE_H
+#define _MAGICKCORE_FEATURE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+  Haralick texture features.
+*/
+typedef struct _ChannelFeatures
+{
+  double
+    angular_second_moment[4],
+    contrast[4],
+    correlation[4],
+    variance_sum_of_squares[4],
+    inverse_difference_moment[4],
+    sum_average[4],
+    sum_variance[4],
+    sum_entropy[4],
+    entropy[4],
+    difference_variance[4],
+    difference_entropy[4],
+    measure_of_correlation_1[4],
+    measure_of_correlation_2[4],
+    maximum_correlation_coefficient[4];
+} ChannelFeatures;
+
+extern MagickExport ChannelFeatures
+  *GetImageChannelFeatures(const Image *,const size_t,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/fourier.c b/MagickCore/fourier.c
new file mode 100644
index 0000000..b7fbf67
--- /dev/null
+++ b/MagickCore/fourier.c
@@ -0,0 +1,1336 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               FFFFF   OOO   U   U  RRRR   IIIII  EEEEE  RRRR                %
+%               F      O   O  U   U  R   R    I    E      R   R               %
+%               FFF    O   O  U   U  RRRR     I    EEE    RRRR                %
+%               F      O   O  U   U  R R      I    E      R R                 %
+%               F       OOO    UUU   R  R   IIIII  EEEEE  R  R                %
+%                                                                             %
+%                                                                             %
+%                MagickCore Discrete Fourier Transform Methods                %
+%                                                                             %
+%                              Software Design                                %
+%                                Sean Burke                                   %
+%                               Fred Weinhaus                                 %
+%                                John Cristy                                  %
+%                                 July 2009                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/fourier.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/thread-private.h"
+#if defined(MAGICKCORE_FFTW_DELEGATE)
+#if defined(MAGICKCORE_HAVE_COMPLEX_H)
+#include <complex.h>
+#endif
+#include <fftw3.h>
+#if !defined(MAGICKCORE_HAVE_CABS)
+#define cabs(z)  (sqrt(z[0]*z[0]+z[1]*z[1]))
+#endif
+#if !defined(MAGICKCORE_HAVE_CARG)
+#define carg(z)  (atan2(cimag(z),creal(z)))
+#endif
+#if !defined(MAGICKCORE_HAVE_CIMAG)
+#define cimag(z)  (z[1])
+#endif
+#if !defined(MAGICKCORE_HAVE_CREAL)
+#define creal(z)  (z[0])
+#endif
+#endif
+
+/*
+  Typedef declarations.
+*/
+typedef struct _FourierInfo
+{
+  ChannelType
+    channel;
+
+  MagickBooleanType
+    modulus;
+
+  size_t
+    width,
+    height;
+
+  ssize_t
+    center;
+} FourierInfo;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     F o r w a r d F o u r i e r T r a n s f o r m I m a g e                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ForwardFourierTransformImage() implements the discrete Fourier transform
+%  (DFT) of the image either as a magnitude / phase or real / imaginary image
+%  pair.
+%
+%  The format of the ForwadFourierTransformImage method is:
+%
+%      Image *ForwardFourierTransformImage(const Image *image,
+%        const MagickBooleanType modulus,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o modulus: if true, return as transform as a magnitude / phase pair
+%      otherwise a real / imaginary image pair.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(MAGICKCORE_FFTW_DELEGATE)
+
+static MagickBooleanType RollFourier(const size_t width,const size_t height,
+  const ssize_t x_offset,const ssize_t y_offset,double *fourier)
+{
+  double
+    *roll;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    u,
+    v,
+    y;
+
+  /*
+    Move zero frequency (DC, average color) from (0,0) to (width/2,height/2).
+  */
+  roll=(double *) AcquireQuantumMemory((size_t) height,width*sizeof(*roll));
+  if (roll == (double *) NULL)
+    return(MagickFalse);
+  i=0L;
+  for (y=0L; y < (ssize_t) height; y++)
+  {
+    if (y_offset < 0L)
+      v=((y+y_offset) < 0L) ? y+y_offset+(ssize_t) height : y+y_offset;
+    else
+      v=((y+y_offset) > ((ssize_t) height-1L)) ? y+y_offset-(ssize_t) height :
+        y+y_offset;
+    for (x=0L; x < (ssize_t) width; x++)
+    {
+      if (x_offset < 0L)
+        u=((x+x_offset) < 0L) ? x+x_offset+(ssize_t) width : x+x_offset;
+      else
+        u=((x+x_offset) > ((ssize_t) width-1L)) ? x+x_offset-(ssize_t) width :
+          x+x_offset;
+      roll[v*width+u]=fourier[i++];
+    }
+  }
+  (void) CopyMagickMemory(fourier,roll,height*width*sizeof(*roll));
+  roll=(double *) RelinquishMagickMemory(roll);
+  return(MagickTrue);
+}
+
+static MagickBooleanType ForwardQuadrantSwap(const size_t width,
+  const size_t height,double *source,double *destination)
+{
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    x;
+
+  ssize_t
+    center,
+    y;
+
+  /*
+    Swap quadrants.
+  */
+  center=(ssize_t) floor((double) width/2L)+1L;
+  status=RollFourier((size_t) center,height,0L,(ssize_t) height/2L,source);
+  if (status == MagickFalse)
+    return(MagickFalse);
+  for (y=0L; y < (ssize_t) height; y++)
+    for (x=0L; x < (ssize_t) (width/2L-1L); x++)
+      destination[width*y+x+width/2L]=source[center*y+x];
+  for (y=1; y < (ssize_t) height; y++)
+    for (x=0L; x < (ssize_t) (width/2L-1L); x++)
+      destination[width*(height-y)+width/2L-x-1L]=source[center*y+x+1L];
+  for (x=0L; x < (ssize_t) (width/2L); x++)
+    destination[-x+width/2L-1L]=destination[x+width/2L+1L];
+  return(MagickTrue);
+}
+
+static void CorrectPhaseLHS(const size_t width,const size_t height,
+  double *fourier)
+{
+  register ssize_t
+    x;
+
+  ssize_t
+    y;
+
+  for (y=0L; y < (ssize_t) height; y++)
+    for (x=0L; x < (ssize_t) (width/2L); x++)
+      fourier[y*width+x]*=(-1.0);
+}
+
+static MagickBooleanType ForwardFourier(const FourierInfo *fourier_info,
+  Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
+{
+  CacheView
+    *magnitude_view,
+    *phase_view;
+
+  double
+    *magnitude_source,
+    *phase_source;
+
+  Image
+    *magnitude_image,
+    *phase_image;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    x;
+
+  register Quantum
+    *q;
+
+  ssize_t
+    i,
+    y;
+
+  magnitude_image=GetFirstImageInList(image);
+  phase_image=GetNextImageInList(image);
+  if (phase_image == (Image *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+        "ImageSequenceRequired","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  /*
+    Create "Fourier Transform" image from constituent arrays.
+  */
+  magnitude_source=(double *) AcquireQuantumMemory((size_t)
+    fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
+  if (magnitude_source == (double *) NULL)
+    return(MagickFalse);
+  (void) ResetMagickMemory(magnitude_source,0,fourier_info->height*
+    fourier_info->width*sizeof(*magnitude_source));
+  phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->width*sizeof(*phase_source));
+  if (phase_source == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
+      return(MagickFalse);
+    }
+  status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,
+    magnitude,magnitude_source);
+  if (status != MagickFalse)
+    status=ForwardQuadrantSwap(fourier_info->height,fourier_info->height,phase,
+      phase_source);
+  CorrectPhaseLHS(fourier_info->height,fourier_info->height,phase_source);
+  if (fourier_info->modulus != MagickFalse)
+    {
+      i=0L;
+      for (y=0L; y < (ssize_t) fourier_info->height; y++)
+        for (x=0L; x < (ssize_t) fourier_info->width; x++)
+        {
+          phase_source[i]/=(2.0*MagickPI);
+          phase_source[i]+=0.5;
+          i++;
+        }
+    }
+  magnitude_view=AcquireCacheView(magnitude_image);
+  phase_view=AcquireCacheView(phase_image);
+  i=0L;
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+  {
+    q=GetCacheViewAuthenticPixels(magnitude_view,0L,y,fourier_info->height,1UL,
+      exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0L; x < (ssize_t) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          SetPixelRed(magnitude_image,ClampToQuantum(QuantumRange*
+            magnitude_source[i]),q);
+          break;
+        }
+        case GreenChannel:
+        {
+          SetPixelGreen(magnitude_image,ClampToQuantum(QuantumRange*
+            magnitude_source[i]),q);
+          break;
+        }
+        case BlueChannel:
+        {
+          SetPixelBlue(magnitude_image,ClampToQuantum(QuantumRange*
+            magnitude_source[i]),q);
+          break;
+        }
+        case BlackChannel:
+        {
+          SetPixelBlack(magnitude_image,ClampToQuantum(QuantumRange*
+            magnitude_source[i]),q);
+          break;
+        }
+        case AlphaChannel:
+        {
+          SetPixelAlpha(magnitude_image,ClampToQuantum(QuantumRange*
+            magnitude_source[i]),q);
+          break;
+        }
+        case GrayChannels:
+        {
+          SetPixelGray(magnitude_image,ClampToQuantum(QuantumRange*
+            magnitude_source[i]),q);
+          break;
+        }
+      }
+      i++;
+      q+=GetPixelChannels(magnitude_image);
+    }
+    status=SyncCacheViewAuthenticPixels(magnitude_view,exception);
+    if (status == MagickFalse)
+      break;
+  }
+  i=0L;
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+  {
+    q=GetCacheViewAuthenticPixels(phase_view,0L,y,fourier_info->height,1UL,
+      exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0L; x < (ssize_t) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          SetPixelRed(phase_image,ClampToQuantum(QuantumRange*
+            phase_source[i]),q);
+          break;
+        }
+        case GreenChannel:
+        {
+          SetPixelGreen(phase_image,ClampToQuantum(QuantumRange*
+            phase_source[i]),q);
+          break;
+        }
+        case BlueChannel:
+        {
+          SetPixelBlue(phase_image,ClampToQuantum(QuantumRange*
+            phase_source[i]),q);
+          break;
+        }
+        case BlackChannel:
+        {
+          SetPixelBlack(phase_image,ClampToQuantum(QuantumRange*
+            phase_source[i]),q);
+          break;
+        }
+        case AlphaChannel:
+        {
+          SetPixelAlpha(phase_image,ClampToQuantum(QuantumRange*
+            phase_source[i]),q);
+          break;
+        }
+        case GrayChannels:
+        {
+          SetPixelGray(phase_image,ClampToQuantum(QuantumRange*
+            phase_source[i]),q);
+          break;
+        }
+      }
+      i++;
+      q+=GetPixelChannels(phase_image);
+    }
+    status=SyncCacheViewAuthenticPixels(phase_view,exception);
+    if (status == MagickFalse)
+      break;
+   }
+  phase_view=DestroyCacheView(phase_view);
+  magnitude_view=DestroyCacheView(magnitude_view);
+  phase_source=(double *) RelinquishMagickMemory(phase_source);
+  magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
+  return(status);
+}
+
+static MagickBooleanType ForwardFourierTransform(FourierInfo *fourier_info,
+  const Image *image,double *magnitude,double *phase,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  double
+    n,
+    *source;
+
+  fftw_complex
+    *fourier;
+
+  fftw_plan
+    fftw_r2c_plan;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    y;
+
+  /*
+    Generate the forward Fourier transform.
+  */
+  source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->width*sizeof(*source));
+  if (source == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  ResetMagickMemory(source,0,fourier_info->height*fourier_info->width*
+    sizeof(*source));
+  i=0L;
+  image_view=AcquireCacheView(image);
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0L,y,fourier_info->width,1UL,
+      exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0L; x < (ssize_t) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          source[i]=QuantumScale*GetPixelRed(image,p);
+          break;
+        }
+        case GreenChannel:
+        {
+          source[i]=QuantumScale*GetPixelGreen(image,p);
+          break;
+        }
+        case BlueChannel:
+        {
+          source[i]=QuantumScale*GetPixelBlue(image,p);
+          break;
+        }
+        case BlackChannel:
+        {
+          source[i]=QuantumScale*GetPixelBlack(image,p);
+          break;
+        }
+        case AlphaChannel:
+        {
+          source[i]=QuantumScale*GetPixelAlpha(image,p);
+          break;
+        }
+        case GrayChannels:
+        {
+          source[i]=QuantumScale*GetPixelGray(image,p);
+          break;
+        }
+      }
+      i++;
+      p+=GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->center*sizeof(*fourier));
+  if (fourier == (fftw_complex *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      source=(double *) RelinquishMagickMemory(source);
+      return(MagickFalse);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ForwardFourierTransform)
+#endif
+  fftw_r2c_plan=fftw_plan_dft_r2c_2d(fourier_info->width,fourier_info->width,
+    source,fourier,FFTW_ESTIMATE);
+  fftw_execute(fftw_r2c_plan);
+  fftw_destroy_plan(fftw_r2c_plan);
+  source=(double *) RelinquishMagickMemory(source);
+  /*
+    Normalize Fourier transform.
+  */
+  n=(double) fourier_info->width*(double) fourier_info->width;
+  i=0L;
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+    for (x=0L; x < (ssize_t) fourier_info->center; x++)
+    {
+#if defined(MAGICKCORE_HAVE_COMPLEX_H)
+      fourier[i]/=n;
+#else
+      fourier[i][0]/=n;
+      fourier[i][1]/=n;
+#endif
+      i++;
+    }
+  /*
+    Generate magnitude and phase (or real and imaginary).
+  */
+  i=0L;
+  if (fourier_info->modulus != MagickFalse)
+    for (y=0L; y < (ssize_t) fourier_info->height; y++)
+      for (x=0L; x < (ssize_t) fourier_info->center; x++)
+      {
+        magnitude[i]=cabs(fourier[i]);
+        phase[i]=carg(fourier[i]);
+        i++;
+      }
+  else
+    for (y=0L; y < (ssize_t) fourier_info->height; y++)
+      for (x=0L; x < (ssize_t) fourier_info->center; x++)
+      {
+        magnitude[i]=creal(fourier[i]);
+        phase[i]=cimag(fourier[i]);
+        i++;
+      }
+  fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
+  return(MagickTrue);
+}
+
+static MagickBooleanType ForwardFourierTransformChannel(const Image *image,
+  const ChannelType channel,const MagickBooleanType modulus,
+  Image *fourier_image,ExceptionInfo *exception)
+{
+  double
+    *magnitude,
+    *phase;
+
+  fftw_complex
+    *fourier;
+
+  FourierInfo
+    fourier_info;
+
+  MagickBooleanType
+    status;
+
+  size_t
+    extent;
+
+  fourier_info.width=image->columns;
+  if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
+      ((image->rows % 2) != 0))
+    {
+      extent=image->columns < image->rows ? image->rows : image->columns;
+      fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
+    }
+  fourier_info.height=fourier_info.width;
+  fourier_info.center=(ssize_t) floor((double) fourier_info.width/2.0)+1L;
+  fourier_info.channel=channel;
+  fourier_info.modulus=modulus;
+  magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*magnitude));
+  if (magnitude == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*phase));
+  if (phase == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      magnitude=(double *) RelinquishMagickMemory(magnitude);
+      return(MagickFalse);
+    }
+  fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*fourier));
+  if (fourier == (fftw_complex *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      phase=(double *) RelinquishMagickMemory(phase);
+      magnitude=(double *) RelinquishMagickMemory(magnitude);
+      return(MagickFalse);
+    }
+  status=ForwardFourierTransform(&fourier_info,image,magnitude,phase,exception);
+  if (status != MagickFalse)
+    status=ForwardFourier(&fourier_info,fourier_image,magnitude,phase,
+      exception);
+  fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
+  phase=(double *) RelinquishMagickMemory(phase);
+  magnitude=(double *) RelinquishMagickMemory(magnitude);
+  return(status);
+}
+#endif
+
+MagickExport Image *ForwardFourierTransformImage(const Image *image,
+  const MagickBooleanType modulus,ExceptionInfo *exception)
+{
+  Image
+    *fourier_image;
+
+  fourier_image=NewImageList();
+#if !defined(MAGICKCORE_FFTW_DELEGATE)
+  (void) modulus;
+  (void) ThrowMagickException(exception,GetMagickModule(),
+    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
+    image->filename);
+#else
+  {
+    Image
+      *magnitude_image;
+
+    size_t
+      extent,
+      width;
+
+    width=image->columns;
+    if ((image->columns != image->rows) || ((image->columns % 2) != 0) ||
+        ((image->rows % 2) != 0))
+      {
+        extent=image->columns < image->rows ? image->rows : image->columns;
+        width=(extent & 0x01) == 1 ? extent+1UL : extent;
+      }
+    magnitude_image=CloneImage(image,width,width,MagickFalse,exception);
+    if (magnitude_image != (Image *) NULL)
+      {
+        Image
+          *phase_image;
+
+        magnitude_image->storage_class=DirectClass;
+        magnitude_image->depth=32UL;
+        phase_image=CloneImage(image,width,width,MagickFalse,exception);
+        if (phase_image == (Image *) NULL)
+          magnitude_image=DestroyImage(magnitude_image);
+        else
+          {
+            MagickBooleanType
+              is_gray,
+              status;
+
+            phase_image->storage_class=DirectClass;
+            phase_image->depth=32UL;
+            AppendImageToList(&fourier_image,magnitude_image);
+            AppendImageToList(&fourier_image,phase_image);
+            status=MagickTrue;
+            is_gray=IsImageGray(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel sections
+#endif
+            {
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+              #pragma omp section
+#endif
+              {
+                MagickBooleanType
+                  thread_status;
+
+                if (is_gray != MagickFalse)
+                  thread_status=ForwardFourierTransformChannel(image,
+                    GrayChannels,modulus,fourier_image,exception);
+                else
+                  thread_status=ForwardFourierTransformChannel(image,
+                    RedChannel,modulus,fourier_image,exception);
+                if (thread_status == MagickFalse)
+                  status=thread_status;
+              }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+              #pragma omp section
+#endif
+              {
+                MagickBooleanType
+                  thread_status;
+
+                thread_status=MagickTrue;
+                if (is_gray == MagickFalse)
+                  thread_status=ForwardFourierTransformChannel(image,
+                    GreenChannel,modulus,fourier_image,exception);
+                if (thread_status == MagickFalse)
+                  status=thread_status;
+              }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+              #pragma omp section
+#endif
+              {
+                MagickBooleanType
+                  thread_status;
+
+                thread_status=MagickTrue;
+                if (is_gray == MagickFalse)
+                  thread_status=ForwardFourierTransformChannel(image,
+                    BlueChannel,modulus,fourier_image,exception);
+                if (thread_status == MagickFalse)
+                  status=thread_status;
+              }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+              #pragma omp section
+#endif
+              {
+                MagickBooleanType
+                  thread_status;
+
+                thread_status=MagickTrue;
+                if (image->colorspace == CMYKColorspace)
+                  thread_status=ForwardFourierTransformChannel(image,
+                    BlackChannel,modulus,fourier_image,exception);
+                if (thread_status == MagickFalse)
+                  status=thread_status;
+              }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+              #pragma omp section
+#endif
+              {
+                MagickBooleanType
+                  thread_status;
+
+                thread_status=MagickTrue;
+                if (image->matte != MagickFalse)
+                  thread_status=ForwardFourierTransformChannel(image,
+                    AlphaChannel,modulus,fourier_image,exception);
+                if (thread_status == MagickFalse)
+                  status=thread_status;
+              }
+            }
+            if (status == MagickFalse)
+              fourier_image=DestroyImageList(fourier_image);
+            fftw_cleanup();
+          }
+      }
+  }
+#endif
+  return(fourier_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I n v e r s e F o u r i e r T r a n s f o r m I m a g e                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InverseFourierTransformImage() implements the inverse discrete Fourier
+%  transform (DFT) of the image either as a magnitude / phase or real /
+%  imaginary image pair.
+%
+%  The format of the InverseFourierTransformImage method is:
+%
+%      Image *InverseFourierTransformImage(const Image *magnitude_image,
+%        const Image *phase_image,const MagickBooleanType modulus,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o magnitude_image: the magnitude or real image.
+%
+%    o phase_image: the phase or imaginary image.
+%
+%    o modulus: if true, return transform as a magnitude / phase pair
+%      otherwise a real / imaginary image pair.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(MAGICKCORE_FFTW_DELEGATE)
+static MagickBooleanType InverseQuadrantSwap(const size_t width,
+  const size_t height,const double *source,double *destination)
+{
+  register ssize_t
+    x;
+
+  ssize_t
+    center,
+    y;
+
+  /*
+    Swap quadrants.
+  */
+  center=(ssize_t) floor((double) width/2.0)+1L;
+  for (y=1L; y < (ssize_t) height; y++)
+    for (x=0L; x < (ssize_t) (width/2L+1L); x++)
+      destination[center*(height-y)-x+width/2L]=source[y*width+x];
+  for (y=0L; y < (ssize_t) height; y++)
+    destination[center*y]=source[y*width+width/2L];
+  for (x=0L; x < center; x++)
+    destination[x]=source[center-x-1L];
+  return(RollFourier(center,height,0L,(ssize_t) height/-2L,destination));
+}
+
+static MagickBooleanType InverseFourier(FourierInfo *fourier_info,
+  const Image *magnitude_image,const Image *phase_image,fftw_complex *fourier,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *magnitude_view,
+    *phase_view;
+
+  double
+    *magnitude,
+    *phase,
+    *magnitude_source,
+    *phase_source;
+
+  MagickBooleanType
+    status;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    y;
+
+  /*
+    Inverse fourier - read image and break down into a double array.
+  */
+  magnitude_source=(double *) AcquireQuantumMemory((size_t)
+    fourier_info->height,fourier_info->width*sizeof(*magnitude_source));
+  if (magnitude_source == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      return(MagickFalse);
+    }
+  phase_source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->width*sizeof(*phase_source));
+  if (phase_source == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
+      return(MagickFalse);
+    }
+  i=0L;
+  magnitude_view=AcquireCacheView(magnitude_image);
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+  {
+    p=GetCacheViewVirtualPixels(magnitude_view,0L,y,fourier_info->width,1UL,
+      exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0L; x < (ssize_t) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          magnitude_source[i]=QuantumScale*GetPixelRed(magnitude_image,p);
+          break;
+        }
+        case GreenChannel:
+        {
+          magnitude_source[i]=QuantumScale*GetPixelGreen(magnitude_image,p);
+          break;
+        }
+        case BlueChannel:
+        {
+          magnitude_source[i]=QuantumScale*GetPixelBlue(magnitude_image,p);
+          break;
+        }
+        case BlackChannel:
+        {
+          magnitude_source[i]=QuantumScale*GetPixelBlack(magnitude_image,p);
+          break;
+        }
+        case AlphaChannel:
+        {
+          magnitude_source[i]=QuantumScale*GetPixelAlpha(magnitude_image,p);
+          break;
+        }
+        case GrayChannels:
+        {
+          magnitude_source[i]=QuantumScale*GetPixelGray(magnitude_image,p);
+          break;
+        }
+      }
+      i++;
+      p+=GetPixelChannels(magnitude_image);
+    }
+  }
+  i=0L;
+  phase_view=AcquireCacheView(phase_image);
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+  {
+    p=GetCacheViewVirtualPixels(phase_view,0,y,fourier_info->width,1,
+      exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0L; x < (ssize_t) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          phase_source[i]=QuantumScale*GetPixelRed(phase_image,p);
+          break;
+        }
+        case GreenChannel:
+        {
+          phase_source[i]=QuantumScale*GetPixelGreen(phase_image,p);
+          break;
+        }
+        case BlueChannel:
+        {
+          phase_source[i]=QuantumScale*GetPixelBlue(phase_image,p);
+          break;
+        }
+        case BlackChannel:
+        {
+          phase_source[i]=QuantumScale*GetPixelBlack(phase_image,p);
+          break;
+        }
+        case AlphaChannel:
+        {
+          phase_source[i]=QuantumScale*GetPixelAlpha(phase_image,p);
+          break;
+        }
+        case GrayChannels:
+        {
+          phase_source[i]=QuantumScale*GetPixelGray(phase_image,p);
+          break;
+        }
+      }
+      i++;
+      p+=GetPixelChannels(phase_image);
+    }
+  }
+  if (fourier_info->modulus != MagickFalse)
+    {
+      i=0L;
+      for (y=0L; y < (ssize_t) fourier_info->height; y++)
+        for (x=0L; x < (ssize_t) fourier_info->width; x++)
+        {
+          phase_source[i]-=0.5;
+          phase_source[i]*=(2.0*MagickPI);
+          i++;
+        }
+    }
+  magnitude_view=DestroyCacheView(magnitude_view);
+  phase_view=DestroyCacheView(phase_view);
+  magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->center*sizeof(*magnitude));
+  if (magnitude == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
+      phase_source=(double *) RelinquishMagickMemory(phase_source);
+      return(MagickFalse);
+    }
+  status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
+    magnitude_source,magnitude);
+  magnitude_source=(double *) RelinquishMagickMemory(magnitude_source);
+  phase=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->width*sizeof(*phase));
+  if (phase == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      phase_source=(double *) RelinquishMagickMemory(phase_source);
+      return(MagickFalse);
+    }
+  CorrectPhaseLHS(fourier_info->width,fourier_info->width,phase_source);
+  if (status != MagickFalse)
+    status=InverseQuadrantSwap(fourier_info->width,fourier_info->height,
+      phase_source,phase);
+  phase_source=(double *) RelinquishMagickMemory(phase_source);
+  /*
+    Merge two sets.
+  */
+  i=0L;
+  if (fourier_info->modulus != MagickFalse)
+    for (y=0L; y < (ssize_t) fourier_info->height; y++)
+       for (x=0L; x < (ssize_t) fourier_info->center; x++)
+       {
+#if defined(MAGICKCORE_HAVE_COMPLEX_H)
+         fourier[i]=magnitude[i]*cos(phase[i])+I*magnitude[i]*sin(phase[i]);
+#else
+         fourier[i][0]=magnitude[i]*cos(phase[i]);
+         fourier[i][1]=magnitude[i]*sin(phase[i]);
+#endif
+         i++;
+      }
+  else
+    for (y=0L; y < (ssize_t) fourier_info->height; y++)
+      for (x=0L; x < (ssize_t) fourier_info->center; x++)
+      {
+#if defined(MAGICKCORE_HAVE_COMPLEX_H)
+        fourier[i]=magnitude[i]+I*phase[i];
+#else
+        fourier[i][0]=magnitude[i];
+        fourier[i][1]=phase[i];
+#endif
+        i++;
+      }
+  phase=(double *) RelinquishMagickMemory(phase);
+  magnitude=(double *) RelinquishMagickMemory(magnitude);
+  return(status);
+}
+
+static MagickBooleanType InverseFourierTransform(FourierInfo *fourier_info,
+  fftw_complex *fourier,Image *image,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  double
+    *source;
+
+  fftw_plan
+    fftw_c2r_plan;
+
+  register Quantum
+    *q;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    y;
+
+  source=(double *) AcquireQuantumMemory((size_t) fourier_info->height,
+    fourier_info->width*sizeof(*source));
+  if (source == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_InverseFourierTransform)
+#endif
+  {
+    fftw_c2r_plan=fftw_plan_dft_c2r_2d(fourier_info->width,fourier_info->height,
+      fourier,source,FFTW_ESTIMATE);
+    fftw_execute(fftw_c2r_plan);
+    fftw_destroy_plan(fftw_c2r_plan);
+  }
+  i=0L;
+  image_view=AcquireCacheView(image);
+  for (y=0L; y < (ssize_t) fourier_info->height; y++)
+  {
+    if (y >= (ssize_t) image->rows)
+      break;
+    q=GetCacheViewAuthenticPixels(image_view,0L,y,fourier_info->width >
+      image->columns ? image->columns : fourier_info->width,1UL,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0L; x < (ssize_t) fourier_info->width; x++)
+    {
+      switch (fourier_info->channel)
+      {
+        case RedChannel:
+        default:
+        {
+          SetPixelRed(image,ClampToQuantum(QuantumRange*source[i]),q);
+          break;
+        }
+        case GreenChannel:
+        {
+          SetPixelGreen(image,ClampToQuantum(QuantumRange*source[i]),q);
+          break;
+        }
+        case BlueChannel:
+        {
+          SetPixelBlue(image,ClampToQuantum(QuantumRange*source[i]),q);
+          break;
+        }
+        case BlackChannel:
+        {
+          SetPixelBlack(image,ClampToQuantum(QuantumRange*source[i]),q);
+          break;
+        }
+        case AlphaChannel:
+        {
+          SetPixelAlpha(image,ClampToQuantum(QuantumRange*source[i]),q);
+          break;
+        }
+        case GrayChannels:
+        {
+          SetPixelGray(image,ClampToQuantum(QuantumRange*source[i]),q);
+          break;
+        }
+      }
+      i++;
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  source=(double *) RelinquishMagickMemory(source);
+  return(MagickTrue);
+}
+
+static MagickBooleanType InverseFourierTransformChannel(
+  const Image *magnitude_image,const Image *phase_image,
+  const ChannelType channel,const MagickBooleanType modulus,
+  Image *fourier_image,ExceptionInfo *exception)
+{
+  double
+    *magnitude,
+    *phase;
+
+  fftw_complex
+    *fourier;
+
+  FourierInfo
+    fourier_info;
+
+  MagickBooleanType
+    status;
+
+  size_t
+    extent;
+
+  fourier_info.width=magnitude_image->columns;
+  if ((magnitude_image->columns != magnitude_image->rows) ||
+      ((magnitude_image->columns % 2) != 0) ||
+      ((magnitude_image->rows % 2) != 0))
+    {
+      extent=magnitude_image->columns < magnitude_image->rows ?
+        magnitude_image->rows : magnitude_image->columns;
+      fourier_info.width=(extent & 0x01) == 1 ? extent+1UL : extent;
+    }
+  fourier_info.height=fourier_info.width;
+  fourier_info.center=(ssize_t) floor((double) fourier_info.width/2.0)+1L;
+  fourier_info.channel=channel;
+  fourier_info.modulus=modulus;
+  magnitude=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*magnitude));
+  if (magnitude == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      return(MagickFalse);
+    }
+  phase=(double *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*phase));
+  if (phase == (double *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      magnitude=(double *) RelinquishMagickMemory(magnitude);
+      return(MagickFalse);
+    }
+  fourier=(fftw_complex *) AcquireQuantumMemory((size_t) fourier_info.height,
+    fourier_info.center*sizeof(*fourier));
+  if (fourier == (fftw_complex *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        magnitude_image->filename);
+      phase=(double *) RelinquishMagickMemory(phase);
+      magnitude=(double *) RelinquishMagickMemory(magnitude);
+      return(MagickFalse);
+    }
+  status=InverseFourier(&fourier_info,magnitude_image,phase_image,fourier,
+   exception);
+  if (status != MagickFalse)
+    status=InverseFourierTransform(&fourier_info,fourier,fourier_image,
+      exception);
+  fourier=(fftw_complex *) RelinquishMagickMemory(fourier);
+  phase=(double *) RelinquishMagickMemory(phase);
+  magnitude=(double *) RelinquishMagickMemory(magnitude);
+  return(status);
+}
+#endif
+
+MagickExport Image *InverseFourierTransformImage(const Image *magnitude_image,
+  const Image *phase_image,const MagickBooleanType modulus,
+  ExceptionInfo *exception)
+{
+  Image
+    *fourier_image;
+
+  assert(magnitude_image != (Image *) NULL);
+  assert(magnitude_image->signature == MagickSignature);
+  if (magnitude_image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      magnitude_image->filename);
+  if (phase_image == (Image *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+        "ImageSequenceRequired","`%s'",magnitude_image->filename);
+      return((Image *) NULL);
+    }
+#if !defined(MAGICKCORE_FFTW_DELEGATE)
+  fourier_image=(Image *) NULL;
+  (void) modulus;
+  (void) ThrowMagickException(exception,GetMagickModule(),
+    MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (FFTW)",
+    magnitude_image->filename);
+#else
+  {
+    fourier_image=CloneImage(magnitude_image,magnitude_image->columns,
+      magnitude_image->rows,MagickFalse,exception);
+    if (fourier_image != (Image *) NULL)
+      {
+        MagickBooleanType
+          is_gray,
+          status;
+
+        status=MagickTrue;
+        is_gray=IsImageGray(magnitude_image,exception);
+        if (is_gray != MagickFalse)
+          is_gray=IsImageGray(phase_image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp parallel sections
+#endif
+        {
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp section
+#endif
+          {
+            MagickBooleanType
+              thread_status;
+
+            if (is_gray != MagickFalse)
+              thread_status=InverseFourierTransformChannel(magnitude_image,
+                phase_image,GrayChannels,modulus,fourier_image,exception);
+            else
+              thread_status=InverseFourierTransformChannel(magnitude_image,
+                phase_image,RedChannel,modulus,fourier_image,exception);
+            if (thread_status == MagickFalse)
+              status=thread_status;
+          }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp section
+#endif
+          {
+            MagickBooleanType
+              thread_status;
+
+            thread_status=MagickTrue;
+            if (is_gray == MagickFalse)
+              thread_status=InverseFourierTransformChannel(magnitude_image,
+                phase_image,GreenChannel,modulus,fourier_image,exception);
+            if (thread_status == MagickFalse)
+              status=thread_status;
+          }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp section
+#endif
+          {
+            MagickBooleanType
+              thread_status;
+
+            thread_status=MagickTrue;
+            if (is_gray == MagickFalse)
+              thread_status=InverseFourierTransformChannel(magnitude_image,
+                phase_image,BlueChannel,modulus,fourier_image,exception);
+            if (thread_status == MagickFalse)
+              status=thread_status;
+          }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp section
+#endif
+          {
+            MagickBooleanType
+              thread_status;
+
+            thread_status=MagickTrue;
+            if (magnitude_image->colorspace == CMYKColorspace)
+              thread_status=InverseFourierTransformChannel(magnitude_image,
+                phase_image,BlackChannel,modulus,fourier_image,exception);
+            if (thread_status == MagickFalse)
+              status=thread_status;
+          }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp section
+#endif
+          {
+            MagickBooleanType
+              thread_status;
+
+            thread_status=MagickTrue;
+            if (magnitude_image->matte != MagickFalse)
+              thread_status=InverseFourierTransformChannel(magnitude_image,
+                phase_image,AlphaChannel,modulus,fourier_image,exception);
+            if (thread_status == MagickFalse)
+              status=thread_status;
+          }
+        }
+        if (status == MagickFalse)
+          fourier_image=DestroyImage(fourier_image);
+      }
+    fftw_cleanup();
+  }
+#endif
+  return(fourier_image);
+}
diff --git a/MagickCore/fourier.h b/MagickCore/fourier.h
new file mode 100644
index 0000000..d0f7898
--- /dev/null
+++ b/MagickCore/fourier.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore discrete Fourier transform (DFT) methods.
+*/
+#ifndef _MAGICKCORE_FFT_H
+#define _MAGICKCORE_FFT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport Image
+ *ForwardFourierTransformImage(const Image *,const MagickBooleanType,
+   ExceptionInfo *),
+ *InverseFourierTransformImage(const Image *,const Image *,
+   const MagickBooleanType,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/fx-private.h b/MagickCore/fx-private.h
new file mode 100644
index 0000000..8881775
--- /dev/null
+++ b/MagickCore/fx-private.h
@@ -0,0 +1,41 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private image f/x methods.
+*/
+#ifndef _MAGICKCORE_FX_PRIVATE_H
+#define _MAGICKCORE_FX_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _FxInfo
+  FxInfo;
+
+extern MagickExport FxInfo
+  *AcquireFxInfo(const Image *,const char *),
+  *DestroyFxInfo(FxInfo *);
+
+extern MagickExport MagickBooleanType
+  FxEvaluateExpression(FxInfo *,MagickRealType *,ExceptionInfo *),
+  FxEvaluateChannelExpression(FxInfo *,const ChannelType,const ssize_t,
+   const ssize_t,MagickRealType *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/fx.c b/MagickCore/fx.c
new file mode 100644
index 0000000..4fbdb30
--- /dev/null
+++ b/MagickCore/fx.c
@@ -0,0 +1,5451 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                 FFFFF  X   X                                %
+%                                 F       X X                                 %
+%                                 FFF      X                                  %
+%                                 F       X X                                 %
+%                                 F      X   X                                %
+%                                                                             %
+%                                                                             %
+%                   MagickCore Image Special Effects Methods                  %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                 October 1996                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/fx-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/random-private.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resample-private.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+
+/*
+  Define declarations.
+*/
+#define LeftShiftOperator 0xf5
+#define RightShiftOperator 0xf6
+#define LessThanEqualOperator 0xf7
+#define GreaterThanEqualOperator 0xf8
+#define EqualOperator 0xf9
+#define NotEqualOperator 0xfa
+#define LogicalAndOperator 0xfb
+#define LogicalOrOperator 0xfc
+#define ExponentialNotation 0xfd
+
+struct _FxInfo
+{
+  const Image
+    *images;
+
+  char
+    *expression;
+
+  FILE
+    *file;
+
+  SplayTreeInfo
+    *colors,
+    *symbols;
+
+  CacheView
+    **view;
+
+  RandomInfo
+    *random_info;
+
+  ExceptionInfo
+    *exception;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e F x I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireFxInfo() allocates the FxInfo structure.
+%
+%  The format of the AcquireFxInfo method is:
+%
+%      FxInfo *AcquireFxInfo(Image *image,const char *expression)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o expression: the expression.
+%
+*/
+MagickExport FxInfo *AcquireFxInfo(const Image *image,const char *expression)
+{
+  char
+    fx_op[2];
+
+  const Image
+    *next;
+
+  FxInfo
+    *fx_info;
+
+  register ssize_t
+    i;
+
+  fx_info=(FxInfo *) AcquireMagickMemory(sizeof(*fx_info));
+  if (fx_info == (FxInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info));
+  fx_info->exception=AcquireExceptionInfo();
+  fx_info->images=image;
+  fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+    RelinquishMagickMemory);
+  fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+    RelinquishMagickMemory);
+  fx_info->view=(CacheView **) AcquireQuantumMemory(GetImageListLength(
+    fx_info->images),sizeof(*fx_info->view));
+  if (fx_info->view == (CacheView **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  i=0;
+  next=GetFirstImageInList(fx_info->images);
+  for ( ; next != (Image *) NULL; next=next->next)
+  {
+    fx_info->view[i]=AcquireCacheView(next);
+    i++;
+  }
+  fx_info->random_info=AcquireRandomInfo();
+  fx_info->expression=ConstantString(expression);
+  fx_info->file=stderr;
+  (void) SubstituteString(&fx_info->expression," ","");  /* compact string */
+  /*
+    Force right-to-left associativity for unary negation.
+  */
+  (void) SubstituteString(&fx_info->expression,"-","-1.0*");
+  if ((strstr(fx_info->expression,"e+") != (char *) NULL) ||
+      (strstr(fx_info->expression,"e-") != (char *) NULL))
+    {
+      /*
+        Convert scientific notation.
+      */
+      (void) SubstituteString(&fx_info->expression,"0e+","0**10^");
+      (void) SubstituteString(&fx_info->expression,"1e+","1**10^");
+      (void) SubstituteString(&fx_info->expression,"2e+","2**10^");
+      (void) SubstituteString(&fx_info->expression,"3e+","3**10^");
+      (void) SubstituteString(&fx_info->expression,"4e+","4**10^");
+      (void) SubstituteString(&fx_info->expression,"5e+","5**10^");
+      (void) SubstituteString(&fx_info->expression,"6e+","6**10^");
+      (void) SubstituteString(&fx_info->expression,"7e+","7**10^");
+      (void) SubstituteString(&fx_info->expression,"8e+","8**10^");
+      (void) SubstituteString(&fx_info->expression,"9e+","9**10^");
+      (void) SubstituteString(&fx_info->expression,"0e-1.0*","0**10^-");
+      (void) SubstituteString(&fx_info->expression,"1e-1.0*","1**10^-");
+      (void) SubstituteString(&fx_info->expression,"2e-1.0*","2**10^-");
+      (void) SubstituteString(&fx_info->expression,"3e-1.0*","3**10^-");
+      (void) SubstituteString(&fx_info->expression,"4e-1.0*","4**10^-");
+      (void) SubstituteString(&fx_info->expression,"5e-1.0*","5**10^-");
+      (void) SubstituteString(&fx_info->expression,"6e-1.0*","6**10^-");
+      (void) SubstituteString(&fx_info->expression,"7e-1.0*","7**10^-");
+      (void) SubstituteString(&fx_info->expression,"8e-1.0*","8**10^-");
+      (void) SubstituteString(&fx_info->expression,"9e-1.0*","9**10^-");
+    }
+  if ((strstr(fx_info->expression,"E+") != (char *) NULL) ||
+      (strstr(fx_info->expression,"E-") != (char *) NULL))
+    {
+      /*
+        Convert scientific notation.
+      */
+      (void) SubstituteString(&fx_info->expression,"0E+","0**10^");
+      (void) SubstituteString(&fx_info->expression,"1E+","1**10^");
+      (void) SubstituteString(&fx_info->expression,"2E+","2**10^");
+      (void) SubstituteString(&fx_info->expression,"3E+","3**10^");
+      (void) SubstituteString(&fx_info->expression,"4E+","4**10^");
+      (void) SubstituteString(&fx_info->expression,"5E+","5**10^");
+      (void) SubstituteString(&fx_info->expression,"6E+","6**10^");
+      (void) SubstituteString(&fx_info->expression,"7E+","7**10^");
+      (void) SubstituteString(&fx_info->expression,"8E+","8**10^");
+      (void) SubstituteString(&fx_info->expression,"9E+","9**10^");
+      (void) SubstituteString(&fx_info->expression,"0E-1.0*","0**10^-");
+      (void) SubstituteString(&fx_info->expression,"1E-1.0*","1**10^-");
+      (void) SubstituteString(&fx_info->expression,"2E-1.0*","2**10^-");
+      (void) SubstituteString(&fx_info->expression,"3E-1.0*","3**10^-");
+      (void) SubstituteString(&fx_info->expression,"4E-1.0*","4**10^-");
+      (void) SubstituteString(&fx_info->expression,"5E-1.0*","5**10^-");
+      (void) SubstituteString(&fx_info->expression,"6E-1.0*","6**10^-");
+      (void) SubstituteString(&fx_info->expression,"7E-1.0*","7**10^-");
+      (void) SubstituteString(&fx_info->expression,"8E-1.0*","8**10^-");
+      (void) SubstituteString(&fx_info->expression,"9E-1.0*","9**10^-");
+    }
+  /*
+    Convert complex to simple operators.
+  */
+  fx_op[1]='\0';
+  *fx_op=(char) LeftShiftOperator;
+  (void) SubstituteString(&fx_info->expression,"<<",fx_op);
+  *fx_op=(char) RightShiftOperator;
+  (void) SubstituteString(&fx_info->expression,">>",fx_op);
+  *fx_op=(char) LessThanEqualOperator;
+  (void) SubstituteString(&fx_info->expression,"<=",fx_op);
+  *fx_op=(char) GreaterThanEqualOperator;
+  (void) SubstituteString(&fx_info->expression,">=",fx_op);
+  *fx_op=(char) EqualOperator;
+  (void) SubstituteString(&fx_info->expression,"==",fx_op);
+  *fx_op=(char) NotEqualOperator;
+  (void) SubstituteString(&fx_info->expression,"!=",fx_op);
+  *fx_op=(char) LogicalAndOperator;
+  (void) SubstituteString(&fx_info->expression,"&&",fx_op);
+  *fx_op=(char) LogicalOrOperator;
+  (void) SubstituteString(&fx_info->expression,"||",fx_op);
+  *fx_op=(char) ExponentialNotation;
+  (void) SubstituteString(&fx_info->expression,"**",fx_op);
+  return(fx_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A d d N o i s e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AddNoiseImage() adds random noise to the image.
+%
+%  The format of the AddNoiseImage method is:
+%
+%      Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
+%        ExceptionInfo *exception)
+%      Image *AddNoiseImageChannel(const Image *image,const ChannelType channel,
+%        const NoiseType noise_type,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o noise_type:  The type of noise: Uniform, Gaussian, Multiplicative,
+%      Impulse, Laplacian, or Poisson.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
+  ExceptionInfo *exception)
+{
+  Image
+    *noise_image;
+
+  noise_image=AddNoiseImageChannel(image,DefaultChannels,noise_type,exception);
+  return(noise_image);
+}
+
+MagickExport Image *AddNoiseImageChannel(const Image *image,
+  const ChannelType channel,const NoiseType noise_type,ExceptionInfo *exception)
+{
+#define AddNoiseImageTag  "AddNoise/Image"
+
+  CacheView
+    *image_view,
+    *noise_view;
+
+  const char
+    *option;
+
+  Image
+    *noise_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  MagickRealType
+    attenuate;
+
+  RandomInfo
+    **restrict random_info;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize noise image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  noise_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (noise_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(noise_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&noise_image->exception);
+      noise_image=DestroyImage(noise_image);
+      return((Image *) NULL);
+    }
+  /*
+    Add noise in each row.
+  */
+  attenuate=1.0;
+  option=GetImageArtifact(image,"attenuate");
+  if (option != (char *) NULL)
+    attenuate=InterpretLocaleValue(option,(char **) NULL);
+  status=MagickTrue;
+  progress=0;
+  random_info=AcquireRandomInfoThreadSet();
+  image_view=AcquireCacheView(image);
+  noise_view=AcquireCacheView(noise_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(noise_image,ClampToQuantum(GenerateDifferentialNoise(
+          random_info[id],GetPixelRed(image,p),noise_type,attenuate)),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(noise_image,ClampToQuantum(GenerateDifferentialNoise(
+          random_info[id],GetPixelGreen(image,p),noise_type,attenuate)),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(noise_image,ClampToQuantum(GenerateDifferentialNoise(
+          random_info[id],GetPixelBlue(image,p),noise_type,attenuate)),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(noise_image,ClampToQuantum(GenerateDifferentialNoise(
+          random_info[id],GetPixelBlack(image,p),noise_type,attenuate)),q);
+      if ((channel & AlphaChannel) != 0)
+        SetPixelAlpha(noise_image,ClampToQuantum(GenerateDifferentialNoise(
+          random_info[id],GetPixelAlpha(image,p),noise_type,attenuate)),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(noise_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(noise_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_AddNoiseImage)
+#endif
+        proceed=SetImageProgress(image,AddNoiseImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  noise_view=DestroyCacheView(noise_view);
+  image_view=DestroyCacheView(image_view);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  if (status == MagickFalse)
+    noise_image=DestroyImage(noise_image);
+  return(noise_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     B l u e S h i f t I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BlueShiftImage() mutes the colors of the image to simulate a scene at
+%  nighttime in the moonlight.
+%
+%  The format of the BlueShiftImage method is:
+%
+%      Image *BlueShiftImage(const Image *image,const double factor,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o factor: the shift factor.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *BlueShiftImage(const Image *image,const double factor,
+  ExceptionInfo *exception)
+{
+#define BlueShiftImageTag  "BlueShift/Image"
+
+  CacheView
+    *image_view,
+    *shift_view;
+
+  Image
+    *shift_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate blue shift image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  shift_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (shift_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(shift_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&shift_image->exception);
+      shift_image=DestroyImage(shift_image);
+      return((Image *) NULL);
+    }
+  /*
+    Blue-shift DirectClass image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  shift_view=AcquireCacheView(shift_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    PixelInfo
+      pixel;
+
+    Quantum
+      quantum;
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      quantum=GetPixelRed(image,p);
+      if (GetPixelGreen(image,p) < quantum)
+        quantum=GetPixelGreen(image,p);
+      if (GetPixelBlue(image,p) < quantum)
+        quantum=GetPixelBlue(image,p);
+      pixel.red=0.5*(GetPixelRed(image,p)+factor*quantum);
+      pixel.green=0.5*(GetPixelGreen(image,p)+factor*quantum);
+      pixel.blue=0.5*(GetPixelBlue(image,p)+factor*quantum);
+      quantum=GetPixelRed(image,p);
+      if (GetPixelGreen(image,p) > quantum)
+        quantum=GetPixelGreen(image,p);
+      if (GetPixelBlue(image,p) > quantum)
+        quantum=GetPixelBlue(image,p);
+      pixel.red=0.5*(pixel.red+factor*quantum);
+      pixel.green=0.5*(pixel.green+factor*quantum);
+      pixel.blue=0.5*(pixel.blue+factor*quantum);
+      SetPixelRed(shift_image,ClampToQuantum(pixel.red),q);
+      SetPixelGreen(shift_image,ClampToQuantum(pixel.green),q);
+      SetPixelBlue(shift_image,ClampToQuantum(pixel.blue),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(shift_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(shift_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_BlueShiftImage)
+#endif
+        proceed=SetImageProgress(image,BlueShiftImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  shift_view=DestroyCacheView(shift_view);
+  if (status == MagickFalse)
+    shift_image=DestroyImage(shift_image);
+  return(shift_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C h a r c o a l I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CharcoalImage() creates a new image that is a copy of an existing one with
+%  the edge highlighted.  It allocates the memory necessary for the new Image
+%  structure and returns a pointer to the new image.
+%
+%  The format of the CharcoalImage method is:
+%
+%      Image *CharcoalImage(const Image *image,const double radius,
+%        const double sigma,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius: the radius of the pixel neighborhood.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CharcoalImage(const Image *image,const double radius,
+  const double sigma,ExceptionInfo *exception)
+{
+  Image
+    *charcoal_image,
+    *clone_image,
+    *edge_image;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  clone_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (clone_image == (Image *) NULL)
+    return((Image *) NULL);
+  (void) SetImageType(clone_image,GrayscaleType);
+  edge_image=EdgeImage(clone_image,radius,exception);
+  clone_image=DestroyImage(clone_image);
+  if (edge_image == (Image *) NULL)
+    return((Image *) NULL);
+  charcoal_image=BlurImage(edge_image,radius,sigma,exception);
+  edge_image=DestroyImage(edge_image);
+  if (charcoal_image == (Image *) NULL)
+    return((Image *) NULL);
+  (void) NormalizeImage(charcoal_image);
+  (void) NegateImage(charcoal_image,MagickFalse);
+  (void) SetImageType(charcoal_image,GrayscaleType);
+  return(charcoal_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o l o r i z e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ColorizeImage() blends the fill color with each pixel in the image.
+%  A percentage blend is specified with opacity.  Control the application
+%  of different color components by specifying a different percentage for
+%  each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
+%
+%  The format of the ColorizeImage method is:
+%
+%      Image *ColorizeImage(const Image *image,const char *opacity,
+%        const PixelPacket colorize,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o opacity:  A character string indicating the level of opacity as a
+%      percentage.
+%
+%    o colorize: A color value.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ColorizeImage(const Image *image,const char *opacity,
+  const PixelPacket colorize,ExceptionInfo *exception)
+{
+#define ColorizeImageTag  "Colorize/Image"
+
+  CacheView
+    *colorize_view,
+    *image_view;
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *colorize_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    pixel;
+
+  MagickStatusType
+    flags;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate colorized image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  colorize_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+    exception);
+  if (colorize_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(colorize_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&colorize_image->exception);
+      colorize_image=DestroyImage(colorize_image);
+      return((Image *) NULL);
+    }
+  if (opacity == (const char *) NULL)
+    return(colorize_image);
+  /*
+    Determine RGB values of the pen color.
+  */
+  flags=ParseGeometry(opacity,&geometry_info);
+  pixel.red=geometry_info.rho;
+  pixel.green=geometry_info.rho;
+  pixel.blue=geometry_info.rho;
+  pixel.alpha=(MagickRealType) OpaqueAlpha;
+  if ((flags & SigmaValue) != 0)
+    pixel.green=geometry_info.sigma;
+  if ((flags & XiValue) != 0)
+    pixel.blue=geometry_info.xi;
+  if ((flags & PsiValue) != 0)
+    pixel.alpha=geometry_info.psi;
+  /*
+    Colorize DirectClass image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  colorize_view=AcquireCacheView(colorize_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(colorize_view,0,y,colorize_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelRed(colorize_image,ClampToQuantum((GetPixelRed(image,p)*
+        (100.0-pixel.red)+colorize.red*pixel.red)/100.0),q);
+      SetPixelGreen(colorize_image,ClampToQuantum((GetPixelGreen(image,p)*
+        (100.0-pixel.green)+colorize.green*pixel.green)/100.0),q);
+      SetPixelBlue(colorize_image,ClampToQuantum((GetPixelBlue(image,p)*
+        (100.0-pixel.blue)+colorize.blue*pixel.blue)/100.0),q);
+      SetPixelAlpha(colorize_image,ClampToQuantum((GetPixelAlpha(image,p)*
+        (100.0-pixel.alpha)+colorize.alpha*pixel.alpha)/100.0),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(colorize_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(colorize_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ColorizeImage)
+#endif
+        proceed=SetImageProgress(image,ColorizeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  colorize_view=DestroyCacheView(colorize_view);
+  if (status == MagickFalse)
+    colorize_image=DestroyImage(colorize_image);
+  return(colorize_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o l o r M a t r i x I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ColorMatrixImage() applies color transformation to an image. This method
+%  permits saturation changes, hue rotation, luminance to alpha, and various
+%  other effects.  Although variable-sized transformation matrices can be used,
+%  typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA
+%  (or RGBA with offsets).  The matrix is similar to those used by Adobe Flash
+%  except offsets are in column 6 rather than 5 (in support of CMYKA images)
+%  and offsets are normalized (divide Flash offset by 255).
+%
+%  The format of the ColorMatrixImage method is:
+%
+%      Image *ColorMatrixImage(const Image *image,
+%        const KernelInfo *color_matrix,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o color_matrix:  the color matrix.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ColorMatrixImage(const Image *image,
+  const KernelInfo *color_matrix,ExceptionInfo *exception)
+{
+#define ColorMatrixImageTag  "ColorMatrix/Image"
+
+  CacheView
+    *color_view,
+    *image_view;
+
+  double
+    ColorMatrix[6][6] =
+    {
+      { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
+      { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 },
+      { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 },
+      { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
+      { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 },
+      { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }
+    };
+
+  Image
+    *color_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    u,
+    v,
+    y;
+
+  /*
+    Create color matrix.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  i=0;
+  for (v=0; v < (ssize_t) color_matrix->height; v++)
+    for (u=0; u < (ssize_t) color_matrix->width; u++)
+    {
+      if ((v < 6) && (u < 6))
+        ColorMatrix[v][u]=color_matrix->values[i];
+      i++;
+    }
+  /*
+    Initialize color image.
+  */
+  color_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (color_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(color_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&color_image->exception);
+      color_image=DestroyImage(color_image);
+      return((Image *) NULL);
+    }
+  if (image->debug != MagickFalse)
+    {
+      char
+        format[MaxTextExtent],
+        *message;
+
+      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+        "  ColorMatrix image with color matrix:");
+      message=AcquireString("");
+      for (v=0; v < 6; v++)
+      {
+        *message='\0';
+        (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
+        (void) ConcatenateString(&message,format);
+        for (u=0; u < 6; u++)
+        {
+          (void) FormatLocaleString(format,MaxTextExtent,"%+f ",
+            ColorMatrix[v][u]);
+          (void) ConcatenateString(&message,format);
+        }
+        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
+      }
+      message=DestroyString(message);
+    }
+  /*
+    ColorMatrix image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  color_view=AcquireCacheView(color_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickRealType
+      pixel;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=GetCacheViewAuthenticPixels(color_view,0,y,color_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      register ssize_t
+        v;
+
+      size_t
+        height;
+
+      height=color_matrix->height > 6 ? 6UL : color_matrix->height;
+      for (v=0; v < (ssize_t) height; v++)
+      {
+        pixel=ColorMatrix[v][0]*GetPixelRed(image,p)+ColorMatrix[v][1]*
+          GetPixelGreen(image,p)+ColorMatrix[v][2]*GetPixelBlue(image,p);
+        if (image->colorspace == CMYKColorspace)
+          pixel+=ColorMatrix[v][3]*GetPixelBlack(image,p);
+        if (image->matte != MagickFalse)
+          pixel+=ColorMatrix[v][4]*GetPixelAlpha(image,p);
+        pixel+=QuantumRange*ColorMatrix[v][5];
+        switch (v)
+        {
+          case 0: SetPixelRed(color_image,ClampToQuantum(pixel),q); break;
+          case 1: SetPixelGreen(color_image,ClampToQuantum(pixel),q); break;
+          case 2: SetPixelBlue(color_image,ClampToQuantum(pixel),q); break;
+          case 3:
+          {
+            if (image->colorspace == CMYKColorspace)
+              SetPixelBlack(color_image,ClampToQuantum(pixel),q);
+            break;
+          }
+          case 4:
+          {
+            if (image->matte != MagickFalse)
+              SetPixelAlpha(color_image,ClampToQuantum(pixel),q);
+            break;
+          }
+        }
+      }
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(color_image);
+    }
+    if (SyncCacheViewAuthenticPixels(color_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ColorMatrixImage)
+#endif
+        proceed=SetImageProgress(image,ColorMatrixImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  color_view=DestroyCacheView(color_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    color_image=DestroyImage(color_image);
+  return(color_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y F x I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyFxInfo() deallocates memory associated with an FxInfo structure.
+%
+%  The format of the DestroyFxInfo method is:
+%
+%      ImageInfo *DestroyFxInfo(ImageInfo *fx_info)
+%
+%  A description of each parameter follows:
+%
+%    o fx_info: the fx info.
+%
+*/
+MagickExport FxInfo *DestroyFxInfo(FxInfo *fx_info)
+{
+  register ssize_t
+    i;
+
+  fx_info->exception=DestroyExceptionInfo(fx_info->exception);
+  fx_info->expression=DestroyString(fx_info->expression);
+  fx_info->symbols=DestroySplayTree(fx_info->symbols);
+  fx_info->colors=DestroySplayTree(fx_info->colors);
+  for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
+    fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
+  fx_info->view=(CacheView **) RelinquishMagickMemory(fx_info->view);
+  fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
+  fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
+  return(fx_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     F x E v a l u a t e C h a n n e l E x p r e s s i o n                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FxEvaluateChannelExpression() evaluates an expression and returns the
+%  results.
+%
+%  The format of the FxEvaluateExpression method is:
+%
+%      MagickRealType FxEvaluateChannelExpression(FxInfo *fx_info,
+%        const ChannelType channel,const ssize_t x,const ssize_t y,
+%        MagickRealType *alpha,Exceptioninfo *exception)
+%      MagickRealType FxEvaluateExpression(FxInfo *fx_info,
+%        MagickRealType *alpha,Exceptioninfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o fx_info: the fx info.
+%
+%    o channel: the channel.
+%
+%    o x,y: the pixel position.
+%
+%    o alpha: the result.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickRealType FxChannelStatistics(FxInfo *fx_info,const Image *image,
+  ChannelType channel,const char *symbol,ExceptionInfo *exception)
+{
+  char
+    key[MaxTextExtent],
+    statistic[MaxTextExtent];
+
+  const char
+    *value;
+
+  register const char
+    *p;
+
+  for (p=symbol; (*p != '.') && (*p != '\0'); p++) ;
+  if (*p == '.')
+    switch (*++p)  /* e.g. depth.r */
+    {
+      case 'r': channel=RedChannel; break;
+      case 'g': channel=GreenChannel; break;
+      case 'b': channel=BlueChannel; break;
+      case 'c': channel=CyanChannel; break;
+      case 'm': channel=MagentaChannel; break;
+      case 'y': channel=YellowChannel; break;
+      case 'k': channel=BlackChannel; break;
+      default: break;
+    }
+  (void) FormatLocaleString(key,MaxTextExtent,"%p.%.20g.%s",(void *) image,
+    (double) channel,symbol);
+  value=(const char *) GetValueFromSplayTree(fx_info->symbols,key);
+  if (value != (const char *) NULL)
+    return(QuantumScale*InterpretLocaleValue(value,(char **) NULL));
+  (void) DeleteNodeFromSplayTree(fx_info->symbols,key);
+  if (LocaleNCompare(symbol,"depth",5) == 0)
+    {
+      size_t
+        depth;
+
+      depth=GetImageChannelDepth(image,channel,exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%.20g",(double)
+        depth);
+    }
+  if (LocaleNCompare(symbol,"kurtosis",8) == 0)
+    {
+      double
+        kurtosis,
+        skewness;
+
+      (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
+        exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%g",kurtosis);
+    }
+  if (LocaleNCompare(symbol,"maxima",6) == 0)
+    {
+      double
+        maxima,
+        minima;
+
+      (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%g",maxima);
+    }
+  if (LocaleNCompare(symbol,"mean",4) == 0)
+    {
+      double
+        mean,
+        standard_deviation;
+
+      (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
+        exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%g",mean);
+    }
+  if (LocaleNCompare(symbol,"minima",6) == 0)
+    {
+      double
+        maxima,
+        minima;
+
+      (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%g",minima);
+    }
+  if (LocaleNCompare(symbol,"skewness",8) == 0)
+    {
+      double
+        kurtosis,
+        skewness;
+
+      (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
+        exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%g",skewness);
+    }
+  if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
+    {
+      double
+        mean,
+        standard_deviation;
+
+      (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
+        exception);
+      (void) FormatLocaleString(statistic,MaxTextExtent,"%g",
+        standard_deviation);
+    }
+  (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key),
+    ConstantString(statistic));
+  return(QuantumScale*InterpretLocaleValue(statistic,(char **) NULL));
+}
+
+static MagickRealType
+  FxEvaluateSubexpression(FxInfo *,const ChannelType,const ssize_t,
+    const ssize_t,const char *,MagickRealType *,ExceptionInfo *);
+
+static inline MagickRealType FxMax(FxInfo *fx_info,const ChannelType channel,
+  const ssize_t x,const ssize_t y,const char *expression,
+  ExceptionInfo *exception)
+{
+  MagickRealType
+    alpha,
+    beta;
+
+  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
+  return((MagickRealType) MagickMax((double) alpha,(double) beta));
+}
+
+static inline MagickRealType FxMin(FxInfo *fx_info,ChannelType channel,
+  const ssize_t x,const ssize_t y,const char *expression,
+  ExceptionInfo *exception)
+{
+  MagickRealType
+    alpha,
+    beta;
+
+  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
+  return((MagickRealType) MagickMin((double) alpha,(double) beta));
+}
+
+static inline const char *FxSubexpression(const char *expression,
+  ExceptionInfo *exception)
+{
+  const char
+    *subexpression;
+
+  register ssize_t
+    level;
+
+  level=0;
+  subexpression=expression;
+  while ((*subexpression != '\0') &&
+         ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
+  {
+    if (strchr("(",(int) *subexpression) != (char *) NULL)
+      level++;
+    else
+      if (strchr(")",(int) *subexpression) != (char *) NULL)
+        level--;
+    subexpression++;
+  }
+  if (*subexpression == '\0')
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "UnbalancedParenthesis","`%s'",expression);
+  return(subexpression);
+}
+
+static MagickRealType FxGetSymbol(FxInfo *fx_info,const ChannelType channel,
+  const ssize_t x,const ssize_t y,const char *expression,
+  ExceptionInfo *exception)
+{
+  char
+    *q,
+    subexpression[MaxTextExtent],
+    symbol[MaxTextExtent];
+
+  const char
+    *p,
+    *value;
+
+  Image
+    *image;
+
+  PixelInfo
+    pixel;
+
+  MagickRealType
+    alpha,
+    beta;
+
+  PointInfo
+    point;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  size_t
+    level;
+
+  p=expression;
+  i=GetImageIndexInList(fx_info->images);
+  level=0;
+  point.x=(double) x;
+  point.y=(double) y;
+  if (isalpha((int) *(p+1)) == 0)
+    {
+      if (strchr("suv",(int) *p) != (char *) NULL)
+        {
+          switch (*p)
+          {
+            case 's':
+            default:
+            {
+              i=GetImageIndexInList(fx_info->images);
+              break;
+            }
+            case 'u': i=0; break;
+            case 'v': i=1; break;
+          }
+          p++;
+          if (*p == '[')
+            {
+              level++;
+              q=subexpression;
+              for (p++; *p != '\0'; )
+              {
+                if (*p == '[')
+                  level++;
+                else
+                  if (*p == ']')
+                    {
+                      level--;
+                      if (level == 0)
+                        break;
+                    }
+                *q++=(*p++);
+              }
+              *q='\0';
+              alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
+                &beta,exception);
+              i=(ssize_t) (alpha+0.5);
+              p++;
+            }
+          if (*p == '.')
+            p++;
+        }
+      if ((isalpha((int) *(p+1)) == 0) && (*p == 'p'))
+        {
+          p++;
+          if (*p == '{')
+            {
+              level++;
+              q=subexpression;
+              for (p++; *p != '\0'; )
+              {
+                if (*p == '{')
+                  level++;
+                else
+                  if (*p == '}')
+                    {
+                      level--;
+                      if (level == 0)
+                        break;
+                    }
+                *q++=(*p++);
+              }
+              *q='\0';
+              alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
+                &beta,exception);
+              point.x=alpha;
+              point.y=beta;
+              p++;
+            }
+          else
+            if (*p == '[')
+              {
+                level++;
+                q=subexpression;
+                for (p++; *p != '\0'; )
+                {
+                  if (*p == '[')
+                    level++;
+                  else
+                    if (*p == ']')
+                      {
+                        level--;
+                        if (level == 0)
+                          break;
+                      }
+                  *q++=(*p++);
+                }
+                *q='\0';
+                alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
+                  &beta,exception);
+                point.x+=alpha;
+                point.y+=beta;
+                p++;
+              }
+          if (*p == '.')
+            p++;
+        }
+    }
+  length=GetImageListLength(fx_info->images);
+  while (i < 0)
+    i+=(ssize_t) length;
+  i%=length;
+  image=GetImageFromList(fx_info->images,i);
+  if (image == (Image *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "NoSuchImage","`%s'",expression);
+      return(0.0);
+    }
+  GetPixelInfo(image,&pixel);
+  (void) InterpolatePixelInfo(image,fx_info->view[i],image->interpolate,
+    point.x,point.y,&pixel,exception);
+  if ((strlen(p) > 2) &&
+      (LocaleCompare(p,"intensity") != 0) &&
+      (LocaleCompare(p,"luminance") != 0) &&
+      (LocaleCompare(p,"hue") != 0) &&
+      (LocaleCompare(p,"saturation") != 0) &&
+      (LocaleCompare(p,"lightness") != 0))
+    {
+      char
+        name[MaxTextExtent];
+
+      (void) CopyMagickString(name,p,MaxTextExtent);
+      for (q=name+(strlen(name)-1); q > name; q--)
+      {
+        if (*q == ')')
+          break;
+        if (*q == '.')
+          {
+            *q='\0';
+            break;
+          }
+      }
+      if ((strlen(name) > 2) &&
+          (GetValueFromSplayTree(fx_info->symbols,name) == (const char *) NULL))
+        {
+          PixelInfo
+            *color;
+
+          color=(PixelInfo *) GetValueFromSplayTree(fx_info->colors,name);
+          if (color != (PixelInfo *) NULL)
+            {
+              pixel=(*color);
+              p+=strlen(name);
+            }
+          else
+            if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
+              {
+                (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
+                  ClonePixelInfo(&pixel));
+                p+=strlen(name);
+              }
+        }
+    }
+  (void) CopyMagickString(symbol,p,MaxTextExtent);
+  StripString(symbol);
+  if (*symbol == '\0')
+    {
+      switch (channel)
+      {
+        case RedChannel: return(QuantumScale*pixel.red);
+        case GreenChannel: return(QuantumScale*pixel.green);
+        case BlueChannel: return(QuantumScale*pixel.blue);
+        case BlackChannel:
+        {
+          if (image->colorspace != CMYKColorspace)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"ColorSeparatedImageRequired","`%s'",
+                image->filename);
+              return(0.0);
+            }
+          return(QuantumScale*pixel.black);
+        }
+        case AlphaChannel:
+        {
+          MagickRealType
+            alpha;
+
+          if (pixel.matte == MagickFalse)
+            return(1.0);
+          alpha=(MagickRealType) (QuantumScale*pixel.alpha);
+          return(alpha);
+        }
+        case DefaultChannels:
+        {
+          return(QuantumScale*GetPixelInfoIntensity(&pixel));
+        }
+        default:
+          break;
+      }
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "UnableToParseExpression","`%s'",p);
+      return(0.0);
+    }
+  switch (*symbol)
+  {
+    case 'A':
+    case 'a':
+    {
+      if (LocaleCompare(symbol,"a") == 0)
+        return((MagickRealType) (QuantumScale*pixel.alpha));
+      break;
+    }
+    case 'B':
+    case 'b':
+    {
+      if (LocaleCompare(symbol,"b") == 0)
+        return(QuantumScale*pixel.blue);
+      break;
+    }
+    case 'C':
+    case 'c':
+    {
+      if (LocaleNCompare(symbol,"channel",7) == 0)
+        {
+          GeometryInfo
+            channel_info;
+
+          MagickStatusType
+            flags;
+
+          flags=ParseGeometry(symbol+7,&channel_info);
+          if (image->colorspace == CMYKColorspace)
+            switch (channel)
+            {
+              case CyanChannel:
+              {
+                if ((flags & RhoValue) == 0)
+                  return(0.0);
+                return(channel_info.rho);
+              }
+              case MagentaChannel:
+              {
+                if ((flags & SigmaValue) == 0)
+                  return(0.0);
+                return(channel_info.sigma);
+              }
+              case YellowChannel:
+              {
+                if ((flags & XiValue) == 0)
+                  return(0.0);
+                return(channel_info.xi);
+              }
+              case BlackChannel:
+              {
+                if ((flags & PsiValue) == 0)
+                  return(0.0);
+                return(channel_info.psi);
+              }
+              case AlphaChannel:
+              {
+                if ((flags & ChiValue) == 0)
+                  return(0.0);
+                return(channel_info.chi);
+              }
+              default:
+                return(0.0);
+            }
+          switch (channel)
+          {
+            case RedChannel:
+            {
+              if ((flags & RhoValue) == 0)
+                return(0.0);
+              return(channel_info.rho);
+            }
+            case GreenChannel:
+            {
+              if ((flags & SigmaValue) == 0)
+                return(0.0);
+              return(channel_info.sigma);
+            }
+            case BlueChannel:
+            {
+              if ((flags & XiValue) == 0)
+                return(0.0);
+              return(channel_info.xi);
+            }
+            case BlackChannel:
+            {
+              if ((flags & ChiValue) == 0)
+                return(0.0);
+              return(channel_info.chi);
+            }
+            case AlphaChannel:
+            {
+              if ((flags & PsiValue) == 0)
+                return(0.0);
+              return(channel_info.psi);
+            }
+            default:
+              return(0.0);
+          }
+          return(0.0);
+        }
+      if (LocaleCompare(symbol,"c") == 0)
+        return(QuantumScale*pixel.red);
+      break;
+    }
+    case 'D':
+    case 'd':
+    {
+      if (LocaleNCompare(symbol,"depth",5) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      break;
+    }
+    case 'G':
+    case 'g':
+    {
+      if (LocaleCompare(symbol,"g") == 0)
+        return(QuantumScale*pixel.green);
+      break;
+    }
+    case 'K':
+    case 'k':
+    {
+      if (LocaleNCompare(symbol,"kurtosis",8) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      if (LocaleCompare(symbol,"k") == 0)
+        {
+          if (image->colorspace != CMYKColorspace)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"ColorSeparatedImageRequired","`%s'",
+                image->filename);
+              return(0.0);
+            }
+          return(QuantumScale*pixel.black);
+        }
+      break;
+    }
+    case 'H':
+    case 'h':
+    {
+      if (LocaleCompare(symbol,"h") == 0)
+        return((MagickRealType) image->rows);
+      if (LocaleCompare(symbol,"hue") == 0)
+        {
+          double
+            hue,
+            lightness,
+            saturation;
+
+          ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
+            ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
+          return(hue);
+        }
+      break;
+    }
+    case 'I':
+    case 'i':
+    {
+      if ((LocaleCompare(symbol,"image.depth") == 0) ||
+          (LocaleCompare(symbol,"image.minima") == 0) ||
+          (LocaleCompare(symbol,"image.maxima") == 0) ||
+          (LocaleCompare(symbol,"image.mean") == 0) ||
+          (LocaleCompare(symbol,"image.kurtosis") == 0) ||
+          (LocaleCompare(symbol,"image.skewness") == 0) ||
+          (LocaleCompare(symbol,"image.standard_deviation") == 0))
+        return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
+      if (LocaleCompare(symbol,"image.resolution.x") == 0)
+        return(image->x_resolution);
+      if (LocaleCompare(symbol,"image.resolution.y") == 0)
+        return(image->y_resolution);
+      if (LocaleCompare(symbol,"intensity") == 0)
+        return(QuantumScale*GetPixelInfoIntensity(&pixel));
+      if (LocaleCompare(symbol,"i") == 0)
+        return((MagickRealType) x);
+      break;
+    }
+    case 'J':
+    case 'j':
+    {
+      if (LocaleCompare(symbol,"j") == 0)
+        return((MagickRealType) y);
+      break;
+    }
+    case 'L':
+    case 'l':
+    {
+      if (LocaleCompare(symbol,"lightness") == 0)
+        {
+          double
+            hue,
+            lightness,
+            saturation;
+
+          ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
+            ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
+          return(lightness);
+        }
+      if (LocaleCompare(symbol,"luminance") == 0)
+        {
+          double
+            luminence;
+
+          luminence=0.2126*pixel.red+0.7152*pixel.green+0.0722*pixel.blue;
+          return(QuantumScale*luminence);
+        }
+      break;
+    }
+    case 'M':
+    case 'm':
+    {
+      if (LocaleNCompare(symbol,"maxima",6) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      if (LocaleNCompare(symbol,"mean",4) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      if (LocaleNCompare(symbol,"minima",6) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      if (LocaleCompare(symbol,"m") == 0)
+        return(QuantumScale*pixel.blue);
+      break;
+    }
+    case 'N':
+    case 'n':
+    {
+      if (LocaleCompare(symbol,"n") == 0)
+        return((MagickRealType) GetImageListLength(fx_info->images));
+      break;
+    }
+    case 'O':
+    case 'o':
+    {
+      if (LocaleCompare(symbol,"o") == 0)
+        return(QuantumScale*pixel.alpha);
+      break;
+    }
+    case 'P':
+    case 'p':
+    {
+      if (LocaleCompare(symbol,"page.height") == 0)
+        return((MagickRealType) image->page.height);
+      if (LocaleCompare(symbol,"page.width") == 0)
+        return((MagickRealType) image->page.width);
+      if (LocaleCompare(symbol,"page.x") == 0)
+        return((MagickRealType) image->page.x);
+      if (LocaleCompare(symbol,"page.y") == 0)
+        return((MagickRealType) image->page.y);
+      break;
+    }
+    case 'R':
+    case 'r':
+    {
+      if (LocaleCompare(symbol,"resolution.x") == 0)
+        return(image->x_resolution);
+      if (LocaleCompare(symbol,"resolution.y") == 0)
+        return(image->y_resolution);
+      if (LocaleCompare(symbol,"r") == 0)
+        return(QuantumScale*pixel.red);
+      break;
+    }
+    case 'S':
+    case 's':
+    {
+      if (LocaleCompare(symbol,"saturation") == 0)
+        {
+          double
+            hue,
+            lightness,
+            saturation;
+
+          ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
+            ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
+          return(saturation);
+        }
+      if (LocaleNCompare(symbol,"skewness",8) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
+        return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
+      break;
+    }
+    case 'T':
+    case 't':
+    {
+      if (LocaleCompare(symbol,"t") == 0)
+        return((MagickRealType) GetImageIndexInList(fx_info->images));
+      break;
+    }
+    case 'W':
+    case 'w':
+    {
+      if (LocaleCompare(symbol,"w") == 0)
+        return((MagickRealType) image->columns);
+      break;
+    }
+    case 'Y':
+    case 'y':
+    {
+      if (LocaleCompare(symbol,"y") == 0)
+        return(QuantumScale*pixel.green);
+      break;
+    }
+    case 'Z':
+    case 'z':
+    {
+      if (LocaleCompare(symbol,"z") == 0)
+        {
+          MagickRealType
+            depth;
+
+          depth=(MagickRealType) GetImageChannelDepth(image,channel,
+            fx_info->exception);
+          return(depth);
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol);
+  if (value != (const char *) NULL)
+    return((MagickRealType) InterpretLocaleValue(value,(char **) NULL));
+  (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+    "UnableToParseExpression","`%s'",symbol);
+  return(0.0);
+}
+
+static const char *FxOperatorPrecedence(const char *expression,
+  ExceptionInfo *exception)
+{
+  typedef enum
+  {
+    UndefinedPrecedence,
+    NullPrecedence,
+    BitwiseComplementPrecedence,
+    ExponentPrecedence,
+    ExponentialNotationPrecedence,
+    MultiplyPrecedence,
+    AdditionPrecedence,
+    ShiftPrecedence,
+    RelationalPrecedence,
+    EquivalencyPrecedence,
+    BitwiseAndPrecedence,
+    BitwiseOrPrecedence,
+    LogicalAndPrecedence,
+    LogicalOrPrecedence,
+    TernaryPrecedence,
+    AssignmentPrecedence,
+    CommaPrecedence,
+    SeparatorPrecedence
+  } FxPrecedence;
+
+  FxPrecedence
+    precedence,
+    target;
+
+  register const char
+    *subexpression;
+
+  register int
+    c;
+
+  size_t
+    level;
+
+  c=0;
+  level=0;
+  subexpression=(const char *) NULL;
+  target=NullPrecedence;
+  while (*expression != '\0')
+  {
+    precedence=UndefinedPrecedence;
+    if ((isspace((int) ((char) *expression)) != 0) || (c == (int) '@'))
+      {
+        expression++;
+        continue;
+      }
+    switch (*expression)
+    {
+      case 'A':
+      case 'a':
+      {
+        if (LocaleNCompare(expression,"atan2",5) == 0)
+          {
+            expression+=5;
+            break;
+          }
+        break;
+      }
+      case 'J':
+      case 'j':
+      {
+        if ((LocaleNCompare(expression,"j0",2) == 0) ||
+            (LocaleNCompare(expression,"j1",2) == 0))
+          {
+            expression+=2;
+            break;
+          }
+        break;
+      }
+      case '#':
+      {
+        while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
+          expression++;
+        break;
+      }
+      default:
+        break;
+    }
+    if ((c == (int) '{') || (c == (int) '['))
+      level++;
+    else
+      if ((c == (int) '}') || (c == (int) ']'))
+        level--;
+    if (level == 0)
+      switch ((unsigned char) *expression)
+      {
+        case '~':
+        case '!':
+        {
+          precedence=BitwiseComplementPrecedence;
+          break;
+        }
+        case '^':
+        case '@':
+        {
+          precedence=ExponentPrecedence;
+          break;
+        }
+        default:
+        {
+          if (((c != 0) && ((isdigit((int) ((char) c)) != 0) ||
+               (strchr(")",c) != (char *) NULL))) &&
+              (((islower((int) ((char) *expression)) != 0) ||
+               (strchr("(",(int) *expression) != (char *) NULL)) ||
+               ((isdigit((int) ((char) c)) == 0) &&
+                (isdigit((int) ((char) *expression)) != 0))) &&
+              (strchr("xy",(int) *expression) == (char *) NULL))
+            precedence=MultiplyPrecedence;
+          break;
+        }
+        case '*':
+        case '/':
+        case '%':
+        {
+          precedence=MultiplyPrecedence;
+          break;
+        }
+        case '+':
+        case '-':
+        {
+          if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
+              (isalpha(c) != 0))
+            precedence=AdditionPrecedence;
+          break;
+        }
+        case LeftShiftOperator:
+        case RightShiftOperator:
+        {
+          precedence=ShiftPrecedence;
+          break;
+        }
+        case '<':
+        case LessThanEqualOperator:
+        case GreaterThanEqualOperator:
+        case '>':
+        {
+          precedence=RelationalPrecedence;
+          break;
+        }
+        case EqualOperator:
+        case NotEqualOperator:
+        {
+          precedence=EquivalencyPrecedence;
+          break;
+        }
+        case '&':
+        {
+          precedence=BitwiseAndPrecedence;
+          break;
+        }
+        case '|':
+        {
+          precedence=BitwiseOrPrecedence;
+          break;
+        }
+        case LogicalAndOperator:
+        {
+          precedence=LogicalAndPrecedence;
+          break;
+        }
+        case LogicalOrOperator:
+        {
+          precedence=LogicalOrPrecedence;
+          break;
+        }
+        case ExponentialNotation:
+        {
+          precedence=ExponentialNotationPrecedence;
+          break;
+        }
+        case ':':
+        case '?':
+        {
+          precedence=TernaryPrecedence;
+          break;
+        }
+        case '=':
+        {
+          precedence=AssignmentPrecedence;
+          break;
+        }
+        case ',':
+        {
+          precedence=CommaPrecedence;
+          break;
+        }
+        case ';':
+        {
+          precedence=SeparatorPrecedence;
+          break;
+        }
+      }
+    if ((precedence == BitwiseComplementPrecedence) ||
+        (precedence == TernaryPrecedence) ||
+        (precedence == AssignmentPrecedence))
+      {
+        if (precedence > target)
+          {
+            /*
+              Right-to-left associativity.
+            */
+            target=precedence;
+            subexpression=expression;
+          }
+      }
+    else
+      if (precedence >= target)
+        {
+          /*
+            Left-to-right associativity.
+          */
+          target=precedence;
+          subexpression=expression;
+        }
+    if (strchr("(",(int) *expression) != (char *) NULL)
+      expression=FxSubexpression(expression,exception);
+    c=(int) (*expression++);
+  }
+  return(subexpression);
+}
+
+static MagickRealType FxEvaluateSubexpression(FxInfo *fx_info,
+  const ChannelType channel,const ssize_t x,const ssize_t y,
+  const char *expression,MagickRealType *beta,ExceptionInfo *exception)
+{
+  char
+    *q,
+    subexpression[MaxTextExtent];
+
+  MagickRealType
+    alpha,
+    gamma;
+
+  register const char
+    *p;
+
+  *beta=0.0;
+  if (exception->severity != UndefinedException)
+    return(0.0);
+  while (isspace((int) *expression) != 0)
+    expression++;
+  if (*expression == '\0')
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "MissingExpression","`%s'",expression);
+      return(0.0);
+    }
+  *subexpression='\0';
+  p=FxOperatorPrecedence(expression,exception);
+  if (p != (const char *) NULL)
+    {
+      (void) CopyMagickString(subexpression,expression,(size_t)
+        (p-expression+1));
+      alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
+        exception);
+      switch ((unsigned char) *p)
+      {
+        case '~':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) (~(size_t) *beta);
+          return(*beta);
+        }
+        case '!':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(*beta == 0.0 ? 1.0 : 0.0);
+        }
+        case '^':
+        {
+          *beta=pow((double) alpha,(double) FxEvaluateSubexpression(fx_info,
+            channel,x,y,++p,beta,exception));
+          return(*beta);
+        }
+        case '*':
+        case ExponentialNotation:
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha*(*beta));
+        }
+        case '/':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          if (*beta == 0.0)
+            {
+              if (exception->severity == UndefinedException)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  OptionError,"DivideByZero","`%s'",expression);
+              return(0.0);
+            }
+          return(alpha/(*beta));
+        }
+        case '%':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=fabs(floor(((double) *beta)+0.5));
+          if (*beta == 0.0)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"DivideByZero","`%s'",expression);
+              return(0.0);
+            }
+          return(fmod((double) alpha,(double) *beta));
+        }
+        case '+':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha+(*beta));
+        }
+        case '-':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha-(*beta));
+        }
+        case LeftShiftOperator:
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) ((size_t) (alpha+0.5) << (size_t)
+            (gamma+0.5));
+          return(*beta);
+        }
+        case RightShiftOperator:
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) ((size_t) (alpha+0.5) >> (size_t)
+            (gamma+0.5));
+          return(*beta);
+        }
+        case '<':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha < *beta ? 1.0 : 0.0);
+        }
+        case LessThanEqualOperator:
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha <= *beta ? 1.0 : 0.0);
+        }
+        case '>':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha > *beta ? 1.0 : 0.0);
+        }
+        case GreaterThanEqualOperator:
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha >= *beta ? 1.0 : 0.0);
+        }
+        case EqualOperator:
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(fabs(alpha-(*beta)) <= MagickEpsilon ? 1.0 : 0.0);
+        }
+        case NotEqualOperator:
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(fabs(alpha-(*beta)) > MagickEpsilon ? 1.0 : 0.0);
+        }
+        case '&':
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) ((size_t) (alpha+0.5) & (size_t)
+            (gamma+0.5));
+          return(*beta);
+        }
+        case '|':
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(MagickRealType) ((size_t) (alpha+0.5) | (size_t)
+            (gamma+0.5));
+          return(*beta);
+        }
+        case LogicalAndOperator:
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(alpha > 0.0) && (gamma > 0.0) ? 1.0 : 0.0;
+          return(*beta);
+        }
+        case LogicalOrOperator:
+        {
+          gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          *beta=(alpha > 0.0) || (gamma > 0.0) ? 1.0 : 0.0;
+          return(*beta);
+        }
+        case '?':
+        {
+          MagickRealType
+            gamma;
+
+          (void) CopyMagickString(subexpression,++p,MaxTextExtent);
+          q=subexpression;
+          p=StringToken(":",&q);
+          if (q == (char *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"UnableToParseExpression","`%s'",subexpression);
+              return(0.0);
+            }
+          if (fabs((double) alpha) > MagickEpsilon)
+            gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,exception);
+          else
+            gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,beta,exception);
+          return(gamma);
+        }
+        case '=':
+        {
+          char
+            numeric[MaxTextExtent];
+
+          q=subexpression;
+          while (isalpha((int) ((unsigned char) *q)) != 0)
+            q++;
+          if (*q != '\0')
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionError,"UnableToParseExpression","`%s'",subexpression);
+              return(0.0);
+            }
+          ClearMagickException(exception);
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          (void) FormatLocaleString(numeric,MaxTextExtent,"%g",(double)
+            *beta);
+          (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression);
+          (void) AddValueToSplayTree(fx_info->symbols,ConstantString(
+            subexpression),ConstantString(numeric));
+          return(*beta);
+        }
+        case ',':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(alpha);
+        }
+        case ';':
+        {
+          *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
+          return(*beta);
+        }
+        default:
+        {
+          gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,
+            exception);
+          return(gamma);
+        }
+      }
+    }
+  if (strchr("(",(int) *expression) != (char *) NULL)
+    {
+      (void) CopyMagickString(subexpression,expression+1,MaxTextExtent);
+      subexpression[strlen(subexpression)-1]='\0';
+      gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
+        exception);
+      return(gamma);
+    }
+  switch (*expression)
+  {
+    case '+':
+    {
+      gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
+        exception);
+      return(1.0*gamma);
+    }
+    case '-':
+    {
+      gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
+        exception);
+      return(-1.0*gamma);
+    }
+    case '~':
+    {
+      gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
+        exception);
+      return((MagickRealType) (~(size_t) (gamma+0.5)));
+    }
+    case 'A':
+    case 'a':
+    {
+      if (LocaleNCompare(expression,"abs",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) fabs((double) alpha));
+        }
+      if (LocaleNCompare(expression,"acos",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) acos((double) alpha));
+        }
+#if defined(MAGICKCORE_HAVE_J1)
+      if (LocaleNCompare(expression,"airy",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          if (alpha == 0.0)
+            return(1.0);
+          gamma=2.0*j1((double) (MagickPI*alpha))/(MagickPI*alpha);
+          return(gamma*gamma);
+        }
+#endif
+      if (LocaleNCompare(expression,"asin",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) asin((double) alpha));
+        }
+      if (LocaleNCompare(expression,"alt",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
+        }
+      if (LocaleNCompare(expression,"atan2",5) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
+            exception);
+          return((MagickRealType) atan2((double) alpha,(double) *beta));
+        }
+      if (LocaleNCompare(expression,"atan",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) atan((double) alpha));
+        }
+      if (LocaleCompare(expression,"a") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'B':
+    case 'b':
+    {
+      if (LocaleCompare(expression,"b") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'C':
+    case 'c':
+    {
+      if (LocaleNCompare(expression,"ceil",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) ceil((double) alpha));
+        }
+      if (LocaleNCompare(expression,"cosh",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) cosh((double) alpha));
+        }
+      if (LocaleNCompare(expression,"cos",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) cos((double) alpha));
+        }
+      if (LocaleCompare(expression,"c") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'D':
+    case 'd':
+    {
+      if (LocaleNCompare(expression,"debug",5) == 0)
+        {
+          const char
+            *type;
+
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
+            exception);
+          if (fx_info->images->colorspace == CMYKColorspace)
+            switch (channel)
+            {
+              case CyanChannel: type="cyan"; break;
+              case MagentaChannel: type="magenta"; break;
+              case YellowChannel: type="yellow"; break;
+              case AlphaChannel: type="opacity"; break;
+              case BlackChannel: type="black"; break;
+              default: type="unknown"; break;
+            }
+          else
+            switch (channel)
+            {
+              case RedChannel: type="red"; break;
+              case GreenChannel: type="green"; break;
+              case BlueChannel: type="blue"; break;
+              case AlphaChannel: type="opacity"; break;
+              default: type="unknown"; break;
+            }
+          (void) CopyMagickString(subexpression,expression+6,MaxTextExtent);
+          if (strlen(subexpression) > 1)
+            subexpression[strlen(subexpression)-1]='\0';
+          if (fx_info->file != (FILE *) NULL)
+            (void) FormatLocaleFile(fx_info->file,
+              "%s[%.20g,%.20g].%s: %s=%.*g\n",fx_info->images->filename,
+               (double) x,(double) y,type,subexpression,GetMagickPrecision(),
+               (double) alpha);
+          return(0.0);
+        }
+      break;
+    }
+    case 'E':
+    case 'e':
+    {
+      if (LocaleCompare(expression,"epsilon") == 0)
+        return((MagickRealType) MagickEpsilon);
+      if (LocaleNCompare(expression,"exp",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) exp((double) alpha));
+        }
+      if (LocaleCompare(expression,"e") == 0)
+        return((MagickRealType) 2.7182818284590452354);
+      break;
+    }
+    case 'F':
+    case 'f':
+    {
+      if (LocaleNCompare(expression,"floor",5) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
+            exception);
+          return((MagickRealType) floor((double) alpha));
+        }
+      break;
+    }
+    case 'G':
+    case 'g':
+    {
+      if (LocaleCompare(expression,"g") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'H':
+    case 'h':
+    {
+      if (LocaleCompare(expression,"h") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      if (LocaleCompare(expression,"hue") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      if (LocaleNCompare(expression,"hypot",5) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
+            exception);
+          return((MagickRealType) hypot((double) alpha,(double) *beta));
+        }
+      break;
+    }
+    case 'K':
+    case 'k':
+    {
+      if (LocaleCompare(expression,"k") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'I':
+    case 'i':
+    {
+      if (LocaleCompare(expression,"intensity") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      if (LocaleNCompare(expression,"int",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) floor(alpha));
+        }
+      if (LocaleCompare(expression,"i") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'J':
+    case 'j':
+    {
+      if (LocaleCompare(expression,"j") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+#if defined(MAGICKCORE_HAVE_J0)
+      if (LocaleNCompare(expression,"j0",2) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
+            exception);
+          return((MagickRealType) j0((double) alpha));
+        }
+#endif
+#if defined(MAGICKCORE_HAVE_J1)
+      if (LocaleNCompare(expression,"j1",2) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
+            exception);
+          return((MagickRealType) j1((double) alpha));
+        }
+#endif
+#if defined(MAGICKCORE_HAVE_J1)
+      if (LocaleNCompare(expression,"jinc",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          if (alpha == 0.0)
+            return(1.0);
+          gamma=(MagickRealType) (2.0*j1((double) (MagickPI*alpha))/
+            (MagickPI*alpha));
+          return(gamma);
+        }
+#endif
+      break;
+    }
+    case 'L':
+    case 'l':
+    {
+      if (LocaleNCompare(expression,"ln",2) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
+            exception);
+          return((MagickRealType) log((double) alpha));
+        }
+      if (LocaleNCompare(expression,"logtwo",6) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,beta,
+            exception);
+          return((MagickRealType) log10((double) alpha))/log10(2.0);
+        }
+      if (LocaleNCompare(expression,"log",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) log10((double) alpha));
+        }
+      if (LocaleCompare(expression,"lightness") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'M':
+    case 'm':
+    {
+      if (LocaleCompare(expression,"MaxRGB") == 0)
+        return((MagickRealType) QuantumRange);
+      if (LocaleNCompare(expression,"maxima",6) == 0)
+        break;
+      if (LocaleNCompare(expression,"max",3) == 0)
+        return(FxMax(fx_info,channel,x,y,expression+3,exception));
+      if (LocaleNCompare(expression,"minima",6) == 0)
+        break;
+      if (LocaleNCompare(expression,"min",3) == 0)
+        return(FxMin(fx_info,channel,x,y,expression+3,exception));
+      if (LocaleNCompare(expression,"mod",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) fmod((double) alpha,(double) *beta));
+        }
+      if (LocaleCompare(expression,"m") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'N':
+    case 'n':
+    {
+      if (LocaleCompare(expression,"n") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'O':
+    case 'o':
+    {
+      if (LocaleCompare(expression,"Opaque") == 0)
+        return(1.0);
+      if (LocaleCompare(expression,"o") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'P':
+    case 'p':
+    {
+      if (LocaleCompare(expression,"pi") == 0)
+        return((MagickRealType) MagickPI);
+      if (LocaleNCompare(expression,"pow",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) pow((double) alpha,(double) *beta));
+        }
+      if (LocaleCompare(expression,"p") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'Q':
+    case 'q':
+    {
+      if (LocaleCompare(expression,"QuantumRange") == 0)
+        return((MagickRealType) QuantumRange);
+      if (LocaleCompare(expression,"QuantumScale") == 0)
+        return((MagickRealType) QuantumScale);
+      break;
+    }
+    case 'R':
+    case 'r':
+    {
+      if (LocaleNCompare(expression,"rand",4) == 0)
+        return((MagickRealType) GetPseudoRandomValue(fx_info->random_info));
+      if (LocaleNCompare(expression,"round",5) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
+            exception);
+          return((MagickRealType) floor((double) alpha+0.5));
+        }
+      if (LocaleCompare(expression,"r") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'S':
+    case 's':
+    {
+      if (LocaleCompare(expression,"saturation") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      if (LocaleNCompare(expression,"sign",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return(alpha < 0.0 ? -1.0 : 1.0);
+        }
+      if (LocaleNCompare(expression,"sinc",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          if (alpha == 0)
+            return(1.0);
+          gamma=(MagickRealType) (sin((double) (MagickPI*alpha))/
+            (MagickPI*alpha));
+          return(gamma);
+        }
+      if (LocaleNCompare(expression,"sinh",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) sinh((double) alpha));
+        }
+      if (LocaleNCompare(expression,"sin",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) sin((double) alpha));
+        }
+      if (LocaleNCompare(expression,"sqrt",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) sqrt((double) alpha));
+        }
+      if (LocaleCompare(expression,"s") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'T':
+    case 't':
+    {
+      if (LocaleNCompare(expression,"tanh",4) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
+            exception);
+          return((MagickRealType) tanh((double) alpha));
+        }
+      if (LocaleNCompare(expression,"tan",3) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
+            exception);
+          return((MagickRealType) tan((double) alpha));
+        }
+      if (LocaleCompare(expression,"Transparent") == 0)
+        return(0.0);
+      if (LocaleNCompare(expression,"trunc",5) == 0)
+        {
+          alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
+            exception);
+          if (alpha >= 0.0)
+            return((MagickRealType) floor((double) alpha));
+          return((MagickRealType) ceil((double) alpha));
+        }
+      if (LocaleCompare(expression,"t") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'U':
+    case 'u':
+    {
+      if (LocaleCompare(expression,"u") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'V':
+    case 'v':
+    {
+      if (LocaleCompare(expression,"v") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'W':
+    case 'w':
+    {
+      if (LocaleCompare(expression,"w") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'Y':
+    case 'y':
+    {
+      if (LocaleCompare(expression,"y") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    case 'Z':
+    case 'z':
+    {
+      if (LocaleCompare(expression,"z") == 0)
+        return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+      break;
+    }
+    default:
+      break;
+  }
+  q=(char *) expression;
+  alpha=InterpretLocaleValue(expression,&q);
+  if (q == expression)
+    return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
+  return(alpha);
+}
+
+MagickExport MagickBooleanType FxEvaluateExpression(FxInfo *fx_info,
+  MagickRealType *alpha,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info,
+  MagickRealType *alpha,ExceptionInfo *exception)
+{
+  FILE
+    *file;
+
+  MagickBooleanType
+    status;
+
+  file=fx_info->file;
+  fx_info->file=(FILE *) NULL;
+  status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
+  fx_info->file=file;
+  return(status);
+}
+
+MagickExport MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
+  const ChannelType channel,const ssize_t x,const ssize_t y,
+  MagickRealType *alpha,ExceptionInfo *exception)
+{
+  MagickRealType
+    beta;
+
+  beta=0.0;
+  *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,&beta,
+    exception);
+  return(exception->severity == OptionError ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     F x I m a g e                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FxImage() applies a mathematical expression to the specified image.
+%
+%  The format of the FxImage method is:
+%
+%      Image *FxImage(const Image *image,const char *expression,
+%        ExceptionInfo *exception)
+%      Image *FxImageChannel(const Image *image,const ChannelType channel,
+%        const char *expression,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o expression: A mathematical expression.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
+{
+  register ssize_t
+    i;
+
+  assert(fx_info != (FxInfo **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (fx_info[i] != (FxInfo *) NULL)
+      fx_info[i]=DestroyFxInfo(fx_info[i]);
+  fx_info=(FxInfo **) RelinquishMagickMemory(fx_info);
+  return(fx_info);
+}
+
+static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
+  ExceptionInfo *exception)
+{
+  char
+    *fx_expression;
+
+  FxInfo
+    **fx_info;
+
+  MagickRealType
+    alpha;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info));
+  if (fx_info == (FxInfo **) NULL)
+    return((FxInfo **) NULL);
+  (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info));
+  if (*expression != '@')
+    fx_expression=ConstantString(expression);
+  else
+    fx_expression=FileToString(expression+1,~0,exception);
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    fx_info[i]=AcquireFxInfo(image,fx_expression);
+    if (fx_info[i] == (FxInfo *) NULL)
+      return(DestroyFxThreadSet(fx_info));
+    (void) FxPreprocessExpression(fx_info[i],&alpha,fx_info[i]->exception);
+  }
+  fx_expression=DestroyString(fx_expression);
+  return(fx_info);
+}
+
+MagickExport Image *FxImage(const Image *image,const char *expression,
+  ExceptionInfo *exception)
+{
+  Image
+    *fx_image;
+
+  fx_image=FxImageChannel(image,GrayChannel,expression,exception);
+  return(fx_image);
+}
+
+MagickExport Image *FxImageChannel(const Image *image,const ChannelType channel,
+  const char *expression,ExceptionInfo *exception)
+{
+#define FxImageTag  "Fx/Image"
+
+  CacheView
+    *fx_view;
+
+  FxInfo
+    **restrict fx_info;
+
+  Image
+    *fx_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  MagickRealType
+    alpha;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  fx_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (fx_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&fx_image->exception);
+      fx_image=DestroyImage(fx_image);
+      return((Image *) NULL);
+    }
+  fx_info=AcquireFxThreadSet(image,expression,exception);
+  if (fx_info == (FxInfo **) NULL)
+    {
+      fx_image=DestroyImage(fx_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  status=FxPreprocessExpression(fx_info[0],&alpha,exception);
+  if (status == MagickFalse)
+    {
+      fx_image=DestroyImage(fx_image);
+      fx_info=DestroyFxThreadSet(fx_info);
+      return((Image *) NULL);
+    }
+  /*
+    Fx image.
+  */
+  status=MagickTrue;
+  progress=0;
+  fx_view=AcquireCacheView(fx_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) fx_image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    MagickRealType
+      alpha;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    alpha=0.0;
+    for (x=0; x < (ssize_t) fx_image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],RedChannel,x,y,
+            &alpha,exception);
+          SetPixelRed(fx_image,ClampToQuantum((MagickRealType) QuantumRange*
+            alpha),q);
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],GreenChannel,x,y,
+            &alpha,exception);
+          SetPixelGreen(fx_image,ClampToQuantum((MagickRealType) QuantumRange*
+            alpha),q);
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],BlueChannel,x,y,
+            &alpha,exception);
+          SetPixelBlue(fx_image,ClampToQuantum((MagickRealType) QuantumRange*
+            alpha),q);
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (fx_image->colorspace == CMYKColorspace))
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],BlackChannel,x,y,
+            &alpha,exception);
+          SetPixelBlack(fx_image,ClampToQuantum((MagickRealType) QuantumRange*
+            alpha),q);
+        }
+      if ((channel & AlphaChannel) != 0)
+        {
+          (void) FxEvaluateChannelExpression(fx_info[id],AlphaChannel,x,y,
+            &alpha,exception);
+          SetPixelAlpha(fx_image,ClampToQuantum((MagickRealType) QuantumRange*
+            alpha),q);
+        }
+      q+=GetPixelChannels(fx_image);
+    }
+    if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_FxImageChannel)
+#endif
+        proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  fx_view=DestroyCacheView(fx_view);
+  fx_info=DestroyFxThreadSet(fx_info);
+  if (status == MagickFalse)
+    fx_image=DestroyImage(fx_image);
+  return(fx_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I m p l o d e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImplodeImage() creates a new image that is a copy of an existing
+%  one with the image pixels "implode" by the specified percentage.  It
+%  allocates the memory necessary for the new Image structure and returns a
+%  pointer to the new image.
+%
+%  The format of the ImplodeImage method is:
+%
+%      Image *ImplodeImage(const Image *image,const double amount,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o implode_image: Method ImplodeImage returns a pointer to the image
+%      after it is implode.  A null image is returned if there is a memory
+%      shortage.
+%
+%    o image: the image.
+%
+%    o amount:  Define the extent of the implosion.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ImplodeImage(const Image *image,const double amount,
+  ExceptionInfo *exception)
+{
+#define ImplodeImageTag  "Implode/Image"
+
+  CacheView
+    *image_view,
+    *implode_view;
+
+  Image
+    *implode_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    radius;
+
+  PointInfo
+    center,
+    scale;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize implode image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  implode_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (implode_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(implode_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&implode_image->exception);
+      implode_image=DestroyImage(implode_image);
+      return((Image *) NULL);
+    }
+  if (implode_image->background_color.alpha != OpaqueAlpha)
+    implode_image->matte=MagickTrue;
+  /*
+    Compute scaling factor.
+  */
+  scale.x=1.0;
+  scale.y=1.0;
+  center.x=0.5*image->columns;
+  center.y=0.5*image->rows;
+  radius=center.x;
+  if (image->columns > image->rows)
+    scale.y=(double) image->columns/(double) image->rows;
+  else
+    if (image->columns < image->rows)
+      {
+        scale.x=(double) image->rows/(double) image->columns;
+        radius=center.y;
+      }
+  /*
+    Implode image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(implode_image,&zero);
+  image_view=AcquireCacheView(image);
+  implode_view=AcquireCacheView(implode_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    MagickRealType
+      distance;
+
+    PointInfo
+      delta;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    delta.y=scale.y*(double) (y-center.y);
+    pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      /*
+        Determine if the pixel is within an ellipse.
+      */
+      delta.x=scale.x*(double) (x-center.x);
+      distance=delta.x*delta.x+delta.y*delta.y;
+      if (distance < (radius*radius))
+        {
+          double
+            factor;
+
+          /*
+            Implode the pixel.
+          */
+          factor=1.0;
+          if (distance > 0.0)
+            factor=pow(sin((double) (MagickPI*sqrt((double) distance)/
+              radius/2)),-amount);
+          (void) InterpolatePixelInfo(image,image_view,
+            UndefinedInterpolatePixel,(double) (factor*delta.x/scale.x+
+            center.x),(double) (factor*delta.y/scale.y+center.y),&pixel,
+            exception);
+          SetPixelPixelInfo(implode_image,&pixel,q);
+        }
+      q+=GetPixelChannels(implode_image);
+    }
+    if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ImplodeImage)
+#endif
+        proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  implode_view=DestroyCacheView(implode_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    implode_image=DestroyImage(implode_image);
+  return(implode_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M o r p h I m a g e s                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The MorphImages() method requires a minimum of two images.  The first
+%  image is transformed into the second by a number of intervening images
+%  as specified by frames.
+%
+%  The format of the MorphImage method is:
+%
+%      Image *MorphImages(const Image *image,const size_t number_frames,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o number_frames:  Define the number of in-between image to generate.
+%      The more in-between frames, the smoother the morph.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *MorphImages(const Image *image,
+  const size_t number_frames,ExceptionInfo *exception)
+{
+#define MorphImageTag  "Morph/Image"
+
+  Image
+    *morph_image,
+    *morph_images;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    scene;
+
+  MagickRealType
+    alpha,
+    beta;
+
+  register const Image
+    *next;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Clone first frame in sequence.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  morph_images=CloneImage(image,0,0,MagickTrue,exception);
+  if (morph_images == (Image *) NULL)
+    return((Image *) NULL);
+  if (GetNextImageInList(image) == (Image *) NULL)
+    {
+      /*
+        Morph single image.
+      */
+      for (i=1; i < (ssize_t) number_frames; i++)
+      {
+        morph_image=CloneImage(image,0,0,MagickTrue,exception);
+        if (morph_image == (Image *) NULL)
+          {
+            morph_images=DestroyImageList(morph_images);
+            return((Image *) NULL);
+          }
+        AppendImageToList(&morph_images,morph_image);
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) i,
+              number_frames);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      return(GetFirstImageInList(morph_images));
+    }
+  /*
+    Morph image sequence.
+  */
+  status=MagickTrue;
+  scene=0;
+  next=image;
+  for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    for (i=0; i < (ssize_t) number_frames; i++)
+    {
+      CacheView
+        *image_view,
+        *morph_view;
+
+      beta=(MagickRealType) (i+1.0)/(MagickRealType) (number_frames+1.0);
+      alpha=1.0-beta;
+      morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta*
+        GetNextImageInList(next)->columns+0.5),(size_t) (alpha*
+        next->rows+beta*GetNextImageInList(next)->rows+0.5),
+        next->filter,next->blur,exception);
+      if (morph_image == (Image *) NULL)
+        {
+          morph_images=DestroyImageList(morph_images);
+          return((Image *) NULL);
+        }
+      if (SetImageStorageClass(morph_image,DirectClass) == MagickFalse)
+        {
+          InheritException(exception,&morph_image->exception);
+          morph_image=DestroyImage(morph_image);
+          return((Image *) NULL);
+        }
+      AppendImageToList(&morph_images,morph_image);
+      morph_images=GetLastImageInList(morph_images);
+      morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns,
+        morph_images->rows,GetNextImageInList(next)->filter,
+        GetNextImageInList(next)->blur,exception);
+      if (morph_image == (Image *) NULL)
+        {
+          morph_images=DestroyImageList(morph_images);
+          return((Image *) NULL);
+        }
+      image_view=AcquireCacheView(morph_image);
+      morph_view=AcquireCacheView(morph_images);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) morph_images->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const Quantum
+          *restrict p;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
+          exception);
+        q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
+          exception);
+        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) morph_images->columns; x++)
+        {
+          SetPixelRed(morph_images,ClampToQuantum(alpha*
+            GetPixelRed(morph_images,q)+beta*GetPixelRed(morph_image,p)),q);
+          SetPixelGreen(morph_images,ClampToQuantum(alpha*
+            GetPixelGreen(morph_images,q)+beta*GetPixelGreen(morph_image,p)),q);
+          SetPixelBlue(morph_images,ClampToQuantum(alpha*
+            GetPixelBlue(morph_images,q)+beta*GetPixelBlue(morph_image,p)),q);
+          SetPixelAlpha(morph_images,ClampToQuantum(alpha*
+            GetPixelAlpha(morph_images,q)+beta*GetPixelAlpha(morph_image,p)),q);
+          if ((morph_image->colorspace == CMYKColorspace) &&
+              (morph_images->colorspace == CMYKColorspace))
+            SetPixelBlack(morph_images,ClampToQuantum(alpha*
+              GetPixelBlack(morph_images,q)+beta*GetPixelBlack(morph_image,p)),
+              q);
+          p+=GetPixelChannels(morph_image);
+          q+=GetPixelChannels(morph_images);
+        }
+        sync=SyncCacheViewAuthenticPixels(morph_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      morph_view=DestroyCacheView(morph_view);
+      image_view=DestroyCacheView(image_view);
+      morph_image=DestroyImage(morph_image);
+    }
+    if (i < (ssize_t) number_frames)
+      break;
+    /*
+      Clone last frame in sequence.
+    */
+    morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
+    if (morph_image == (Image *) NULL)
+      {
+        morph_images=DestroyImageList(morph_images);
+        return((Image *) NULL);
+      }
+    AppendImageToList(&morph_images,morph_image);
+    morph_images=GetLastImageInList(morph_images);
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_MorphImages)
+#endif
+        proceed=SetImageProgress(image,MorphImageTag,scene,
+          GetImageListLength(image));
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+    scene++;
+  }
+  if (GetNextImageInList(next) != (Image *) NULL)
+    {
+      morph_images=DestroyImageList(morph_images);
+      return((Image *) NULL);
+    }
+  return(GetFirstImageInList(morph_images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P l a s m a I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PlasmaImage() initializes an image with plasma fractal values.  The image
+%  must be initialized with a base color and the random number generator
+%  seeded before this method is called.
+%
+%  The format of the PlasmaImage method is:
+%
+%      MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
+%        size_t attenuate,size_t depth)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o segment:   Define the region to apply plasma fractals values.
+%
+%    o attenuate: Define the plasma attenuation factor.
+%
+%    o depth: Limit the plasma recursion depth.
+%
+*/
+
+static inline Quantum PlasmaPixel(RandomInfo *random_info,
+  const MagickRealType pixel,const MagickRealType noise)
+{
+  Quantum
+    plasma;
+
+  plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
+    noise/2.0);
+  return(plasma);
+}
+
+MagickExport MagickBooleanType PlasmaImageProxy(Image *image,
+  CacheView *image_view,RandomInfo *random_info,const SegmentInfo *segment,
+  size_t attenuate,size_t depth)
+{
+  ExceptionInfo
+    *exception;
+
+  MagickRealType
+    plasma;
+
+  PixelPacket
+    u,
+    v;
+
+  ssize_t
+    x,
+    x_mid,
+    y,
+    y_mid;
+
+  if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0))
+    return(MagickTrue);
+  if (depth != 0)
+    {
+      SegmentInfo
+        local_info;
+
+      /*
+        Divide the area into quadrants and recurse.
+      */
+      depth--;
+      attenuate++;
+      x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
+      y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
+      local_info=(*segment);
+      local_info.x2=(double) x_mid;
+      local_info.y2=(double) y_mid;
+      (void) PlasmaImageProxy(image,image_view,random_info,&local_info,
+        attenuate,depth);
+      local_info=(*segment);
+      local_info.y1=(double) y_mid;
+      local_info.x2=(double) x_mid;
+      (void) PlasmaImageProxy(image,image_view,random_info,&local_info,
+        attenuate,depth);
+      local_info=(*segment);
+      local_info.x1=(double) x_mid;
+      local_info.y2=(double) y_mid;
+      (void) PlasmaImageProxy(image,image_view,random_info,&local_info,
+        attenuate,depth);
+      local_info=(*segment);
+      local_info.x1=(double) x_mid;
+      local_info.y1=(double) y_mid;
+      return(PlasmaImageProxy(image,image_view,random_info,&local_info,
+        attenuate,depth));
+    }
+  x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
+  y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
+  if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) &&
+      (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid))
+    return(MagickFalse);
+  /*
+    Average pixels and apply plasma.
+  */
+  exception=(&image->exception);
+  plasma=(MagickRealType) QuantumRange/(2.0*attenuate);
+  if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid))
+    {
+      register Quantum
+        *restrict q;
+
+      /*
+        Left pixel.
+      */
+      x=(ssize_t) ceil(segment->x1-0.5);
+      (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
+        ceil(segment->y1-0.5),&u,exception);
+      (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
+        ceil(segment->y2-0.5),&v,exception);
+      q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
+      if (q == (const Quantum *) NULL)
+        return(MagickTrue);
+      SetPixelRed(image,PlasmaPixel(random_info,(MagickRealType)
+        (u.red+v.red)/2.0,plasma),q);
+      SetPixelGreen(image,PlasmaPixel(random_info,(MagickRealType)
+        (u.green+v.green)/2.0,plasma),q);
+      SetPixelBlue(image,PlasmaPixel(random_info,(MagickRealType)
+        (u.blue+v.blue)/2.0,plasma),q);
+      (void) SyncCacheViewAuthenticPixels(image_view,exception);
+      if (segment->x1 != segment->x2)
+        {
+          /*
+            Right pixel.
+          */
+          x=(ssize_t) ceil(segment->x2-0.5);
+          (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
+            ceil(segment->y1-0.5),&u,exception);
+          (void) GetOneCacheViewVirtualPixel(image_view,x,(ssize_t)
+            ceil(segment->y2-0.5),&v,exception);
+          q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
+          if (q == (const Quantum *) NULL)
+            return(MagickTrue);
+          SetPixelRed(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.red+v.red)/2.0,plasma),q);
+          SetPixelGreen(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.green+v.green)/2.0,plasma),q);
+          SetPixelBlue(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.blue+v.blue)/2.0,plasma),q);
+          (void) SyncCacheViewAuthenticPixels(image_view,exception);
+        }
+    }
+  if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
+    {
+      if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
+        {
+          register Quantum
+            *restrict q;
+
+          /*
+            Bottom pixel.
+          */
+          y=(ssize_t) ceil(segment->y2-0.5);
+          (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+            ceil(segment->x1-0.5),y,&u,exception);
+          (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+            ceil(segment->x2-0.5),y,&v,exception);
+          q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
+          if (q == (const Quantum *) NULL)
+            return(MagickTrue);
+          SetPixelRed(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.red+v.red)/2.0,plasma),q);
+          SetPixelGreen(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.green+v.green)/2.0,plasma),q);
+          SetPixelBlue(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.blue+v.blue)/2.0,plasma),q);
+          (void) SyncCacheViewAuthenticPixels(image_view,exception);
+        }
+      if (segment->y1 != segment->y2)
+        {
+          register Quantum
+            *restrict q;
+
+          /*
+            Top pixel.
+          */
+          y=(ssize_t) ceil(segment->y1-0.5);
+          (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+            ceil(segment->x1-0.5),y,&u,exception);
+          (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t)
+            ceil(segment->x2-0.5),y,&v,exception);
+          q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
+          if (q == (const Quantum *) NULL)
+            return(MagickTrue);
+          SetPixelRed(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.red+v.red)/2.0,plasma),q);
+          SetPixelGreen(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.green+v.green)/2.0,plasma),q);
+          SetPixelBlue(image,PlasmaPixel(random_info,(MagickRealType)
+            (u.blue+v.blue)/2.0,plasma),q);
+          (void) SyncCacheViewAuthenticPixels(image_view,exception);
+        }
+    }
+  if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
+    {
+      register Quantum
+        *restrict q;
+
+      /*
+        Middle pixel.
+      */
+      x=(ssize_t) ceil(segment->x1-0.5);
+      y=(ssize_t) ceil(segment->y1-0.5);
+      (void) GetOneVirtualPixel(image,x,y,&u,exception);
+      x=(ssize_t) ceil(segment->x2-0.5);
+      y=(ssize_t) ceil(segment->y2-0.5);
+      (void) GetOneCacheViewVirtualPixel(image_view,x,y,&v,exception);
+      q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception);
+      if (q == (const Quantum *) NULL)
+        return(MagickTrue);
+      SetPixelRed(image,PlasmaPixel(random_info,(MagickRealType)
+        (u.red+v.red)/2.0,plasma),q);
+      SetPixelGreen(image,PlasmaPixel(random_info,(MagickRealType)
+        (u.green+v.green)/2.0,plasma),q);
+      SetPixelBlue(image,PlasmaPixel(random_info,(MagickRealType)
+        (u.blue+v.blue)/2.0,plasma),q);
+      (void) SyncCacheViewAuthenticPixels(image_view,exception);
+    }
+  if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+MagickExport MagickBooleanType PlasmaImage(Image *image,
+  const SegmentInfo *segment,size_t attenuate,size_t depth)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  RandomInfo
+    *random_info;
+
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  image_view=AcquireCacheView(image);
+  random_info=AcquireRandomInfo();
+  status=PlasmaImageProxy(image,image_view,random_info,segment,attenuate,depth);
+  random_info=DestroyRandomInfo(random_info);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P o l a r o i d I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PolaroidImage() simulates a Polaroid picture.
+%
+%  The format of the AnnotateImage method is:
+%
+%      Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
+%        const double angle,ExceptionInfo exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o draw_info: the draw info.
+%
+%    o angle: Apply the effect along this angle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
+  const double angle,ExceptionInfo *exception)
+{
+  const char
+    *value;
+
+  Image
+    *bend_image,
+    *caption_image,
+    *flop_image,
+    *picture_image,
+    *polaroid_image,
+    *rotate_image,
+    *trim_image;
+
+  size_t
+    height;
+
+  ssize_t
+    quantum;
+
+  /*
+    Simulate a Polaroid picture.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
+    image->rows)/25.0,10.0);
+  height=image->rows+2*quantum;
+  caption_image=(Image *) NULL;
+  value=GetImageProperty(image,"Caption");
+  if (value != (const char *) NULL)
+    {
+      char
+        *caption,
+        geometry[MaxTextExtent];
+
+      DrawInfo
+        *annotate_info;
+
+      MagickBooleanType
+        status;
+
+      ssize_t
+        count;
+
+      TypeMetric
+        metrics;
+
+      /*
+        Generate caption image.
+      */
+      caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
+      if (caption_image == (Image *) NULL)
+        return((Image *) NULL);
+      annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
+      caption=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,
+        value);
+      (void) CloneString(&annotate_info->text,caption);
+      count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,&metrics,
+        &caption);
+      status=SetImageExtent(caption_image,image->columns,(size_t)
+        ((count+1)*(metrics.ascent-metrics.descent)+0.5));
+      if (status == MagickFalse)
+        caption_image=DestroyImage(caption_image);
+      else
+        {
+          caption_image->background_color=image->border_color;
+          (void) SetImageBackgroundColor(caption_image);
+          (void) CloneString(&annotate_info->text,caption);
+          (void) FormatLocaleString(geometry,MaxTextExtent,"+0+%g",
+            metrics.ascent);
+          if (annotate_info->gravity == UndefinedGravity)
+            (void) CloneString(&annotate_info->geometry,AcquireString(
+              geometry));
+          (void) AnnotateImage(caption_image,annotate_info);
+          height+=caption_image->rows;
+        }
+      annotate_info=DestroyDrawInfo(annotate_info);
+      caption=DestroyString(caption);
+    }
+  picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
+    exception);
+  if (picture_image == (Image *) NULL)
+    {
+      if (caption_image != (Image *) NULL)
+        caption_image=DestroyImage(caption_image);
+      return((Image *) NULL);
+    }
+  picture_image->background_color=image->border_color;
+  (void) SetImageBackgroundColor(picture_image);
+  (void) CompositeImage(picture_image,OverCompositeOp,image,quantum,quantum);
+  if (caption_image != (Image *) NULL)
+    {
+      (void) CompositeImage(picture_image,OverCompositeOp,caption_image,
+        quantum,(ssize_t) (image->rows+3*quantum/2));
+      caption_image=DestroyImage(caption_image);
+    }
+  (void) QueryColorDatabase("none",&picture_image->background_color,exception);
+  (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel);
+  rotate_image=RotateImage(picture_image,90.0,exception);
+  picture_image=DestroyImage(picture_image);
+  if (rotate_image == (Image *) NULL)
+    return((Image *) NULL);
+  picture_image=rotate_image;
+  bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
+    picture_image->columns,exception);
+  picture_image=DestroyImage(picture_image);
+  if (bend_image == (Image *) NULL)
+    return((Image *) NULL);
+  InheritException(&bend_image->exception,exception);
+  picture_image=bend_image;
+  rotate_image=RotateImage(picture_image,-90.0,exception);
+  picture_image=DestroyImage(picture_image);
+  if (rotate_image == (Image *) NULL)
+    return((Image *) NULL);
+  picture_image=rotate_image;
+  picture_image->background_color=image->background_color;
+  polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
+    exception);
+  if (polaroid_image == (Image *) NULL)
+    {
+      picture_image=DestroyImage(picture_image);
+      return(picture_image);
+    }
+  flop_image=FlopImage(polaroid_image,exception);
+  polaroid_image=DestroyImage(polaroid_image);
+  if (flop_image == (Image *) NULL)
+    {
+      picture_image=DestroyImage(picture_image);
+      return(picture_image);
+    }
+  polaroid_image=flop_image;
+  (void) CompositeImage(polaroid_image,OverCompositeOp,picture_image,
+    (ssize_t) (-0.01*picture_image->columns/2.0),0L);
+  picture_image=DestroyImage(picture_image);
+  (void) QueryColorDatabase("none",&polaroid_image->background_color,exception);
+  rotate_image=RotateImage(polaroid_image,angle,exception);
+  polaroid_image=DestroyImage(polaroid_image);
+  if (rotate_image == (Image *) NULL)
+    return((Image *) NULL);
+  polaroid_image=rotate_image;
+  trim_image=TrimImage(polaroid_image,exception);
+  polaroid_image=DestroyImage(polaroid_image);
+  if (trim_image == (Image *) NULL)
+    return((Image *) NULL);
+  polaroid_image=trim_image;
+  return(polaroid_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S e p i a T o n e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickSepiaToneImage() applies a special effect to the image, similar to the
+%  effect achieved in a photo darkroom by sepia toning.  Threshold ranges from
+%  0 to QuantumRange and is a measure of the extent of the sepia toning.  A
+%  threshold of 80% is a good starting point for a reasonable tone.
+%
+%  The format of the SepiaToneImage method is:
+%
+%      Image *SepiaToneImage(const Image *image,const double threshold,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o threshold: the tone threshold.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
+  ExceptionInfo *exception)
+{
+#define SepiaToneImageTag  "SepiaTone/Image"
+
+  CacheView
+    *image_view,
+    *sepia_view;
+
+  Image
+    *sepia_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize sepia-toned image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  sepia_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (sepia_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(sepia_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&sepia_image->exception);
+      sepia_image=DestroyImage(sepia_image);
+      return((Image *) NULL);
+    }
+  /*
+    Tone each row of the image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  sepia_view=AcquireCacheView(sepia_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        intensity,
+        tone;
+
+      intensity=(MagickRealType) GetPixelIntensity(image,p);
+      tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+
+        (MagickRealType) QuantumRange-threshold;
+      SetPixelRed(sepia_image,ClampToQuantum(tone),q);
+      tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange :
+        intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0;
+      SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
+      tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
+      SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
+      tone=threshold/7.0;
+      if ((MagickRealType) GetPixelGreen(image,q) < tone)
+        SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
+      if ((MagickRealType) GetPixelBlue(image,q) < tone)
+        SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(sepia_image);
+    }
+    if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SepiaToneImage)
+#endif
+        proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  sepia_view=DestroyCacheView(sepia_view);
+  image_view=DestroyCacheView(image_view);
+  (void) NormalizeImage(sepia_image);
+  (void) ContrastImage(sepia_image,MagickTrue);
+  if (status == MagickFalse)
+    sepia_image=DestroyImage(sepia_image);
+  return(sepia_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S h a d o w I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShadowImage() simulates a shadow from the specified image and returns it.
+%
+%  The format of the ShadowImage method is:
+%
+%      Image *ShadowImage(const Image *image,const double opacity,
+%        const double sigma,const ssize_t x_offset,const ssize_t y_offset,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o opacity: percentage transparency.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o x_offset: the shadow x-offset.
+%
+%    o y_offset: the shadow y-offset.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ShadowImage(const Image *image,const double opacity,
+  const double sigma,const ssize_t x_offset,const ssize_t y_offset,
+  ExceptionInfo *exception)
+{
+#define ShadowImageTag  "Shadow/Image"
+
+  CacheView
+    *border_view;
+
+  Image
+    *border_image,
+    *clone_image,
+    *shadow_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    border_info;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  clone_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (clone_image == (Image *) NULL)
+    return((Image *) NULL);
+  (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod);
+  clone_image->compose=OverCompositeOp;
+  border_info.width=(size_t) floor(2.0*sigma+0.5);
+  border_info.height=(size_t) floor(2.0*sigma+0.5);
+  border_info.x=0;
+  border_info.y=0;
+  (void) QueryColorDatabase("none",&clone_image->border_color,exception);
+  border_image=BorderImage(clone_image,&border_info,exception);
+  clone_image=DestroyImage(clone_image);
+  if (border_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (border_image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel);
+  /*
+    Shadow image.
+  */
+  status=MagickTrue;
+  progress=0;
+  border_view=AcquireCacheView(border_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) border_image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(border_view,0,y,border_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) border_image->columns; x++)
+    {
+      SetPixelRed(border_image,border_image->background_color.red,q);
+      SetPixelGreen(border_image,border_image->background_color.green,q);
+      SetPixelBlue(border_image,border_image->background_color.blue,q);
+      if (border_image->matte == MagickFalse)
+        SetPixelAlpha(border_image,border_image->background_color.alpha,q);
+      else
+        SetPixelAlpha(border_image,ClampToQuantum((MagickRealType)
+          (GetPixelAlpha(border_image,q)*opacity/100.0)),q);
+      q+=GetPixelChannels(border_image);
+    }
+    if (SyncCacheViewAuthenticPixels(border_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (border_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ShadowImage)
+#endif
+        proceed=SetImageProgress(border_image,ShadowImageTag,progress++,
+          border_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  border_view=DestroyCacheView(border_view);
+  shadow_image=BlurImageChannel(border_image,AlphaChannel,0.0,sigma,exception);
+  border_image=DestroyImage(border_image);
+  if (shadow_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (shadow_image->page.width == 0)
+    shadow_image->page.width=shadow_image->columns;
+  if (shadow_image->page.height == 0)
+    shadow_image->page.height=shadow_image->rows;
+  shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
+  shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
+  shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
+  shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
+  return(shadow_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S k e t c h I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SketchImage() simulates a pencil sketch.  We convolve the image with a
+%  Gaussian operator of the given radius and standard deviation (sigma).  For
+%  reasonable results, radius should be larger than sigma.  Use a radius of 0
+%  and SketchImage() selects a suitable radius for you.  Angle gives the angle
+%  of the sketch.
+%
+%  The format of the SketchImage method is:
+%
+%    Image *SketchImage(const Image *image,const double radius,
+%      const double sigma,const double angle,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting
+%      the center pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o angle: Apply the effect along this angle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SketchImage(const Image *image,const double radius,
+  const double sigma,const double angle,ExceptionInfo *exception)
+{
+  CacheView
+    *random_view;
+
+  Image
+    *blend_image,
+    *blur_image,
+    *dodge_image,
+    *random_image,
+    *sketch_image;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  RandomInfo
+    **restrict random_info;
+
+  ssize_t
+    y;
+
+  /*
+    Sketch image.
+  */
+  random_image=CloneImage(image,image->columns << 1,image->rows << 1,
+    MagickTrue,exception);
+  if (random_image == (Image *) NULL)
+    return((Image *) NULL);
+  status=MagickTrue;
+  GetPixelInfo(random_image,&zero);
+  random_info=AcquireRandomInfoThreadSet();
+  random_view=AcquireCacheView(random_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) random_image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    PixelInfo
+      pixel;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    for (x=0; x < (ssize_t) random_image->columns; x++)
+    {
+      pixel.red=(MagickRealType) (QuantumRange*
+        GetPseudoRandomValue(random_info[id]));
+      pixel.green=pixel.red;
+      pixel.blue=pixel.red;
+      if (image->colorspace == CMYKColorspace)
+        pixel.black=pixel.red;
+      SetPixelPixelInfo(random_image,&pixel,q);
+      q+=GetPixelChannels(random_image);
+    }
+    if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  random_view=DestroyCacheView(random_view);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  if (status == MagickFalse)
+    {
+      random_image=DestroyImage(random_image);
+      return(random_image);
+    }
+  blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
+  random_image=DestroyImage(random_image);
+  if (blur_image == (Image *) NULL)
+    return((Image *) NULL);
+  dodge_image=EdgeImage(blur_image,radius,exception);
+  blur_image=DestroyImage(blur_image);
+  if (dodge_image == (Image *) NULL)
+    return((Image *) NULL);
+  (void) NormalizeImage(dodge_image);
+  (void) NegateImage(dodge_image,MagickFalse);
+  (void) TransformImage(&dodge_image,(char *) NULL,"50%");
+  sketch_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (sketch_image == (Image *) NULL)
+    {
+      dodge_image=DestroyImage(dodge_image);
+      return((Image *) NULL);
+    }
+  (void) CompositeImage(sketch_image,ColorDodgeCompositeOp,dodge_image,0,0);
+  dodge_image=DestroyImage(dodge_image);
+  blend_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (blend_image == (Image *) NULL)
+    {
+      sketch_image=DestroyImage(sketch_image);
+      return((Image *) NULL);
+    }
+  (void) SetImageArtifact(blend_image,"compose:args","20x80");
+  (void) CompositeImage(sketch_image,BlendCompositeOp,blend_image,0,0);
+  blend_image=DestroyImage(blend_image);
+  return(sketch_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S o l a r i z e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SolarizeImage() applies a special effect to the image, similar to the effect
+%  achieved in a photo darkroom by selectively exposing areas of photo
+%  sensitive paper to light.  Threshold ranges from 0 to QuantumRange and is a
+%  measure of the extent of the solarization.
+%
+%  The format of the SolarizeImage method is:
+%
+%      MagickBooleanType SolarizeImage(Image *image,const double threshold)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o threshold:  Define the extent of the solarization.
+%
+*/
+MagickExport MagickBooleanType SolarizeImage(Image *image,
+  const double threshold)
+{
+#define SolarizeImageTag  "Solarize/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->storage_class == PseudoClass)
+    {
+      register ssize_t
+        i;
+
+      /*
+        Solarize colormap.
+      */
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if ((MagickRealType) image->colormap[i].red > threshold)
+          image->colormap[i].red=(Quantum) QuantumRange-image->colormap[i].red;
+        if ((MagickRealType) image->colormap[i].green > threshold)
+          image->colormap[i].green=(Quantum) QuantumRange-
+            image->colormap[i].green;
+        if ((MagickRealType) image->colormap[i].blue > threshold)
+          image->colormap[i].blue=(Quantum) QuantumRange-
+            image->colormap[i].blue;
+      }
+    }
+  /*
+    Solarize image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((MagickRealType) GetPixelRed(image,q) > threshold)
+        SetPixelRed(image,QuantumRange-GetPixelRed(image,q),q);
+      if ((MagickRealType) GetPixelGreen(image,q) > threshold)
+        SetPixelGreen(image,QuantumRange-GetPixelGreen(image,q),q);
+      if ((MagickRealType) GetPixelBlue(image,q) > threshold)
+        SetPixelBlue(image,QuantumRange-GetPixelBlue(image,q),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SolarizeImage)
+#endif
+        proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t e g a n o I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SteganoImage() hides a digital watermark within the image.  Recover
+%  the hidden watermark later to prove that the authenticity of an image.
+%  Offset defines the start position within the image to hide the watermark.
+%
+%  The format of the SteganoImage method is:
+%
+%      Image *SteganoImage(const Image *image,Image *watermark,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o watermark: the watermark image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
+  ExceptionInfo *exception)
+{
+#define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
+#define SetBit(alpha,i,set) (Quantum) ((set) != 0 ? (size_t) (alpha) \
+  | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
+#define SteganoImageTag  "Stegano/Image"
+
+  CacheView
+    *stegano_view,
+    *watermark_view;
+
+  Image
+    *stegano_image;
+
+  int
+    c;
+
+  MagickBooleanType
+    status;
+
+  PixelPacket
+    pixel;
+
+  register Quantum
+    *q;
+
+  register ssize_t
+    x;
+
+  size_t
+    depth,
+    one;
+
+  ssize_t
+    i,
+    j,
+    k,
+    y;
+
+  /*
+    Initialize steganographic image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(watermark != (const Image *) NULL);
+  assert(watermark->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  one=1UL;
+  stegano_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (stegano_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(stegano_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&stegano_image->exception);
+      stegano_image=DestroyImage(stegano_image);
+      return((Image *) NULL);
+    }
+  stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
+  /*
+    Hide watermark in low-order bits of image.
+  */
+  c=0;
+  i=0;
+  j=0;
+  depth=stegano_image->depth;
+  k=image->offset;
+  status=MagickTrue;
+  watermark_view=AcquireCacheView(watermark);
+  stegano_view=AcquireCacheView(stegano_image);
+  for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
+  {
+    for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
+    {
+      for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
+      {
+        (void) GetOneCacheViewVirtualPixel(watermark_view,x,y,&pixel,exception);
+        if ((k/(ssize_t) stegano_image->columns) >= (ssize_t) stegano_image->rows)
+          break;
+        q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
+          stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          break;
+        switch (c)
+        {
+          case 0:
+          {
+            SetPixelRed(image,SetBit(GetPixelRed(image,q),j,GetBit(
+              GetPixelPacketIntensity(&pixel),i)),q);
+            break;
+          }
+          case 1:
+          {
+            SetPixelGreen(image,SetBit(GetPixelGreen(image,q),j,GetBit(
+              GetPixelPacketIntensity(&pixel),i)),q);
+            break;
+          }
+          case 2:
+          {
+            SetPixelBlue(image,SetBit(GetPixelBlue(image,q),j,GetBit(
+              GetPixelPacketIntensity(&pixel),i)),q);
+            break;
+          }
+        }
+        if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
+          break;
+        c++;
+        if (c == 3)
+          c=0;
+        k++;
+        if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
+          k=0;
+        if (k == image->offset)
+          j++;
+      }
+    }
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
+          (depth-i),depth);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  stegano_view=DestroyCacheView(stegano_view);
+  watermark_view=DestroyCacheView(watermark_view);
+  if (stegano_image->storage_class == PseudoClass)
+    (void) SyncImage(stegano_image);
+  if (status == MagickFalse)
+    {
+      stegano_image=DestroyImage(stegano_image);
+      return((Image *) NULL);
+    }
+  return(stegano_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t e r e o A n a g l y p h I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StereoAnaglyphImage() combines two images and produces a single image that
+%  is the composite of a left and right image of a stereo pair.  Special
+%  red-green stereo glasses are required to view this effect.
+%
+%  The format of the StereoAnaglyphImage method is:
+%
+%      Image *StereoImage(const Image *left_image,const Image *right_image,
+%        ExceptionInfo *exception)
+%      Image *StereoAnaglyphImage(const Image *left_image,
+%        const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o left_image: the left image.
+%
+%    o right_image: the right image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+%    o x_offset: amount, in pixels, by which the left image is offset to the
+%      right of the right image.
+%
+%    o y_offset: amount, in pixels, by which the left image is offset to the
+%      bottom of the right image.
+%
+%
+*/
+MagickExport Image *StereoImage(const Image *left_image,
+  const Image *right_image,ExceptionInfo *exception)
+{
+  return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
+}
+
+MagickExport Image *StereoAnaglyphImage(const Image *left_image,
+  const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
+  ExceptionInfo *exception)
+{
+#define StereoImageTag  "Stereo/Image"
+
+  const Image
+    *image;
+
+  Image
+    *stereo_image;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(left_image != (const Image *) NULL);
+  assert(left_image->signature == MagickSignature);
+  if (left_image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      left_image->filename);
+  assert(right_image != (const Image *) NULL);
+  assert(right_image->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert(right_image != (const Image *) NULL);
+  image=left_image;
+  if ((left_image->columns != right_image->columns) ||
+      (left_image->rows != right_image->rows))
+    ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
+  /*
+    Initialize stereo image attributes.
+  */
+  stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
+    MagickTrue,exception);
+  if (stereo_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(stereo_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&stereo_image->exception);
+      stereo_image=DestroyImage(stereo_image);
+      return((Image *) NULL);
+    }
+  /*
+    Copy left image to red channel and right image to blue channel.
+  */
+  status=MagickTrue;
+  for (y=0; y < (ssize_t) stereo_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict r;
+
+    p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
+      exception);
+    q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
+    r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
+    if ((p == (const Quantum *) NULL) ||
+        (q == (const Quantum *) NULL) || (r == (Quantum *) NULL))
+      break;
+    for (x=0; x < (ssize_t) stereo_image->columns; x++)
+    {
+      SetPixelRed(image,GetPixelRed(left_image,p),r);
+      SetPixelGreen(image,GetPixelGreen(left_image,q),r);
+      SetPixelBlue(image,GetPixelBlue(left_image,q),r);
+      SetPixelAlpha(image,(GetPixelAlpha(left_image,p)+
+        GetPixelAlpha(left_image,q))/2,r);
+      p+=GetPixelChannels(left_image);
+      q++;
+      r++;
+    }
+    if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
+      break;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
+          stereo_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  if (status == MagickFalse)
+    {
+      stereo_image=DestroyImage(stereo_image);
+      return((Image *) NULL);
+    }
+  return(stereo_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S w i r l I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SwirlImage() swirls the pixels about the center of the image, where
+%  degrees indicates the sweep of the arc through which each pixel is moved.
+%  You get a more dramatic effect as the degrees move from 1 to 360.
+%
+%  The format of the SwirlImage method is:
+%
+%      Image *SwirlImage(const Image *image,double degrees,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o degrees: Define the tightness of the swirling effect.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SwirlImage(const Image *image,double degrees,
+  ExceptionInfo *exception)
+{
+#define SwirlImageTag  "Swirl/Image"
+
+  CacheView
+    *image_view,
+    *swirl_view;
+
+  Image
+    *swirl_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    radius;
+
+  PointInfo
+    center,
+    scale;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize swirl image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  swirl_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (swirl_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(swirl_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&swirl_image->exception);
+      swirl_image=DestroyImage(swirl_image);
+      return((Image *) NULL);
+    }
+  if (swirl_image->background_color.alpha != OpaqueAlpha)
+    swirl_image->matte=MagickTrue;
+  /*
+    Compute scaling factor.
+  */
+  center.x=(double) image->columns/2.0;
+  center.y=(double) image->rows/2.0;
+  radius=MagickMax(center.x,center.y);
+  scale.x=1.0;
+  scale.y=1.0;
+  if (image->columns > image->rows)
+    scale.y=(double) image->columns/(double) image->rows;
+  else
+    if (image->columns < image->rows)
+      scale.x=(double) image->rows/(double) image->columns;
+  degrees=(double) DegreesToRadians(degrees);
+  /*
+    Swirl image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(swirl_image,&zero);
+  image_view=AcquireCacheView(image);
+  swirl_view=AcquireCacheView(swirl_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    MagickRealType
+      distance;
+
+    PointInfo
+      delta;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    delta.y=scale.y*(double) (y-center.y);
+    pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      /*
+        Determine if the pixel is within an ellipse.
+      */
+      delta.x=scale.x*(double) (x-center.x);
+      distance=delta.x*delta.x+delta.y*delta.y;
+      if (distance < (radius*radius))
+        {
+          MagickRealType
+            cosine,
+            factor,
+            sine;
+
+          /*
+            Swirl the pixel.
+          */
+          factor=1.0-sqrt((double) distance)/radius;
+          sine=sin((double) (degrees*factor*factor));
+          cosine=cos((double) (degrees*factor*factor));
+          (void) InterpolatePixelInfo(image,image_view,
+            UndefinedInterpolatePixel,(double) ((cosine*delta.x-sine*delta.y)/
+            scale.x+center.x),(double) ((sine*delta.x+cosine*delta.y)/scale.y+
+            center.y),&pixel,exception);
+          SetPixelPixelInfo(swirl_image,&pixel,q);
+        }
+      q+=GetPixelChannels(swirl_image);
+    }
+    if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SwirlImage)
+#endif
+        proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  swirl_view=DestroyCacheView(swirl_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    swirl_image=DestroyImage(swirl_image);
+  return(swirl_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T i n t I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TintImage() applies a color vector to each pixel in the image.  The length
+%  of the vector is 0 for black and white and at its maximum for the midtones.
+%  The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
+%
+%  The format of the TintImage method is:
+%
+%      Image *TintImage(const Image *image,const char *opacity,
+%        const PixelPacket tint,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o opacity: A color value used for tinting.
+%
+%    o tint: A color value used for tinting.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *TintImage(const Image *image,const char *opacity,
+  const PixelPacket tint,ExceptionInfo *exception)
+{
+#define TintImageTag  "Tint/Image"
+
+  CacheView
+    *image_view,
+    *tint_view;
+
+  GeometryInfo
+    geometry_info;
+
+  Image
+    *tint_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    color_vector,
+    pixel;
+
+  MagickStatusType
+    flags;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate tint image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (tint_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(tint_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&tint_image->exception);
+      tint_image=DestroyImage(tint_image);
+      return((Image *) NULL);
+    }
+  if (opacity == (const char *) NULL)
+    return(tint_image);
+  /*
+    Determine RGB values of the color.
+  */
+  flags=ParseGeometry(opacity,&geometry_info);
+  pixel.red=geometry_info.rho;
+  if ((flags & SigmaValue) != 0)
+    pixel.green=geometry_info.sigma;
+  else
+    pixel.green=pixel.red;
+  if ((flags & XiValue) != 0)
+    pixel.blue=geometry_info.xi;
+  else
+    pixel.blue=pixel.red;
+  if ((flags & PsiValue) != 0)
+    pixel.alpha=geometry_info.psi;
+  else
+    pixel.alpha=(MagickRealType) OpaqueAlpha;
+  color_vector.red=(MagickRealType) (pixel.red*tint.red/100.0-
+    GetPixelPacketIntensity(&tint));
+  color_vector.green=(MagickRealType) (pixel.green*tint.green/100.0-
+    GetPixelPacketIntensity(&tint));
+  color_vector.blue=(MagickRealType) (pixel.blue*tint.blue/100.0-
+    GetPixelPacketIntensity(&tint));
+  /*
+    Tint image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  tint_view=AcquireCacheView(tint_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        weight;
+
+      weight=QuantumScale*GetPixelRed(image,p)-0.5;
+      pixel.red=(MagickRealType) GetPixelRed(image,p)+color_vector.red*
+        (1.0-(4.0*(weight*weight)));
+      SetPixelRed(tint_image,ClampToQuantum(pixel.red),q);
+      weight=QuantumScale*GetPixelGreen(image,p)-0.5;
+      pixel.green=(MagickRealType) GetPixelGreen(image,p)+color_vector.green*
+        (1.0-(4.0*(weight*weight)));
+      SetPixelGreen(tint_image,ClampToQuantum(pixel.green),q);
+      weight=QuantumScale*GetPixelBlue(image,p)-0.5;
+      pixel.blue=(MagickRealType) GetPixelBlue(image,p)+color_vector.blue*
+        (1.0-(4.0*(weight*weight)));
+      SetPixelBlue(tint_image,ClampToQuantum(pixel.blue),q);
+      SetPixelAlpha(tint_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(tint_image);
+    }
+    if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TintImage)
+#endif
+        proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  tint_view=DestroyCacheView(tint_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    tint_image=DestroyImage(tint_image);
+  return(tint_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     V i g n e t t e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  VignetteImage() softens the edges of the image in vignette style.
+%
+%  The format of the VignetteImage method is:
+%
+%      Image *VignetteImage(const Image *image,const double radius,
+%        const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius: the radius of the pixel neighborhood.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+%    o x, y:  Define the x and y ellipse offset.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *VignetteImage(const Image *image,const double radius,
+  const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
+{
+  char
+    ellipse[MaxTextExtent];
+
+  DrawInfo
+    *draw_info;
+
+  Image
+    *canvas_image,
+    *blur_image,
+    *oval_image,
+    *vignette_image;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (canvas_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(canvas_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&canvas_image->exception);
+      canvas_image=DestroyImage(canvas_image);
+      return((Image *) NULL);
+    }
+  canvas_image->matte=MagickTrue;
+  oval_image=CloneImage(canvas_image,canvas_image->columns,
+    canvas_image->rows,MagickTrue,exception);
+  if (oval_image == (Image *) NULL)
+    {
+      canvas_image=DestroyImage(canvas_image);
+      return((Image *) NULL);
+    }
+  (void) QueryColorDatabase("#000000",&oval_image->background_color,exception);
+  (void) SetImageBackgroundColor(oval_image);
+  draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
+  (void) QueryColorDatabase("#ffffff",&draw_info->fill,exception);
+  (void) QueryColorDatabase("#ffffff",&draw_info->stroke,exception);
+  (void) FormatLocaleString(ellipse,MaxTextExtent,
+    "ellipse %g,%g,%g,%g,0.0,360.0",image->columns/2.0,
+    image->rows/2.0,image->columns/2.0-x,image->rows/2.0-y);
+  draw_info->primitive=AcquireString(ellipse);
+  (void) DrawImage(oval_image,draw_info);
+  draw_info=DestroyDrawInfo(draw_info);
+  blur_image=BlurImage(oval_image,radius,sigma,exception);
+  oval_image=DestroyImage(oval_image);
+  if (blur_image == (Image *) NULL)
+    {
+      canvas_image=DestroyImage(canvas_image);
+      return((Image *) NULL);
+    }
+  blur_image->matte=MagickFalse;
+  (void) CompositeImage(canvas_image,CopyOpacityCompositeOp,blur_image,0,0);
+  blur_image=DestroyImage(blur_image);
+  vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
+  canvas_image=DestroyImage(canvas_image);
+  return(vignette_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     W a v e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WaveImage() creates a "ripple" effect in the image by shifting the pixels
+%  vertically along a sine wave whose amplitude and wavelength is specified
+%  by the given parameters.
+%
+%  The format of the WaveImage method is:
+%
+%      Image *WaveImage(const Image *image,const double amplitude,
+%        const double wave_length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o amplitude, wave_length:  Define the amplitude and wave length of the
+%      sine wave.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *WaveImage(const Image *image,const double amplitude,
+  const double wave_length,ExceptionInfo *exception)
+{
+#define WaveImageTag  "Wave/Image"
+
+  CacheView
+    *image_view,
+    *wave_view;
+
+  Image
+    *wave_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    *sine_map;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize wave image attributes.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  wave_image=CloneImage(image,image->columns,(size_t) (image->rows+2.0*
+    fabs(amplitude)),MagickTrue,exception);
+  if (wave_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(wave_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&wave_image->exception);
+      wave_image=DestroyImage(wave_image);
+      return((Image *) NULL);
+    }
+  if (wave_image->background_color.alpha != OpaqueAlpha)
+    wave_image->matte=MagickTrue;
+  /*
+    Allocate sine map.
+  */
+  sine_map=(MagickRealType *) AcquireQuantumMemory((size_t) wave_image->columns,
+    sizeof(*sine_map));
+  if (sine_map == (MagickRealType *) NULL)
+    {
+      wave_image=DestroyImage(wave_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  for (i=0; i < (ssize_t) wave_image->columns; i++)
+    sine_map[i]=fabs(amplitude)+amplitude*sin((double) ((2.0*MagickPI*i)/
+      wave_length));
+  /*
+    Wave image.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(wave_image,&zero);
+  image_view=AcquireCacheView(image);
+  wave_view=AcquireCacheView(wave_image);
+  (void) SetCacheViewVirtualPixelMethod(image_view,
+    BackgroundVirtualPixelMethod);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) wave_image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    for (x=0; x < (ssize_t) wave_image->columns; x++)
+    {
+      (void) InterpolatePixelInfo(image,image_view,
+        UndefinedInterpolatePixel,(double) x,(double) (y-sine_map[x]),&pixel,
+        exception);
+      SetPixelPixelInfo(wave_image,&pixel,q);
+      q+=GetPixelChannels(wave_image);
+    }
+    if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_WaveImage)
+#endif
+        proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  wave_view=DestroyCacheView(wave_view);
+  image_view=DestroyCacheView(image_view);
+  sine_map=(MagickRealType *) RelinquishMagickMemory(sine_map);
+  if (status == MagickFalse)
+    wave_image=DestroyImage(wave_image);
+  return(wave_image);
+}
diff --git a/MagickCore/fx.h b/MagickCore/fx.h
new file mode 100644
index 0000000..67f6e55
--- /dev/null
+++ b/MagickCore/fx.h
@@ -0,0 +1,75 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image f/x methods.
+*/
+#ifndef _MAGICKCORE_FX_H
+#define _MAGICKCORE_FX_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/draw.h"
+
+typedef enum
+{
+  UndefinedNoise,
+  UniformNoise,
+  GaussianNoise,
+  MultiplicativeGaussianNoise,
+  ImpulseNoise,
+  LaplacianNoise,
+  PoissonNoise,
+  RandomNoise
+} NoiseType;
+
+extern MagickExport Image
+  *AddNoiseImage(const Image *,const NoiseType,ExceptionInfo *),
+  *AddNoiseImageChannel(const Image *,const ChannelType,const NoiseType,
+    ExceptionInfo *),
+  *BlueShiftImage(const Image *,const double,ExceptionInfo *),
+  *CharcoalImage(const Image *,const double,const double,ExceptionInfo *),
+  *ColorizeImage(const Image *,const char *,const PixelPacket,ExceptionInfo *),
+  *ColorMatrixImage(const Image *,const KernelInfo *kernel,ExceptionInfo *),
+  *FxImage(const Image *,const char *,ExceptionInfo *),
+  *FxImageChannel(const Image *,const ChannelType,const char *,ExceptionInfo *),
+  *ImplodeImage(const Image *,const double,ExceptionInfo *),
+  *MorphImages(const Image *,const size_t,ExceptionInfo *),
+  *PolaroidImage(const Image *,const DrawInfo *,const double,ExceptionInfo *),
+  *SepiaToneImage(const Image *,const double,ExceptionInfo *),
+  *ShadowImage(const Image *,const double,const double,const ssize_t,
+    const ssize_t,ExceptionInfo *),
+  *SketchImage(const Image *,const double,const double,const double,
+    ExceptionInfo *),
+  *SteganoImage(const Image *,const Image *,ExceptionInfo *),
+  *StereoImage(const Image *,const Image *,ExceptionInfo *),
+  *StereoAnaglyphImage(const Image *,const Image *,const ssize_t,const ssize_t,
+     ExceptionInfo *),
+  *SwirlImage(const Image *,double,ExceptionInfo *),
+  *TintImage(const Image *,const char *,const PixelPacket,ExceptionInfo *),
+  *VignetteImage(const Image *,const double,const double,const ssize_t,
+    const ssize_t,ExceptionInfo *),
+  *WaveImage(const Image *,const double,const double,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  PlasmaImage(Image *,const SegmentInfo *,size_t,size_t),
+  SolarizeImage(Image *,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/gem.c b/MagickCore/gem.c
new file mode 100644
index 0000000..cf479c1
--- /dev/null
+++ b/MagickCore/gem.c
@@ -0,0 +1,835 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                              GGGG  EEEEE  M   M                             %
+%                             G      E      MM MM                             %
+%                             G GG   EEE    M M M                             %
+%                             G   G  E      M   M                             %
+%                              GGGG  EEEEE  M   M                             %
+%                                                                             %
+%                                                                             %
+%                    Graphic Gems - Graphic Support Methods                   %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                 August 1996                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/signature-private.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t H S B T o R G B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHSBToRGB() transforms a (hue, saturation, brightness) to a (red,
+%  green, blue) triple.
+%
+%  The format of the ConvertHSBToRGBImage method is:
+%
+%      void ConvertHSBToRGB(const double hue,const double saturation,
+%        const double brightness,Quantum *red,Quantum *green,Quantum *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, saturation, brightness: A double value representing a
+%      component of the HSB color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickExport void ConvertHSBToRGB(const double hue,const double saturation,
+  const double brightness,Quantum *red,Quantum *green,Quantum *blue)
+{
+  MagickRealType
+    f,
+    h,
+    p,
+    q,
+    t;
+
+  /*
+    Convert HSB to RGB colorspace.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  if (saturation == 0.0)
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *green=(*red);
+      *blue=(*red);
+      return;
+    }
+  h=6.0*(hue-floor(hue));
+  f=h-floor((double) h);
+  p=brightness*(1.0-saturation);
+  q=brightness*(1.0-saturation*f);
+  t=brightness*(1.0-(saturation*(1.0-f)));
+  switch ((int) h)
+  {
+    case 0:
+    default:
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*t);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
+      break;
+    }
+    case 1:
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*q);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
+      break;
+    }
+    case 2:
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*p);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*t);
+      break;
+    }
+    case 3:
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*p);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*q);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      break;
+    }
+    case 4:
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*t);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*p);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      break;
+    }
+    case 5:
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*p);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*q);
+      break;
+    }
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t H S L T o R G B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
+%  green, blue) triple.
+%
+%  The format of the ConvertHSLToRGBImage method is:
+%
+%      void ConvertHSLToRGB(const double hue,const double saturation,
+%        const double lightness,Quantum *red,Quantum *green,Quantum *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, saturation, lightness: A double value representing a
+%      component of the HSL color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+
+static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
+  MagickRealType m2,MagickRealType hue)
+{
+  if (hue < 0.0)
+    hue+=1.0;
+  if (hue > 1.0)
+    hue-=1.0;
+  if ((6.0*hue) < 1.0)
+    return(m1+6.0*(m2-m1)*hue);
+  if ((2.0*hue) < 1.0)
+    return(m2);
+  if ((3.0*hue) < 2.0)
+    return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
+  return(m1);
+}
+
+MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
+  const double lightness,Quantum *red,Quantum *green,Quantum *blue)
+{
+  MagickRealType
+    b,
+    g,
+    r,
+    m1,
+    m2;
+
+  /*
+    Convert HSL to RGB colorspace.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  if (saturation == 0)
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*lightness);
+      *green=(*red);
+      *blue=(*red);
+      return;
+    }
+  if (lightness < 0.5)
+    m2=lightness*(saturation+1.0);
+  else
+    m2=(lightness+saturation)-(lightness*saturation);
+  m1=2.0*lightness-m2;
+  r=ConvertHueToRGB(m1,m2,hue+1.0/3.0);
+  g=ConvertHueToRGB(m1,m2,hue);
+  b=ConvertHueToRGB(m1,m2,hue-1.0/3.0);
+  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
+  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
+  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t H W B T o R G B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
+%  blue) triple.
+%
+%  The format of the ConvertHWBToRGBImage method is:
+%
+%      void ConvertHWBToRGB(const double hue,const double whiteness,
+%        const double blackness,Quantum *red,Quantum *green,Quantum *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, whiteness, blackness: A double value representing a
+%      component of the HWB color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickExport void ConvertHWBToRGB(const double hue,const double whiteness,
+  const double blackness,Quantum *red,Quantum *green,Quantum *blue)
+{
+  MagickRealType
+    b,
+    f,
+    g,
+    n,
+    r,
+    v;
+
+  register ssize_t
+    i;
+
+  /*
+    Convert HWB to RGB colorspace.
+  */
+  assert(red != (Quantum *) NULL);
+  assert(green != (Quantum *) NULL);
+  assert(blue != (Quantum *) NULL);
+  v=1.0-blackness;
+  if (hue == 0.0)
+    {
+      *red=ClampToQuantum((MagickRealType) QuantumRange*v);
+      *green=ClampToQuantum((MagickRealType) QuantumRange*v);
+      *blue=ClampToQuantum((MagickRealType) QuantumRange*v);
+      return;
+    }
+  i=(ssize_t) floor(6.0*hue);
+  f=6.0*hue-i;
+  if ((i & 0x01) != 0)
+    f=1.0-f;
+  n=whiteness+f*(v-whiteness);  /* linear interpolation */
+  switch (i)
+  {
+    default:
+    case 6:
+    case 0: r=v; g=n; b=whiteness; break;
+    case 1: r=n; g=v; b=whiteness; break;
+    case 2: r=whiteness; g=v; b=n; break;
+    case 3: r=whiteness; g=n; b=v; break;
+    case 4: r=n; g=whiteness; b=v; break;
+    case 5: r=v; g=whiteness; b=n; break;
+  }
+  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
+  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
+  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o H S B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
+%  brightness) triple.
+%
+%  The format of the ConvertRGBToHSB method is:
+%
+%      void ConvertRGBToHSB(const Quantum red,const Quantum green,
+%        const Quantum blue,double *hue,double *saturation,double *brightness)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel..
+%
+%    o hue, saturation, brightness: A pointer to a double value representing a
+%      component of the HSB color space.
+%
+*/
+MagickExport void ConvertRGBToHSB(const Quantum red,const Quantum green,
+  const Quantum blue,double *hue,double *saturation,double *brightness)
+{
+  MagickRealType
+    delta,
+    max,
+    min;
+
+  /*
+    Convert RGB to HSB colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(saturation != (double *) NULL);
+  assert(brightness != (double *) NULL);
+  *hue=0.0;
+  *saturation=0.0;
+  *brightness=0.0;
+  min=(MagickRealType) (red < green ? red : green);
+  if ((MagickRealType) blue < min)
+    min=(MagickRealType) blue;
+  max=(MagickRealType) (red > green ? red : green);
+  if ((MagickRealType) blue > max)
+    max=(MagickRealType) blue;
+  if (max == 0.0)
+    return;
+  delta=max-min;
+  *saturation=(double) (delta/max);
+  *brightness=(double) (QuantumScale*max);
+  if (delta == 0.0)
+    return;
+  if ((MagickRealType) red == max)
+    *hue=(double) ((green-(MagickRealType) blue)/delta);
+  else
+    if ((MagickRealType) green == max)
+      *hue=(double) (2.0+(blue-(MagickRealType) red)/delta);
+    else
+      *hue=(double) (4.0+(red-(MagickRealType) green)/delta);
+  *hue/=6.0;
+  if (*hue < 0.0)
+    *hue+=1.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o H S L                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
+%  lightness) triple.
+%
+%  The format of the ConvertRGBToHSL method is:
+%
+%      void ConvertRGBToHSL(const Quantum red,const Quantum green,
+%        const Quantum blue,double *hue,double *saturation,double *lightness)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel..
+%
+%    o hue, saturation, lightness: A pointer to a double value representing a
+%      component of the HSL color space.
+%
+*/
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport void ConvertRGBToHSL(const Quantum red,const Quantum green,
+  const Quantum blue,double *hue,double *saturation,double *lightness)
+{
+  MagickRealType
+    b,
+    delta,
+    g,
+    max,
+    min,
+    r;
+
+  /*
+    Convert RGB to HSL colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(saturation != (double *) NULL);
+  assert(lightness != (double *) NULL);
+  r=QuantumScale*red;
+  g=QuantumScale*green;
+  b=QuantumScale*blue;
+  max=MagickMax(r,MagickMax(g,b));
+  min=MagickMin(r,MagickMin(g,b));
+  *lightness=(double) ((min+max)/2.0);
+  delta=max-min;
+  if (delta == 0.0)
+    {
+      *hue=0.0;
+      *saturation=0.0;
+      return;
+    }
+  if (*lightness < 0.5)
+    *saturation=(double) (delta/(min+max));
+  else
+    *saturation=(double) (delta/(2.0-max-min));
+  if (r == max)
+    *hue=((((max-b)/6.0)+(delta/2.0))-(((max-g)/6.0)+(delta/2.0)))/delta;
+  else
+    if (g == max)
+      *hue=(1.0/3.0)+((((max-r)/6.0)+(delta/2.0))-(((max-b)/6.0)+(delta/2.0)))/
+        delta;
+    else
+      if (b == max)
+        *hue=(2.0/3.0)+((((max-g)/6.0)+(delta/2.0))-(((max-r)/6.0)+
+          (delta/2.0)))/delta;
+  if (*hue < 0.0)
+    *hue+=1.0;
+  if (*hue > 1.0)
+    *hue-=1.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o H W B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
+%  blackness) triple.
+%
+%  The format of the ConvertRGBToHWB method is:
+%
+%      void ConvertRGBToHWB(const Quantum red,const Quantum green,
+%        const Quantum blue,double *hue,double *whiteness,double *blackness)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel.
+%
+%    o hue, whiteness, blackness: A pointer to a double value representing a
+%      component of the HWB color space.
+%
+*/
+MagickExport void ConvertRGBToHWB(const Quantum red,const Quantum green,
+  const Quantum blue,double *hue,double *whiteness,double *blackness)
+{
+  long
+    i;
+
+  MagickRealType
+    f,
+    v,
+    w;
+
+  /*
+    Convert RGB to HWB colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(whiteness != (double *) NULL);
+  assert(blackness != (double *) NULL);
+  w=(MagickRealType) MagickMin((double) red,MagickMin((double) green,(double)
+    blue));
+  v=(MagickRealType) MagickMax((double) red,MagickMax((double) green,(double)
+    blue));
+  *blackness=1.0-QuantumScale*v;
+  *whiteness=QuantumScale*w;
+  if (v == w)
+    {
+      *hue=0.0;
+      return;
+    }
+  f=((MagickRealType) red == w) ? green-(MagickRealType) blue :
+    (((MagickRealType) green == w) ? blue-(MagickRealType) red : red-
+    (MagickRealType) green);
+  i=((MagickRealType) red == w) ? 3 : (((MagickRealType) green == w) ? 5 : 1);
+  *hue=((double) i-f/(v-1.0*w))/6.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x p a n d A f f i n e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExpandAffine() computes the affine's expansion factor, i.e. the square root
+%  of the factor by which the affine transform affects area. In an affine
+%  transform composed of scaling, rotation, shearing, and translation, returns
+%  the amount of scaling.
+%
+%  The format of the ExpandAffine method is:
+%
+%      double ExpandAffine(const AffineMatrix *affine)
+%
+%  A description of each parameter follows:
+%
+%    o expansion: Method ExpandAffine returns the affine's expansion factor.
+%
+%    o affine: A pointer the affine transform of type AffineMatrix.
+%
+*/
+MagickExport double ExpandAffine(const AffineMatrix *affine)
+{
+  assert(affine != (const AffineMatrix *) NULL);
+  return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e n e r a t e D i f f e r e n t i a l N o i s e                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GenerateDifferentialNoise() generates differentual noise.
+%
+%  The format of the GenerateDifferentialNoise method is:
+%
+%      double GenerateDifferentialNoise(RandomInfo *random_info,
+%        const Quantum pixel,const NoiseType noise_type,
+%        const MagickRealType attenuate)
+%
+%  A description of each parameter follows:
+%
+%    o random_info: the random info.
+%
+%    o pixel: noise is relative to this pixel value.
+%
+%    o noise_type: the type of noise.
+%
+%    o attenuate:  attenuate the noise.
+%
+*/
+MagickExport double GenerateDifferentialNoise(RandomInfo *random_info,
+  const Quantum pixel,const NoiseType noise_type,const MagickRealType attenuate)
+{
+#define NoiseEpsilon  (attenuate*1.0e-5)
+#define SigmaUniform  (attenuate*4.0)
+#define SigmaGaussian  (attenuate*4.0)
+#define SigmaImpulse  (attenuate*0.10)
+#define SigmaLaplacian (attenuate*10.0)
+#define SigmaMultiplicativeGaussian  (attenuate*1.0)
+#define SigmaPoisson  (attenuate*0.05)
+#define TauGaussian  (attenuate*20.0)
+
+  double
+    alpha,
+    beta,
+    noise,
+    sigma;
+
+  alpha=GetPseudoRandomValue(random_info);
+  switch (noise_type)
+  {
+    case UniformNoise:
+    default:
+    {
+      noise=(double) pixel+ScaleCharToQuantum((unsigned char)
+        (SigmaUniform*(alpha)));
+      break;
+    }
+    case GaussianNoise:
+    {
+      double
+        gamma,
+        tau;
+
+      if (alpha == 0.0)
+        alpha=1.0;
+      beta=GetPseudoRandomValue(random_info);
+      gamma=sqrt(-2.0*log(alpha));
+      sigma=gamma*cos((double) (2.0*MagickPI*beta));
+      tau=gamma*sin((double) (2.0*MagickPI*beta));
+      noise=(double) pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
+        TauGaussian*tau;
+      break;
+    }
+    case MultiplicativeGaussianNoise:
+    {
+      if (alpha <= NoiseEpsilon)
+        sigma=(double) QuantumRange;
+      else
+        sigma=sqrt(-2.0*log(alpha));
+      beta=GetPseudoRandomValue(random_info);
+      noise=(double) pixel+pixel*SigmaMultiplicativeGaussian*sigma/2.0*
+        cos((double) (2.0*MagickPI*beta));
+      break;
+    }
+    case ImpulseNoise:
+    {
+      if (alpha < (SigmaImpulse/2.0))
+        noise=0.0;
+       else
+         if (alpha >= (1.0-(SigmaImpulse/2.0)))
+           noise=(double) QuantumRange;
+         else
+           noise=(double) pixel;
+      break;
+    }
+    case LaplacianNoise:
+    {
+      if (alpha <= 0.5)
+        {
+          if (alpha <= NoiseEpsilon)
+            noise=(double) pixel-(double) QuantumRange;
+          else
+            noise=(double) pixel+ScaleCharToQuantum((unsigned char)
+              (SigmaLaplacian*log((2.0*alpha))+0.5));
+          break;
+        }
+      beta=1.0-alpha;
+      if (beta <= (0.5*NoiseEpsilon))
+        noise=(double) (pixel+QuantumRange);
+      else
+        noise=(double) pixel-ScaleCharToQuantum((unsigned char)
+          (SigmaLaplacian*log((2.0*beta))+0.5));
+      break;
+    }
+    case PoissonNoise:
+    {
+      double
+        poisson;
+
+      register ssize_t
+        i;
+
+      poisson=exp(-SigmaPoisson*ScaleQuantumToChar(pixel));
+      for (i=0; alpha > poisson; i++)
+      {
+        beta=GetPseudoRandomValue(random_info);
+        alpha*=beta;
+      }
+      noise=(double) ScaleCharToQuantum((unsigned char) (i/SigmaPoisson));
+      break;
+    }
+    case RandomNoise:
+    {
+      noise=(double) QuantumRange*alpha;
+      break;
+    }
+  }
+  return(noise);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t O p t i m a l K e r n e l W i d t h                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
+%  filter.  Start with the minimum value of 3 pixels and walk out until we drop
+%  below the threshold of one pixel numerical accuracy.
+%
+%  The format of the GetOptimalKernelWidth method is:
+%
+%      size_t GetOptimalKernelWidth(const double radius,
+%        const double sigma)
+%
+%  A description of each parameter follows:
+%
+%    o width: Method GetOptimalKernelWidth returns the optimal width of
+%      a convolution kernel.
+%
+%    o radius: the radius of the Gaussian, in pixels, not counting the center
+%      pixel.
+%
+%    o sigma: the standard deviation of the Gaussian, in pixels.
+%
+*/
+MagickExport size_t GetOptimalKernelWidth1D(const double radius,
+  const double sigma)
+{
+  double
+    alpha,
+    beta,
+    gamma,
+    normalize,
+    value;
+
+  register ssize_t
+    i;
+
+  size_t
+    width;
+
+  ssize_t
+    j;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (radius > MagickEpsilon)
+    return((size_t) (2.0*ceil(radius)+1.0));
+  gamma=fabs(sigma);
+  if (gamma <= MagickEpsilon)
+    return(3UL);
+  alpha=1.0/(2.0*gamma*gamma);
+  beta=(double) (1.0/(MagickSQ2PI*gamma));
+  for (width=5; ; )
+  {
+    normalize=0.0;
+    j=(ssize_t) width/2;
+    for (i=(-j); i <= j; i++)
+      normalize+=exp(-((double) (i*i))*alpha)*beta;
+    value=exp(-((double) (j*j))*alpha)*beta/normalize;
+    if ((value < QuantumScale) || (value < MagickEpsilon))
+      break;
+    width+=2;
+  }
+  return((size_t) (width-2));
+}
+
+MagickExport size_t GetOptimalKernelWidth2D(const double radius,
+  const double sigma)
+{
+  double
+    alpha,
+    beta,
+    gamma,
+    normalize,
+    value;
+
+  size_t
+    width;
+
+  ssize_t
+    j,
+    u,
+    v;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (radius > MagickEpsilon)
+    return((size_t) (2.0*ceil(radius)+1.0));
+  gamma=fabs(sigma);
+  if (gamma <= MagickEpsilon)
+    return(3UL);
+  alpha=1.0/(2.0*gamma*gamma);
+  beta=(double) (1.0/(Magick2PI*gamma*gamma));
+  for (width=5; ; )
+  {
+    normalize=0.0;
+    j=(ssize_t) width/2;
+    for (v=(-j); v <= j; v++)
+      for (u=(-j); u <= j; u++)
+        normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
+    value=exp(-((double) (j*j))*alpha)*beta/normalize;
+    if ((value < QuantumScale) || (value < MagickEpsilon))
+      break;
+    width+=2;
+  }
+  return((size_t) (width-2));
+}
+
+MagickExport size_t  GetOptimalKernelWidth(const double radius,
+  const double sigma)
+{
+  return(GetOptimalKernelWidth1D(radius,sigma));
+}
diff --git a/MagickCore/gem.h b/MagickCore/gem.h
new file mode 100644
index 0000000..27796f9
--- /dev/null
+++ b/MagickCore/gem.h
@@ -0,0 +1,56 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private graphic gems methods.
+*/
+#ifndef _MAGICKCORE_GEM_PRIVATE_H
+#define _MAGICKCORE_GEM_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/fx.h>
+#include <MagickCore/random_.h>
+
+extern MagickExport double
+  ExpandAffine(const AffineMatrix *),
+  GenerateDifferentialNoise(RandomInfo *,const Quantum,const NoiseType,
+    const MagickRealType);
+
+extern MagickExport size_t
+  GetOptimalKernelWidth(const double,const double),
+  GetOptimalKernelWidth1D(const double,const double),
+  GetOptimalKernelWidth2D(const double,const double);
+
+extern MagickExport void
+  ConvertHSBToRGB(const double,const double,const double,Quantum *,Quantum *,
+    Quantum *),
+  ConvertHSLToRGB(const double,const double,const double,Quantum *,Quantum *,
+    Quantum *),
+  ConvertHWBToRGB(const double,const double,const double,Quantum *,Quantum *,
+    Quantum *),
+  ConvertRGBToHSB(const Quantum,const Quantum,const Quantum,double *,double *,
+    double *),
+  ConvertRGBToHSL(const Quantum,const Quantum,const Quantum,double *,double *,
+    double *),
+  ConvertRGBToHWB(const Quantum,const Quantum,const Quantum,double *,double *,
+    double *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/geometry.c b/MagickCore/geometry.c
new file mode 100644
index 0000000..01a95cf
--- /dev/null
+++ b/MagickCore/geometry.c
@@ -0,0 +1,1452 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           GGGG   EEEEE   OOO   M   M  EEEEE  TTTTT  RRRR   Y   Y            %
+%           G      E      O   O  MM MM  E        T    R   R   Y Y             %
+%           G  GG  EEE    O   O  M M M  EEE      T    RRRR     Y              %
+%           G   G  E      O   O  M   M  E        T    R R      Y              %
+%            GGGG  EEEEE   OOO   M   M  EEEEE    T    R  R     Y              %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Geometry Methods                           %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                              January 2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t G e o m e t r y                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetGeometry() parses a geometry specification and returns the width,
+%  height, x, and y values.  It also returns flags that indicates which
+%  of the four values (width, height, x, y) were located in the string, and
+%  whether the x or y values are negative.  In addition, there are flags to
+%  report any meta characters (%, !, <, or >).
+%
+%  The format of the GetGeometry method is:
+%
+%      MagickStatusType GetGeometry(const char *geometry,ssize_t *x,ssize_t *y,
+%        size_t *width,size_t *height)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry.
+%
+%    o x,y:  The x and y offset as determined by the geometry specification.
+%
+%    o width,height:  The width and height as determined by the geometry
+%      specification.
+%
+*/
+MagickExport MagickStatusType GetGeometry(const char *geometry,ssize_t *x,
+  ssize_t *y,size_t *width,size_t *height)
+{
+  char
+    *p,
+    pedantic_geometry[MaxTextExtent],
+    *q;
+
+  double
+    value;
+
+  MagickStatusType
+    flags;
+
+  /*
+    Remove whitespace and meta characters from geometry specification.
+  */
+  flags=NoValue;
+  if ((geometry == (char *) NULL) || (*geometry == '\0'))
+    return(flags);
+  if (strlen(geometry) >= (MaxTextExtent-1))
+    return(flags);
+  (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
+  for (p=pedantic_geometry; *p != '\0'; )
+  {
+    if (isspace((int) ((unsigned char) *p)) != 0)
+      {
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        continue;
+      }
+    switch ((int) *p)
+    {
+      case '%':
+      {
+        flags|=PercentValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '!':
+      {
+        flags|=AspectValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '<':
+      {
+        flags|=LessValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '>':
+      {
+        flags|=GreaterValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '^':
+      {
+        flags|=MinimumValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '@':
+      {
+        flags|=AreaValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '(':
+      case ')':
+      {
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '-':
+      case '.':
+      case ',':
+      case '+':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case -41:
+      case 'x':
+      case 'X':
+      {
+        p++;
+        break;
+      }
+      default:
+        return(flags);
+    }
+  }
+  /*
+    Parse width, height, x, and y.
+  */
+  p=pedantic_geometry;
+  if (*p == '\0')
+    return(flags);
+  q=p;
+  value=InterpretLocaleValue(p,&q);
+  (void) value;
+  if (LocaleNCompare(p,"0x",2) == 0)
+    value=(double) strtol(p,&q,10);
+  if ((((int) *q) == -41) || (*q == 'x') || (*q == 'X') || (*q == '\0'))
+    {
+      /*
+        Parse width.
+      */
+      q=p;
+      if (LocaleNCompare(p,"0x",2) == 0)
+        *width=(size_t) strtol(p,&p,10);
+      else
+        *width=(size_t) floor(InterpretLocaleValue(p,&p)+0.5);
+      if (p != q)
+        flags|=WidthValue;
+    }
+  if ((((int) *p) == -41) || (*p == 'x') || (*p == 'X'))
+    {
+      p++;
+      if ((*p != '+') && (*p != '-'))
+        {
+          /*
+            Parse height.
+          */
+          q=p;
+          *height=(size_t) floor(InterpretLocaleValue(p,&p)+0.5);
+          if (p != q)
+            flags|=HeightValue;
+        }
+    }
+  if ((*p == '+') || (*p == '-'))
+    {
+      /*
+        Parse x value.
+      */
+      if (*p == '-')
+        flags|=XNegative;
+      q=p;
+      *x=(ssize_t) ceil(InterpretLocaleValue(p,&p)-0.5);
+      if (p != q)
+        flags|=XValue;
+      if ((*p == '+') || (*p == '-'))
+        {
+          /*
+            Parse y value.
+          */
+          if (*p == '-')
+            flags|=YNegative;
+          q=p;
+          *y=(ssize_t) ceil(InterpretLocaleValue(p,&p)-0.5);
+          if (p != q)
+            flags|=YValue;
+        }
+    }
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t P a g e G e o m e t r y                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPageGeometry() replaces any page mneumonic with the equivalent size in
+%  picas.
+%
+%  The format of the GetPageGeometry method is:
+%
+%      char *GetPageGeometry(const char *page_geometry)
+%
+%  A description of each parameter follows.
+%
+%   o  page_geometry:  Specifies a pointer to an array of characters.  The
+%      string is either a Postscript page name (e.g. A4) or a postscript page
+%      geometry (e.g. 612x792+36+36).
+%
+*/
+MagickExport char *GetPageGeometry(const char *page_geometry)
+{
+  static const char
+    *PageSizes[][2]=
+    {
+      { "4x6",  "288x432" },
+      { "5x7",  "360x504" },
+      { "7x9",  "504x648" },
+      { "8x10", "576x720" },
+      { "9x11",  "648x792" },
+      { "9x12",  "648x864" },
+      { "10x13",  "720x936" },
+      { "10x14",  "720x1008" },
+      { "11x17",  "792x1224" },
+      { "a0",  "2384x3370" },
+      { "a1",  "1684x2384" },
+      { "a10", "73x105" },
+      { "a2",  "1191x1684" },
+      { "a3",  "842x1191" },
+      { "a4",  "595x842" },
+      { "a4smaLL", "595x842" },
+      { "a5",  "420x595" },
+      { "a6",  "297x420" },
+      { "a7",  "210x297" },
+      { "a8",  "148x210" },
+      { "a9",  "105x148" },
+      { "archa", "648x864" },
+      { "archb", "864x1296" },
+      { "archC", "1296x1728" },
+      { "archd", "1728x2592" },
+      { "arche", "2592x3456" },
+      { "b0",  "2920x4127" },
+      { "b1",  "2064x2920" },
+      { "b10", "91x127" },
+      { "b2",  "1460x2064" },
+      { "b3",  "1032x1460" },
+      { "b4",  "729x1032" },
+      { "b5",  "516x729" },
+      { "b6",  "363x516" },
+      { "b7",  "258x363" },
+      { "b8",  "181x258" },
+      { "b9",  "127x181" },
+      { "c0",  "2599x3676" },
+      { "c1",  "1837x2599" },
+      { "c2",  "1298x1837" },
+      { "c3",  "918x1296" },
+      { "c4",  "649x918" },
+      { "c5",  "459x649" },
+      { "c6",  "323x459" },
+      { "c7",  "230x323" },
+      { "executive", "540x720" },
+      { "flsa", "612x936" },
+      { "flse", "612x936" },
+      { "folio",  "612x936" },
+      { "halfletter", "396x612" },
+      { "isob0", "2835x4008" },
+      { "isob1", "2004x2835" },
+      { "isob10", "88x125" },
+      { "isob2", "1417x2004" },
+      { "isob3", "1001x1417" },
+      { "isob4", "709x1001" },
+      { "isob5", "499x709" },
+      { "isob6", "354x499" },
+      { "isob7", "249x354" },
+      { "isob8", "176x249" },
+      { "isob9", "125x176" },
+      { "jisb0", "1030x1456" },
+      { "jisb1", "728x1030" },
+      { "jisb2", "515x728" },
+      { "jisb3", "364x515" },
+      { "jisb4", "257x364" },
+      { "jisb5", "182x257" },
+      { "jisb6", "128x182" },
+      { "ledger",  "1224x792" },
+      { "legal",  "612x1008" },
+      { "letter", "612x792" },
+      { "lettersmaLL",  "612x792" },
+      { "quarto",  "610x780" },
+      { "statement",  "396x612" },
+      { "tabloid",  "792x1224" },
+      { (char *) NULL, (char *) NULL }
+    };
+
+  char
+    *page;
+
+  register ssize_t
+    i;
+
+  assert(page_geometry != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",page_geometry);
+  page=AcquireString(page_geometry);
+  for (i=0; *PageSizes[i] != (char *) NULL; i++)
+    if (LocaleNCompare(PageSizes[i][0],page,strlen(PageSizes[i][0])) == 0)
+      {
+        RectangleInfo
+          geometry;
+
+        MagickStatusType
+          flags;
+
+        /*
+          Replace mneumonic with the equivalent size in dots-per-inch.
+        */
+        (void) CopyMagickString(page,PageSizes[i][1],MaxTextExtent);
+        (void) ConcatenateMagickString(page,page_geometry+
+          strlen(PageSizes[i][0]),MaxTextExtent);
+        flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
+          &geometry.height);
+        if ((flags & GreaterValue) == 0)
+          (void) ConcatenateMagickString(page,">",MaxTextExtent);
+        break;
+      }
+  return(page);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G r a v i t y A d j u s t G e o m e t r y                                 %
+%                                                                             %
+%                                                                             % %                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GravityAdjustGeometry() adjusts the offset of a region with regard to the
+%  given: width, height and gravity; against which it is positioned.
+%
+%  The region should also have an appropriate width and height to correctly
+%  set the right offset of the top left corner of the region.
+%
+%  The format of the GravityAdjustGeometry method is:
+%
+%      void GravityAdjustGeometry(const size_t width, const size_t height,
+%        const GravityType gravity,RectangleInfo *region);
+%
+%  A description of each parameter follows:
+%
+%    o width, height:  the larger area the region is relative to
+%
+%    o gravity: the edge/corner the current offset is relative to
+%
+%    o region:  The region requiring a offset adjustment relative to gravity
+%
+*/
+MagickExport void GravityAdjustGeometry(const size_t width,
+  const size_t height,const GravityType gravity,RectangleInfo *region)
+{
+  if (region->height == 0)
+    region->height=height;
+  if (region->width == 0)
+    region->width=width;
+  switch (gravity)
+  {
+    case NorthEastGravity:
+    case EastGravity:
+    case SouthEastGravity:
+    {
+      region->x=(ssize_t) (width-region->width-region->x);
+      break;
+    }
+    case NorthGravity:
+    case SouthGravity:
+    case CenterGravity:
+    case StaticGravity:
+    {
+      region->x+=(ssize_t) (width/2-region->width/2);
+      break;
+    }
+    case ForgetGravity:
+    case NorthWestGravity:
+    case WestGravity:
+    case SouthWestGravity:
+    default:
+      break;
+  }
+  switch (gravity)
+  {
+    case SouthWestGravity:
+    case SouthGravity:
+    case SouthEastGravity:
+    {
+      region->y=(ssize_t) (height-region->height-region->y);
+      break;
+    }
+    case EastGravity:
+    case WestGravity:
+    case CenterGravity:
+    case StaticGravity:
+    {
+      region->y+=(ssize_t) (height/2-region->height/2);
+      break;
+    }
+    case ForgetGravity:
+    case NorthWestGravity:
+    case NorthGravity:
+    case NorthEastGravity:
+    default:
+      break;
+  }
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     I s G e o m e t r y                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsGeometry() returns MagickTrue if the geometry specification is valid.
+%  Examples are 100, 100x200, x200, 100x200+10+20, +10+20, 200%, 200x200!, etc.
+%
+%  The format of the IsGeometry method is:
+%
+%      MagickBooleanType IsGeometry(const char *geometry)
+%
+%  A description of each parameter follows:
+%
+%    o geometry: This string is the geometry specification.
+%
+*/
+MagickExport MagickBooleanType IsGeometry(const char *geometry)
+{
+  GeometryInfo
+    geometry_info;
+
+  MagickStatusType
+    flags;
+
+  if (geometry == (const char *) NULL)
+    return(MagickFalse);
+  flags=ParseGeometry(geometry,&geometry_info);
+  if (flags == NoValue)
+    flags=ParseGeometry(geometry+1,&geometry_info);  /* i.e. +-4+-4 */
+  return(flags != NoValue ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     I s S c e n e G e o m e t r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsSceneGeometry() returns MagickTrue if the geometry is a valid scene
+%  specification (e.g. [1], [1-9], [1,7,4]).
+%
+%  The format of the IsSceneGeometry method is:
+%
+%      MagickBooleanType IsSceneGeometry(const char *geometry,
+%        const MagickBooleanType pedantic)
+%
+%  A description of each parameter follows:
+%
+%    o geometry: This string is the geometry specification.
+%
+%    o pedantic: A value other than 0 invokes a more restrictive set of
+%      conditions for a valid specification (e.g. [1], [1-4], [4-1]).
+%
+*/
+MagickExport MagickBooleanType IsSceneGeometry(const char *geometry,
+  const MagickBooleanType pedantic)
+{
+  char
+    *p;
+
+  double
+    value;
+
+  if (geometry == (const char *) NULL)
+    return(MagickFalse);
+  p=(char *) geometry;
+  value=InterpretLocaleValue(geometry,&p);
+  (void) value;
+  if (p == geometry)
+    return(MagickFalse);
+  if (strspn(geometry,"0123456789-, ") != strlen(geometry))
+    return(MagickFalse);
+  if ((pedantic != MagickFalse) && (strchr(geometry,',') != (char *) NULL))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e A b s o l u t e G e o m e t r y                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseAbsoluteGeometry() returns a region as defined by the geometry string,
+%  without any modification by percentages or gravity.
+%
+%  It currently just a wrapper around GetGeometry(), but may be expanded in
+%  the future to handle other positioning information.
+%
+%  The format of the ParseAbsoluteGeometry method is:
+%
+%      MagickStatusType ParseAbsoluteGeometry(const char *geometry,
+%        RectangleInfo *region_info)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "100x100+10+10").
+%
+%    o region_info: the region as defined by the geometry string.
+%
+*/
+MagickExport MagickStatusType ParseAbsoluteGeometry(const char *geometry,
+  RectangleInfo *region_info)
+{
+  MagickStatusType
+    flags;
+
+  flags=GetGeometry(geometry,&region_info->x,&region_info->y,
+    &region_info->width,&region_info->height);
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e A f f i n e G e o m e t r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseAffineGeometry() returns an affine matrix as defined by a string of 4
+%  to 6 comma/space separated floating point values.
+%
+%  The affine matrix determinant is checked for validity of the values.
+%
+%  The format of the ParseAffineGeometry method is:
+%
+%      MagickStatusType ParseAffineGeometry(const char *geometry,
+%        AffineMatrix *affine_matrix,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "1.0,0.0,0.0,1.0,3.2,1.2").
+%
+%    o affine_matrix: the affine matrix as defined by the geometry string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickStatusType ParseAffineGeometry(const char *geometry,
+  AffineMatrix *affine_matrix,ExceptionInfo *exception)
+{
+  char
+    token[MaxTextExtent];
+
+  const char
+    *p;
+
+  double
+    determinant;
+
+  MagickStatusType
+    flags;
+
+  register ssize_t
+    i;
+
+  GetAffineMatrix(affine_matrix);
+  flags=NoValue;
+  p=(char *) geometry;
+  for (i=0; (*p != '\0') && (i < 6); i++)
+  {
+    GetMagickToken(p,&p,token);
+    if (*token == ',')
+      GetMagickToken(p,&p,token);
+    switch (i)
+    {
+      case 0:
+      {
+        affine_matrix->sx=InterpretLocaleValue(token,(char **) NULL);
+        break;
+      }
+      case 1:
+      {
+        affine_matrix->rx=InterpretLocaleValue(token,(char **) NULL);
+        break;
+      }
+      case 2:
+      {
+        affine_matrix->ry=InterpretLocaleValue(token,(char **) NULL);
+        break;
+      }
+      case 3:
+      {
+        affine_matrix->sy=InterpretLocaleValue(token,(char **) NULL);
+        break;
+      }
+      case 4:
+      {
+        affine_matrix->tx=InterpretLocaleValue(token,(char **) NULL);
+        flags|=XValue;
+        break;
+      }
+      case 5:
+      {
+        affine_matrix->ty=InterpretLocaleValue(token,(char **) NULL);
+        flags|=YValue;
+        break;
+      }
+    }
+  }
+  determinant=(affine_matrix->sx*affine_matrix->sy-affine_matrix->rx*
+    affine_matrix->ry);
+  if (fabs(determinant) < MagickEpsilon)
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "InvalidGeometry","`%s'",geometry);
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e G e o m e t r y                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseGeometry() parses a geometry specification and returns the sigma,
+%  rho, xi, and psi values.  It also returns flags that indicates which
+%  of the four values (sigma, rho, xi, psi) were located in the string, and
+%  whether the xi or pi values are negative.
+%
+%  In addition, it reports if there are any of meta characters (%, !, <, >, @,
+%  and ^) flags present. It does not report the location of the percentage
+%  relative to the values.
+%
+%  The format of the ParseGeometry method is:
+%
+%      MagickStatusType ParseGeometry(const char *geometry,
+%        GeometryInfo *geometry_info)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "100x100+10+10").
+%
+%    o geometry_info:  returns the parsed width/height/x/y in this structure.
+%
+*/
+MagickExport MagickStatusType ParseGeometry(const char *geometry,
+  GeometryInfo *geometry_info)
+{
+  char
+    *p,
+    pedantic_geometry[MaxTextExtent],
+    *q;
+
+  double
+    value;
+
+  MagickStatusType
+    flags;
+
+  /*
+    Remove whitespaces meta characters from geometry specification.
+  */
+  assert(geometry_info != (GeometryInfo *) NULL);
+  flags=NoValue;
+  if ((geometry == (char *) NULL) || (*geometry == '\0'))
+    return(flags);
+  if (strlen(geometry) >= (MaxTextExtent-1))
+    return(flags);
+  (void) CopyMagickString(pedantic_geometry,geometry,MaxTextExtent);
+  for (p=pedantic_geometry; *p != '\0'; )
+  {
+    if (isspace((int) ((unsigned char) *p)) != 0)
+      {
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        continue;
+      }
+    switch ((int) *p)
+    {
+      case '%':
+      {
+        flags|=PercentValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '!':
+      {
+        flags|=AspectValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '<':
+      {
+        flags|=LessValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '>':
+      {
+        flags|=GreaterValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '^':
+      {
+        flags|=MinimumValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '@':
+      {
+        flags|=AreaValue;
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '(':
+      case ')':
+      {
+        (void) CopyMagickString(p,p+1,MaxTextExtent);
+        break;
+      }
+      case '-':
+      case '+':
+      case ',':
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case -41:
+      case 'x':
+      case 'X':
+      case '/':
+      case ':':
+      {
+        p++;
+        break;
+      }
+      case '.':
+      {
+        p++;
+        flags|=DecimalValue;
+        break;
+      }
+      default:
+        return(flags);
+    }
+  }
+  /*
+    Parse rho, sigma, xi, psi, and optionally chi.
+  */
+  p=pedantic_geometry;
+  if (*p == '\0')
+    return(flags);
+  q=p;
+  value=InterpretLocaleValue(p,&q);
+  if (LocaleNCompare(p,"0x",2) == 0)
+    value=(double) strtol(p,&q,10);
+  if ((((int) *q) == -41) || (*q == 'x') || (*q == 'X') || (*q == ',') ||
+      (*q == '/') || (*q == ':') || (*q =='\0'))
+    {
+      /*
+        Parse rho.
+      */
+      q=p;
+      if (LocaleNCompare(p,"0x",2) == 0)
+        value=(double) strtol(p,&p,10);
+      else
+        value=InterpretLocaleValue(p,&p);
+      if (p != q)
+        {
+          flags|=RhoValue;
+          geometry_info->rho=value;
+        }
+    }
+  q=p;
+  if ((((int) *p) == -41) || (*p == 'x') || (*p == 'X') || (*p == ',') ||
+      (*p == '/') || (*p == ':'))
+    {
+      /*
+        Parse sigma.
+      */
+      p++;
+      while (isspace((int) ((unsigned char) *p)) != 0)
+        p++;
+      if (((((int) *q) != -41) && (*q != 'x') && (*q != 'X')) ||
+          ((*p != '+') && (*p != '-')))
+        {
+          q=p;
+          value=InterpretLocaleValue(p,&p);
+          if (p != q)
+            {
+              flags|=SigmaValue;
+              geometry_info->sigma=value;
+            }
+        }
+    }
+  while (isspace((int) ((unsigned char) *p)) != 0)
+    p++;
+  if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') || (*p == ':'))
+    {
+      /*
+        Parse xi value.
+      */
+      if ((*p == ',') || (*p == '/') || (*p == ':'))
+        p++;
+      q=p;
+      value=InterpretLocaleValue(p,&p);
+      if (p != q)
+        {
+          flags|=XiValue;
+          if (*q == '-')
+            flags|=XiNegative;
+          geometry_info->xi=value;
+        }
+      while (isspace((int) ((unsigned char) *p)) != 0)
+        p++;
+      if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
+          (*p == ':'))
+        {
+          /*
+            Parse psi value.
+          */
+          if ((*p == ',') || (*p == '/') || (*p == ':'))
+            p++;
+          q=p;
+          value=InterpretLocaleValue(p,&p);
+          if (p != q)
+            {
+              flags|=PsiValue;
+              if (*q == '-')
+                flags|=PsiNegative;
+              geometry_info->psi=value;
+            }
+        }
+      while (isspace((int) ((unsigned char) *p)) != 0)
+        p++;
+      if ((*p == '+') || (*p == '-') || (*p == ',') || (*p == '/') ||
+          (*p == ':'))
+        {
+          /*
+            Parse chi value.
+          */
+          if ((*p == ',') || (*p == '/') || (*p == ':'))
+            p++;
+          q=p;
+          value=InterpretLocaleValue(p,&p);
+          if (p != q)
+            {
+              flags|=ChiValue;
+              if (*q == '-')
+                flags|=ChiNegative;
+              geometry_info->chi=value;
+            }
+        }
+    }
+  if (strchr(pedantic_geometry,':') != (char *) NULL)
+    {
+      /*
+        Normalize sampling factor (e.g. 4:2:2 => 2x1).
+      */
+      geometry_info->rho/=geometry_info->sigma;
+      geometry_info->sigma=1.0;
+      if (geometry_info->xi == 0.0)
+        geometry_info->sigma=2.0;
+    }
+  if (((flags & SigmaValue) == 0) && ((flags & XiValue) != 0) &&
+      ((flags & PsiValue) == 0))
+    {
+      /*
+        Support negative height values (e.g. 30x-20).
+      */
+      geometry_info->sigma=geometry_info->xi;
+      geometry_info->xi=0.0;
+      flags|=SigmaValue;
+      flags&=(~XiValue);
+    }
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e G r a v i t y G e o m e t r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseGravityGeometry() returns a region as defined by the geometry string
+%  with respect to the given image page (canvas) dimensions and the images
+%  gravity setting.
+%
+%  This is typically used for specifing a area within a given image for
+%  cropping images to a smaller size, chopping out rows and or columns, or
+%  resizing and positioning overlay images.
+%
+%  Percentages are relative to image size and not page size, and are set to
+%  nearest integer (pixel) size.
+%
+%  The format of the ParseGravityGeometry method is:
+%
+%      MagickStatusType ParseGravityGeometry(Image *image,const char *geometry,
+%        RectangeInfo *region_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "100x100+10+10").
+%
+%    o region_info: the region as defined by the geometry string with respect
+%      to the image dimensions and its gravity.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickStatusType ParseGravityGeometry(const Image *image,
+  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
+{
+  MagickStatusType
+    flags;
+
+  size_t
+    height,
+    width;
+
+  SetGeometry(image,region_info);
+  if (image->page.width != 0)
+    region_info->width=image->page.width;
+  if (image->page.height != 0)
+    region_info->height=image->page.height;
+  flags=ParseAbsoluteGeometry(geometry,region_info);
+  if (flags == NoValue)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "InvalidGeometry","`%s'",geometry);
+      return(flags);
+    }
+  if ((flags & PercentValue) != 0)
+    {
+      GeometryInfo
+        geometry_info;
+
+      MagickStatusType
+        status;
+
+      PointInfo
+        scale;
+
+      /*
+        Geometry is a percentage of the image size, not canvas size
+      */
+      if (image->gravity != UndefinedGravity)
+        flags|=XValue | YValue;
+      status=ParseGeometry(geometry,&geometry_info);
+      scale.x=geometry_info.rho;
+      if ((status & RhoValue) == 0)
+        scale.x=100.0;
+      scale.y=geometry_info.sigma;
+      if ((status & SigmaValue) == 0)
+        scale.y=scale.x;
+      region_info->width=(size_t) floor((scale.x*image->columns/100.0)+0.5);
+      region_info->height=(size_t) floor((scale.y*image->rows/100.0)+0.5);
+    }
+  /*
+    Adjust offset according to gravity setting.
+  */
+  width=region_info->width;
+  height=region_info->height;
+  if (width == 0)
+    region_info->width=image->page.width | image->columns;
+  if (height == 0)
+    region_info->height=image->page.height | image->rows;
+  GravityAdjustGeometry(image->columns,image->rows,image->gravity,region_info);
+  region_info->width=width;
+  region_info->height=height;
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P a r s e M e t a G e o m e t r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseMetaGeometry() is similar to GetGeometry() except the returned
+%  geometry is modified as determined by the meta characters:  %, !, <, >, @,
+%  and ^ in relation to image resizing.
+%
+%  Final image dimensions are adjusted so as to preserve the aspect ratio as
+%  much as possible, while generating a integer (pixel) size, and fitting the
+%  image within the specified geometry width and height.
+%
+%  Flags are interpreted...
+%     %   geometry size is given percentage of original image size
+%     !   do not try to preserve aspect ratio
+%     <   only enlarge images smaller that geometry
+%     >   only shrink images larger than geometry
+%     @   Fit image to contain at most this many pixels
+%     ^   Contain the given geometry given, (minimal dimensions given)
+%
+%  The format of the ParseMetaGeometry method is:
+%
+%      MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
+%        ssize_t *y, size_t *width,size_t *height)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "100x100+10+10").
+%
+%    o x,y:  The x and y offset, set according to the geometry specification.
+%
+%    o width,height:  The width and height of original image, modified by
+%      the given geometry specification.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,
+  const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickStatusType ParseMetaGeometry(const char *geometry,ssize_t *x,
+  ssize_t *y,size_t *width,size_t *height)
+{
+  GeometryInfo
+    geometry_info;
+
+  MagickStatusType
+    flags;
+
+  size_t
+    former_height,
+    former_width;
+
+  /*
+    Ensure the image geometry is valid.
+  */
+  assert(x != (ssize_t *) NULL);
+  assert(y != (ssize_t *) NULL);
+  assert(width != (size_t *) NULL);
+  assert(height != (size_t *) NULL);
+  if ((geometry == (char *) NULL) || (*geometry == '\0'))
+    return(NoValue);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",geometry);
+  /*
+    Parse geometry using GetGeometry.
+  */
+  SetGeometryInfo(&geometry_info);
+  former_width=(*width);
+  former_height=(*height);
+  flags=GetGeometry(geometry,x,y,width,height);
+  if ((flags & PercentValue) != 0)
+    {
+      MagickStatusType
+        flags;
+
+      PointInfo
+        scale;
+
+      /*
+        Geometry is a percentage of the image size.
+      */
+      flags=ParseGeometry(geometry,&geometry_info);
+      scale.x=geometry_info.rho;
+      if ((flags & RhoValue) == 0)
+        scale.x=100.0;
+      scale.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        scale.y=scale.x;
+      *width=(size_t) floor(scale.x*former_width/100.0+0.5);
+      if (*width == 0)
+        *width=1;
+      *height=(size_t) floor(scale.y*former_height/100.0+0.5);
+      if (*height == 0)
+        *height=1;
+      former_width=(*width);
+      former_height=(*height);
+    }
+  if (((flags & AspectValue) == 0) && ((*width != former_width) ||
+      (*height != former_height)))
+    {
+      MagickRealType
+        scale_factor;
+
+      /*
+        Respect aspect ratio of the image.
+      */
+      if ((former_width == 0) || (former_height == 0))
+        scale_factor=1.0;
+      else
+        if (((flags & RhoValue) != 0) && (flags & SigmaValue) != 0)
+          {
+            scale_factor=(MagickRealType) *width/(MagickRealType) former_width;
+            if ((flags & MinimumValue) == 0)
+              {
+                if (scale_factor > ((MagickRealType) *height/(MagickRealType)
+                    former_height))
+                  scale_factor=(MagickRealType) *height/(MagickRealType)
+                    former_height;
+              }
+            else
+              if (scale_factor < ((MagickRealType) *height/(MagickRealType)
+                  former_height))
+                scale_factor=(MagickRealType) *height/(MagickRealType)
+                  former_height;
+          }
+        else
+          if ((flags & RhoValue) != 0)
+            {
+              scale_factor=(MagickRealType) *width/(MagickRealType)
+                former_width;
+              if (((flags & MinimumValue) != 0) &&
+                  (scale_factor < ((MagickRealType) *width/(MagickRealType)
+                   former_height)))
+                scale_factor=(MagickRealType) *width/(MagickRealType)
+                  former_height;
+            }
+          else
+            {
+              scale_factor=(MagickRealType) *height/(MagickRealType)
+                former_height;
+              if (((flags & MinimumValue) != 0) &&
+                  (scale_factor < ((MagickRealType) *height/(MagickRealType)
+                   former_width)))
+                scale_factor=(MagickRealType) *height/(MagickRealType)
+                  former_width;
+            }
+      *width=MagickMax((size_t) floor(scale_factor*former_width+0.5),1UL);
+      *height=MagickMax((size_t) floor(scale_factor*former_height+0.5),1UL);
+    }
+  if ((flags & GreaterValue) != 0)
+    {
+      if (former_width < *width)
+        *width=former_width;
+      if (former_height < *height)
+        *height=former_height;
+    }
+  if ((flags & LessValue) != 0)
+    {
+      if (former_width > *width)
+        *width=former_width;
+      if (former_height > *height)
+        *height=former_height;
+    }
+  if ((flags & AreaValue) != 0)
+    {
+      MagickRealType
+        area,
+        distance;
+
+      PointInfo
+        scale;
+
+      /*
+        Geometry is a maximum area in pixels.
+      */
+      (void) ParseGeometry(geometry,&geometry_info);
+      area=geometry_info.rho;
+      distance=sqrt((double) former_width*former_height);
+      scale.x=(double) former_width/(double) (distance/sqrt((double) area));
+      scale.y=(double) former_height/(double) (distance/sqrt((double) area));
+      if ((scale.x < (double) *width) || (scale.y < (double) *height))
+        {
+          *width=(size_t) (former_width/(distance/sqrt((double) area)));
+          *height=(size_t) (former_height/(distance/sqrt((double) area)));
+        }
+      former_width=(*width);
+      former_height=(*height);
+    }
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e P a g e G e o m e t r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParsePageGeometry() returns a region as defined by the geometry string with
+%  respect to the image page (canvas) dimensions.
+%
+%  WARNING: Percentage dimensions remain relative to the actual image
+%  dimensions, and not canvas dimensions.
+%
+%  The format of the ParsePageGeometry method is:
+%
+%      MagickStatusType ParsePageGeometry(const Image *image,
+%        const char *geometry,RectangeInfo *region_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "100x100+10+10").
+%
+%    o region_info: the region as defined by the geometry string with
+%      respect to the image and its gravity.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickStatusType ParsePageGeometry(const Image *image,
+  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
+{
+  MagickStatusType
+    flags;
+
+  SetGeometry(image,region_info);
+  if (image->page.width != 0)
+    region_info->width=image->page.width;
+  if (image->page.height != 0)
+    region_info->height=image->page.height;
+  flags=ParseAbsoluteGeometry(geometry,region_info);
+  if (flags == NoValue)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "InvalidGeometry","`%s'",geometry);
+      return(flags);
+    }
+  if ((flags & PercentValue) != 0)
+    {
+      region_info->width=image->columns;
+      region_info->height=image->rows;
+    }
+  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
+    &region_info->width,&region_info->height);
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e R e g i o n G e o m e t r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseRegionGeometry() returns a region as defined by the geometry string
+%  with respect to the image dimensions and aspect ratio.
+%
+%  This is basically a wrapper around ParseMetaGeometry.  This is typically
+%  used to parse a geometry string to work out the final integer dimensions
+%  for image resizing.
+%
+%  The format of the ParseRegionGeometry method is:
+%
+%      MagickStatusType ParseRegionGeometry(const Image *image,
+%        const char *geometry,RectangeInfo *region_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o geometry:  The geometry string (e.g. "100x100+10+10").
+%
+%    o region_info: the region as defined by the geometry string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickStatusType ParseRegionGeometry(const Image *image,
+  const char *geometry,RectangleInfo *region_info,ExceptionInfo *exception)
+{
+  MagickStatusType
+    flags;
+
+  SetGeometry(image,region_info);
+  flags=ParseMetaGeometry(geometry,&region_info->x,&region_info->y,
+    &region_info->width,&region_info->height);
+  if (flags == NoValue)
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "InvalidGeometry","`%s'",geometry);
+  return(flags);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t G e o m e t r y                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetGeometry() sets the geometry to its default values.
+%
+%  The format of the SetGeometry method is:
+%
+%      SetGeometry(const Image *image,RectangleInfo *geometry)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o geometry: the geometry.
+%
+*/
+MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(geometry != (RectangleInfo *) NULL);
+  (void) ResetMagickMemory(geometry,0,sizeof(*geometry));
+  geometry->width=image->columns;
+  geometry->height=image->rows;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t G e o m e t r y I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetGeometryInfo sets the GeometryInfo structure to its default values.
+%
+%  The format of the SetGeometryInfo method is:
+%
+%      SetGeometryInfo(GeometryInfo *geometry_info)
+%
+%  A description of each parameter follows:
+%
+%    o geometry_info: the geometry info structure.
+%
+*/
+MagickExport void SetGeometryInfo(GeometryInfo *geometry_info)
+{
+  assert(geometry_info != (GeometryInfo *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  (void) ResetMagickMemory(geometry_info,0,sizeof(*geometry_info));
+}
diff --git a/MagickCore/geometry.h b/MagickCore/geometry.h
new file mode 100644
index 0000000..9fa8f3b
--- /dev/null
+++ b/MagickCore/geometry.h
@@ -0,0 +1,160 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image geometry methods.
+*/
+#ifndef _MAGICKCORE_GEOMETRY_H
+#define _MAGICKCORE_GEOMETRY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+#undef NoValue
+  NoValue = 0x0000,
+#undef XValue
+  XValue = 0x0001,
+  XiValue = 0x0001,
+#undef YValue
+  YValue = 0x0002,
+  PsiValue = 0x0002,
+#undef WidthValue
+  WidthValue = 0x0004,
+  RhoValue = 0x0004,
+#undef HeightValue
+  HeightValue = 0x0008,
+  SigmaValue = 0x0008,
+  ChiValue = 0x0010,
+  XiNegative = 0x0020,
+#undef XNegative
+  XNegative = 0x0020,
+  PsiNegative = 0x0040,
+#undef YNegative
+  YNegative = 0x0040,
+  ChiNegative = 0x0080,
+  PercentValue = 0x1000,   /* '%'  percentage of something */
+  AspectValue = 0x2000,    /* '!'  resize no-aspect - special use flag */
+  NormalizeValue = 0x2000, /* '!'  ScaleKernelValue() in morphology.c */
+  LessValue = 0x4000,      /* '<'  resize smaller - special use flag */
+  GreaterValue = 0x8000,   /* '>'  resize larger - spacial use flag */
+  MinimumValue = 0x10000,  /* '^'  special handling needed */
+  CorrelateNormalizeValue = 0x10000, /* '^' see ScaleKernelValue() */
+  AreaValue = 0x20000,     /* '@'  resize to area - special use flag */
+  DecimalValue = 0x40000,  /* '.'  floating point numbers found */
+#undef AllValues
+  AllValues = 0x7fffffff
+} GeometryFlags;
+
+#if defined(ForgetGravity)
+#undef ForgetGravity
+#undef NorthWestGravity
+#undef NorthGravity
+#undef NorthEastGravity
+#undef WestGravity
+#undef CenterGravity
+#undef EastGravity
+#undef SouthWestGravity
+#undef SouthGravity
+#undef SouthEastGravity
+#undef StaticGravity
+#endif
+
+typedef enum
+{
+  UndefinedGravity,
+  ForgetGravity = 0,
+  NorthWestGravity = 1,
+  NorthGravity = 2,
+  NorthEastGravity = 3,
+  WestGravity = 4, 
+  CenterGravity = 5,
+  EastGravity = 6,
+  SouthWestGravity = 7,
+  SouthGravity = 8,
+  SouthEastGravity = 9,
+  StaticGravity = 10 
+} GravityType;
+
+typedef struct _AffineMatrix
+{
+  double
+    sx,
+    rx,
+    ry,
+    sy,
+    tx,
+    ty;
+} AffineMatrix;
+
+typedef struct _GeometryInfo
+{
+  double
+    rho,
+    sigma,
+    xi,
+    psi,
+    chi;
+} GeometryInfo;
+
+typedef struct _OffsetInfo
+{
+  ssize_t
+    x,
+    y;
+} OffsetInfo;
+
+typedef struct _RectangleInfo
+{
+  size_t
+    width,
+    height;
+
+  ssize_t
+    x,
+    y;
+} RectangleInfo;
+
+extern MagickExport char
+  *GetPageGeometry(const char *);
+
+extern MagickExport MagickBooleanType
+  IsGeometry(const char *),
+  IsSceneGeometry(const char *,const MagickBooleanType);
+
+extern MagickExport MagickStatusType
+  GetGeometry(const char *,ssize_t *,ssize_t *,size_t *,size_t *),
+  ParseAbsoluteGeometry(const char *,RectangleInfo *),
+  ParseAffineGeometry(const char *,AffineMatrix *,ExceptionInfo *),
+  ParseGeometry(const char *,GeometryInfo *),
+  ParseGravityGeometry(const Image *,const char *,RectangleInfo *,
+    ExceptionInfo *),
+  ParseMetaGeometry(const char *,ssize_t *,ssize_t *,size_t *,size_t *),
+  ParsePageGeometry(const Image *,const char *,RectangleInfo *,ExceptionInfo *),
+  ParseRegionGeometry(const Image *,const char *,RectangleInfo *,
+    ExceptionInfo *);
+
+extern MagickExport void
+  GravityAdjustGeometry(const size_t,const size_t,
+    const GravityType,RectangleInfo *),
+  SetGeometry(const Image *,RectangleInfo *),
+  SetGeometryInfo(GeometryInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/hashmap.c b/MagickCore/hashmap.c
new file mode 100644
index 0000000..c2b20ba
--- /dev/null
+++ b/MagickCore/hashmap.c
@@ -0,0 +1,1982 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                H   H   AAA   SSSSS  H   H  M   M   AAA   PPPP               %
+%                H   H  A   A  SS     H   H  MM MM  A   A  P   P              %
+%                HHHHH  AAAAA   SSS   HHHHH  M M M  AAAAA  PPPP               %
+%                H   H  A   A     SS  H   H  M   M  A   A  P                  %
+%                H   H  A   A  SSSSS  H   H  M   M  A   A  P                  %
+%                                                                             %
+%                                                                             %
+%                  MagickCore Hash-map and Linked-list Methods                %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               December 2002                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  This module implements the standard handy hash and linked-list methods for
+%  storing and retrieving large numbers of data elements.  It is loosely based
+%  on the Java implementation of these algorithms.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _ElementInfo
+{
+  void
+    *value;
+
+  struct _ElementInfo
+    *next;
+} ElementInfo;
+
+typedef struct _EntryInfo
+{
+  size_t
+    hash;
+
+  void
+    *key,
+    *value;
+} EntryInfo;
+
+struct _LinkedListInfo
+{
+  size_t
+    capacity,
+    elements;
+
+  ElementInfo
+    *head,
+    *tail,
+    *next;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+struct _HashmapInfo
+{
+  size_t
+    (*hash)(const void *);
+
+  MagickBooleanType
+    (*compare)(const void *,const void *);
+
+  void
+    *(*relinquish_key)(void *),
+    *(*relinquish_value)(void *);
+
+  size_t
+    capacity,
+    entries,
+    next;
+
+  MagickBooleanType
+    head_of_list;
+
+  LinkedListInfo
+    **map;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A p p e n d V a l u e T o L i n k e d L i s t                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AppendValueToLinkedList() appends a value to the end of the linked-list.
+%
+%  The format of the AppendValueToLinkedList method is:
+%
+%      MagickBooleanType AppendValueToLinkedList(LinkedListInfo *list_info,
+%        const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+%    o value: the value.
+%
+*/
+MagickExport MagickBooleanType AppendValueToLinkedList(
+  LinkedListInfo *list_info,const void *value)
+{
+  register ElementInfo
+    *next;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  list_info->debug=IsEventLogging();
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (list_info->elements == list_info->capacity)
+    return(MagickFalse);
+  next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
+  if (next == (ElementInfo *) NULL)
+    return(MagickFalse);
+  next->value=(void *) value;
+  next->next=(ElementInfo *) NULL;
+  LockSemaphoreInfo(list_info->semaphore);
+  if (list_info->next == (ElementInfo *) NULL)
+    list_info->next=next;
+  if (list_info->elements == 0)
+    list_info->head=next;
+  else
+    list_info->tail->next=next;
+  list_info->tail=next;
+  list_info->elements++;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l e a r L i n k e d L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClearLinkedList() clears all the elements from the linked-list.
+%
+%  The format of the ClearLinkedList method is:
+%
+%      void ClearLinkedList(LinkedListInfo *list_info,
+%        void *(*relinquish_value)(void *))
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+%    o relinquish_value: the value deallocation method; typically
+%      RelinquishMagickMemory().
+%
+*/
+MagickExport void ClearLinkedList(LinkedListInfo *list_info,
+  void *(*relinquish_value)(void *))
+{
+  ElementInfo
+    *element;
+
+  register ElementInfo
+    *next;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(list_info->semaphore);
+  next=list_info->head;
+  while (next != (ElementInfo *) NULL)
+  {
+    if (relinquish_value != (void *(*)(void *)) NULL)
+      next->value=relinquish_value(next->value);
+    element=next;
+    next=next->next;
+    element=(ElementInfo *) RelinquishMagickMemory(element);
+  }
+  list_info->head=(ElementInfo *) NULL;
+  list_info->tail=(ElementInfo *) NULL;
+  list_info->next=(ElementInfo *) NULL;
+  list_info->elements=0;
+  UnlockSemaphoreInfo(list_info->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e H a s h m a p S t r i n g                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareHashmapString() finds an entry in a hash-map based on the contents
+%  of a string.
+%
+%  The format of the CompareHashmapString method is:
+%
+%      MagickBooleanType CompareHashmapString(const void *target,
+%        const void *source)
+%
+%  A description of each parameter follows:
+%
+%    o target: the target string.
+%
+%    o source: the source string.
+%
+*/
+MagickExport MagickBooleanType CompareHashmapString(const void *target,
+  const void *source)
+{
+  const char
+    *p,
+    *q;
+
+  p=(const char *) target;
+  q=(const char *) source;
+  return(LocaleCompare(p,q) == 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e H a s h m a p S t r i n g I n f o                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareHashmapStringInfo() finds an entry in a hash-map based on the
+%  contents of a string.
+%
+%  The format of the CompareHashmapStringInfo method is:
+%
+%      MagickBooleanType CompareHashmapStringInfo(const void *target,
+%        const void *source)
+%
+%  A description of each parameter follows:
+%
+%    o target: the target string.
+%
+%    o source: the source string.
+%
+*/
+MagickExport MagickBooleanType CompareHashmapStringInfo(const void *target,
+  const void *source)
+{
+  const StringInfo
+    *p,
+    *q;
+
+  p=(const StringInfo *) target;
+  q=(const StringInfo *) source;
+  return(CompareStringInfo(p,q) == 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y H a s h m a p                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyHashmap() frees the hash-map and all associated resources.
+%
+%  The format of the DestroyHashmap method is:
+%
+%      HashmapInfo *DestroyHashmap(HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport HashmapInfo *DestroyHashmap(HashmapInfo *hashmap_info)
+{
+  LinkedListInfo
+    *list_info;
+
+  register EntryInfo
+    *entry;
+
+  register ssize_t
+    i;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  for (i=0; i < (ssize_t) hashmap_info->capacity; i++)
+  {
+    list_info=hashmap_info->map[i];
+    if (list_info != (LinkedListInfo *) NULL)
+      {
+        list_info->next=list_info->head;
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+        while (entry != (EntryInfo *) NULL)
+        {
+          if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
+            entry->key=hashmap_info->relinquish_key(entry->key);
+          if (hashmap_info->relinquish_value != (void *(*)(void *)) NULL)
+            entry->value=hashmap_info->relinquish_value(entry->value);
+          entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+        }
+      }
+    if (list_info != (LinkedListInfo *) NULL)
+      list_info=DestroyLinkedList(list_info,RelinquishMagickMemory);
+  }
+  hashmap_info->map=(LinkedListInfo **) RelinquishMagickMemory(
+    hashmap_info->map);
+  hashmap_info->signature=(~MagickSignature);
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+  DestroySemaphoreInfo(&hashmap_info->semaphore);
+  hashmap_info=(HashmapInfo *) RelinquishMagickMemory(hashmap_info);
+  return(hashmap_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y L i n k e d L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyLinkedList() frees the linked-list and all associated resources.
+%
+%  The format of the DestroyLinkedList method is:
+%
+%      LinkedListInfo *DestroyLinkedList(LinkedListInfo *list_info,
+%        void *(*relinquish_value)(void *))
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+%    o relinquish_value: the value deallocation method;  typically
+%      RelinquishMagickMemory().
+%
+*/
+MagickExport LinkedListInfo *DestroyLinkedList(LinkedListInfo *list_info,
+  void *(*relinquish_value)(void *))
+{
+  ElementInfo
+    *entry;
+
+  register ElementInfo
+    *next;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(list_info->semaphore);
+  for (next=list_info->head; next != (ElementInfo *) NULL; )
+  {
+    if (relinquish_value != (void *(*)(void *)) NULL)
+      next->value=relinquish_value(next->value);
+    entry=next;
+    next=next->next;
+    entry=(ElementInfo *) RelinquishMagickMemory(entry);
+  }
+  list_info->signature=(~MagickSignature);
+  UnlockSemaphoreInfo(list_info->semaphore);
+  DestroySemaphoreInfo(&list_info->semaphore);
+  list_info=(LinkedListInfo *) RelinquishMagickMemory(list_info);
+  return(list_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L a s t V a l u e I n L i n k e d L i s t                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLastValueInLinkedList() gets the last value in the linked-list.
+%
+%  The format of the GetLastValueInLinkedList method is:
+%
+%      void *GetLastValueInLinkedList(LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked_list info.
+%
+*/
+MagickExport void *GetLastValueInLinkedList(LinkedListInfo *list_info)
+{
+  void
+    *value;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (list_info->elements == 0)
+    return((void *) NULL);
+  LockSemaphoreInfo(list_info->semaphore);
+  value=list_info->tail->value;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t K e y I n H a s h m a p                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextKeyInHashmap() gets the next key in the hash-map.
+%
+%  The format of the GetNextKeyInHashmap method is:
+%
+%      void *GetNextKeyInHashmap(HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport void *GetNextKeyInHashmap(HashmapInfo *hashmap_info)
+{
+  LinkedListInfo
+    *list_info;
+
+  register EntryInfo
+    *entry;
+
+  void
+    *key;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  while (hashmap_info->next < hashmap_info->capacity)
+  {
+    list_info=hashmap_info->map[hashmap_info->next];
+    if (list_info != (LinkedListInfo *) NULL)
+      {
+        if (hashmap_info->head_of_list == MagickFalse)
+          {
+            list_info->next=list_info->head;
+            hashmap_info->head_of_list=MagickTrue;
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+        if (entry != (EntryInfo *) NULL)
+          {
+            key=entry->key;
+            UnlockSemaphoreInfo(hashmap_info->semaphore);
+            return(key);
+          }
+        hashmap_info->head_of_list=MagickFalse;
+      }
+    hashmap_info->next++;
+  }
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+  return((void *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t V a l u e I n H a s h m a p                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextValueInHashmap() gets the next value in the hash-map.
+%
+%  The format of the GetNextValueInHashmap method is:
+%
+%      void *GetNextValueInHashmap(HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport void *GetNextValueInHashmap(HashmapInfo *hashmap_info)
+{
+  LinkedListInfo
+    *list_info;
+
+  register EntryInfo
+    *entry;
+
+  void
+    *value;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  while (hashmap_info->next < hashmap_info->capacity)
+  {
+    list_info=hashmap_info->map[hashmap_info->next];
+    if (list_info != (LinkedListInfo *) NULL)
+      {
+        if (hashmap_info->head_of_list == MagickFalse)
+          {
+            list_info->next=list_info->head;
+            hashmap_info->head_of_list=MagickTrue;
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+        if (entry != (EntryInfo *) NULL)
+          {
+            value=entry->value;
+            UnlockSemaphoreInfo(hashmap_info->semaphore);
+            return(value);
+          }
+        hashmap_info->head_of_list=MagickFalse;
+      }
+    hashmap_info->next++;
+  }
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+  return((void *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t V a l u e I n L i n k e d L i s t                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextValueInLinkedList() gets the next value in the linked-list.
+%
+%  The format of the GetNextValueInLinkedList method is:
+%
+%      void *GetNextValueInLinkedList(LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+*/
+MagickExport void *GetNextValueInLinkedList(LinkedListInfo *list_info)
+{
+  void
+    *value;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(list_info->semaphore);
+  if (list_info->next == (ElementInfo *) NULL)
+    {
+      UnlockSemaphoreInfo(list_info->semaphore);
+      return((void *) NULL);
+    }
+  value=list_info->next->value;
+  list_info->next=list_info->next->next;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N u m b e r O f E n t r i e s I n H a s h m a p                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNumberOfEntriesInHashmap() returns the number of entries in the hash-map.
+%
+%  The format of the GetNumberOfEntriesInHashmap method is:
+%
+%      size_t GetNumberOfEntriesInHashmap(const HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport size_t GetNumberOfEntriesInHashmap(
+  const HashmapInfo *hashmap_info)
+{
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(hashmap_info->entries);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N u m b e r O f E l e m e n t s I n L i n k e d L i s t             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNumberOfElementsInLinkedList() returns the number of entries in the
+%  linked-list.
+%
+%  The format of the GetNumberOfElementsInLinkedList method is:
+%
+%      size_t GetNumberOfElementsInLinkedList(
+%        const LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+*/
+MagickExport size_t GetNumberOfElementsInLinkedList(
+  const LinkedListInfo *list_info)
+{
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(list_info->elements);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V a l u e F r o m H a s h m a p                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetValueFromHashmap() gets an entry from the hash-map by its key.
+%
+%  The format of the GetValueFromHashmap method is:
+%
+%      void *GetValueFromHashmap(HashmapInfo *hashmap_info,const void *key)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+%    o key: the key.
+%
+*/
+MagickExport void *GetValueFromHashmap(HashmapInfo *hashmap_info,
+  const void *key)
+{
+  LinkedListInfo
+    *list_info;
+
+  register EntryInfo
+    *entry;
+
+  size_t
+    hash;
+
+  void
+    *value;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (key == (const void *) NULL)
+    return((void *) NULL);
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  hash=hashmap_info->hash(key);
+  list_info=hashmap_info->map[hash % hashmap_info->capacity];
+  if (list_info != (LinkedListInfo *) NULL)
+    {
+      list_info->next=list_info->head;
+      entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      while (entry != (EntryInfo *) NULL)
+      {
+        if (entry->hash == hash)
+          {
+            MagickBooleanType
+              compare;
+
+            compare=MagickTrue;
+            if (hashmap_info->compare !=
+                (MagickBooleanType (*)(const void *,const void *)) NULL)
+              compare=hashmap_info->compare(key,entry->key);
+            if (compare == MagickTrue)
+              {
+                value=entry->value;
+                UnlockSemaphoreInfo(hashmap_info->semaphore);
+                return(value);
+              }
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      }
+    }
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+  return((void *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V a l u e F r o m L i n k e d L i s t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetValueFromLinkedList() gets a value from the linked-list at the specified
+%  location.
+%
+%  The format of the GetValueFromLinkedList method is:
+%
+%      void *GetValueFromLinkedList(LinkedListInfo *list_info,
+%        const size_t index)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked_list info.
+%
+%    o index: the list index.
+%
+*/
+MagickExport void *GetValueFromLinkedList(LinkedListInfo *list_info,
+  const size_t index)
+{
+  register ElementInfo
+    *next;
+
+  register ssize_t
+    i;
+
+  void
+    *value;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (index >= list_info->elements)
+    return((void *) NULL);
+  LockSemaphoreInfo(list_info->semaphore);
+  if (index == 0)
+    {
+      value=list_info->head->value;
+      UnlockSemaphoreInfo(list_info->semaphore);
+      return(value);
+    }
+  if (index == (list_info->elements-1))
+    {
+      value=list_info->tail->value;
+      UnlockSemaphoreInfo(list_info->semaphore);
+      return(value);
+    }
+  next=list_info->head;
+  for (i=0; i < (ssize_t) index; i++)
+    next=next->next;
+  value=next->value;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H a s h P o i n t e r T y p e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  HashPointerType() finds an entry in a hash-map based on the address of a
+%  pointer.
+%
+%  The format of the HashPointerType method is:
+%
+%      size_t HashPointerType(const void *pointer)
+%
+%  A description of each parameter follows:
+%
+%    o pointer: compute the hash entry location from this pointer address.
+%
+*/
+MagickExport size_t HashPointerType(const void *pointer)
+{
+  size_t
+    hash;
+
+  hash=(size_t) pointer;
+  hash+=(~(hash << 9));
+  hash^=(hash >> 14);
+  hash+=(hash << 4);
+  hash^=(hash >> 10);
+  return(hash);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H a s h S t r i n g T y p e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  HashStringType() finds an entry in a hash-map based on the contents of a
+%  string.
+%
+%  The format of the HashStringType method is:
+%
+%      size_t HashStringType(const void *string)
+%
+%  A description of each parameter follows:
+%
+%    o string: compute the hash entry location from this string.
+%
+*/
+MagickExport size_t HashStringType(const void *string)
+{
+  const unsigned char
+    *digest;
+
+  register ssize_t
+    i;
+
+  SignatureInfo
+    *signature_info;
+
+  size_t
+    hash;
+
+  StringInfo
+    *signature;
+
+  signature_info=AcquireSignatureInfo();
+  signature=StringToStringInfo((const char *) string);
+  UpdateSignature(signature_info,signature);
+  FinalizeSignature(signature_info);
+  digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
+  hash=0;
+  for (i=0; i < 8; i++)
+    hash^=digest[i];
+  signature=DestroyStringInfo(signature);
+  signature_info=DestroySignatureInfo(signature_info);
+  return(hash);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   H a s h S t r i n g I n f o T y p e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Specify the HashStringInfoType() method in NewHashmap() to find an entry
+%  in a hash-map based on the contents of a string.
+%
+%  The format of the HashStringInfoType method is:
+%
+%      size_t HashStringInfoType(const void *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: compute the hash entry location from this string.
+%
+*/
+MagickExport size_t HashStringInfoType(const void *string_info)
+{
+  const unsigned char
+    *digest;
+
+  register ssize_t
+    i;
+
+  SignatureInfo
+    *signature_info;
+
+  size_t
+    hash;
+
+  signature_info=AcquireSignatureInfo();
+  UpdateSignature(signature_info,(const StringInfo *) string_info);
+  FinalizeSignature(signature_info);
+  digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
+  hash=0;
+  for (i=0; i < 8; i++)
+    hash^=digest[i];
+  signature_info=DestroySignatureInfo(signature_info);
+  return(hash);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n s e r t V a l u e I n L i n k e d L i s t                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InsertValueInLinkedList() inserts an element in the linked-list at the
+%  specified location.
+%
+%  The format of the InsertValueInLinkedList method is:
+%
+%      MagickBooleanType InsertValueInLinkedList(ListInfo *list_info,
+%        const size_t index,const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the hashmap info.
+%
+%    o index: the index.
+%
+%    o value: the value.
+%
+*/
+MagickExport MagickBooleanType InsertValueInLinkedList(
+  LinkedListInfo *list_info,const size_t index,const void *value)
+{
+  register ElementInfo
+    *next;
+
+  register ssize_t
+    i;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (value == (const void *) NULL)
+    return(MagickFalse);
+  if ((index > list_info->elements) ||
+      (list_info->elements == list_info->capacity))
+    return(MagickFalse);
+  next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
+  if (next == (ElementInfo *) NULL)
+    return(MagickFalse);
+  next->value=(void *) value;
+  next->next=(ElementInfo *) NULL;
+  LockSemaphoreInfo(list_info->semaphore);
+  if (list_info->elements == 0)
+    {
+      if (list_info->next == (ElementInfo *) NULL)
+        list_info->next=next;
+      list_info->head=next;
+      list_info->tail=next;
+    }
+  else
+    {
+      if (index == 0)
+        {
+          if (list_info->next == list_info->head)
+            list_info->next=next;
+          next->next=list_info->head;
+          list_info->head=next;
+        }
+      else
+        if (index == list_info->elements)
+          {
+            if (list_info->next == (ElementInfo *) NULL)
+              list_info->next=next;
+            list_info->tail->next=next;
+            list_info->tail=next;
+          }
+        else
+          {
+            ElementInfo
+              *element;
+
+            element=list_info->head;
+            next->next=element->next;
+            for (i=1; i < (ssize_t) index; i++)
+            {
+              element=element->next;
+              next->next=element->next;
+            }
+            next=next->next;
+            element->next=next;
+            if (list_info->next == next->next)
+              list_info->next=next;
+          }
+    }
+  list_info->elements++;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n s e r t V a l u e I n S o r t e d L i n k e d L i s t                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InsertValueInSortedLinkedList() inserts a value in the sorted linked-list.
+%
+%  The format of the InsertValueInSortedLinkedList method is:
+%
+%      MagickBooleanType InsertValueInSortedLinkedList(ListInfo *list_info,
+%        int (*compare)(const void *,const void *),void **replace,
+%        const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the hashmap info.
+%
+%    o index: the index.
+%
+%    o compare: the compare method.
+%
+%    o replace: return previous element here.
+%
+%    o value: the value.
+%
+*/
+MagickExport MagickBooleanType InsertValueInSortedLinkedList(
+  LinkedListInfo *list_info,int (*compare)(const void *,const void *),
+  void **replace,const void *value)
+{
+  ElementInfo
+    *element;
+
+  register ElementInfo
+    *next;
+
+  register ssize_t
+    i;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if ((compare == (int (*)(const void *,const void *)) NULL) ||
+      (value == (const void *) NULL))
+    return(MagickFalse);
+  if (list_info->elements == list_info->capacity)
+    return(MagickFalse);
+  next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
+  if (next == (ElementInfo *) NULL)
+    return(MagickFalse);
+  next->value=(void *) value;
+  element=(ElementInfo *) NULL;
+  LockSemaphoreInfo(list_info->semaphore);
+  next->next=list_info->head;
+  while (next->next != (ElementInfo *) NULL)
+  {
+    i=(ssize_t) compare(value,next->next->value);
+    if ((i < 0) || ((replace != (void **) NULL) && (i == 0)))
+      {
+        if (i == 0)
+          {
+            *replace=next->next->value;
+            next->next=next->next->next;
+            if (element != (ElementInfo *) NULL)
+              element->next=(ElementInfo *) RelinquishMagickMemory(
+                element->next);
+            list_info->elements--;
+          }
+        if (element != (ElementInfo *) NULL)
+          element->next=next;
+        else
+          list_info->head=next;
+        break;
+      }
+    element=next->next;
+    next->next=next->next->next;
+  }
+  if (next->next == (ElementInfo *) NULL)
+    {
+      if (element != (ElementInfo *) NULL)
+        element->next=next;
+      else
+        list_info->head=next;
+      list_info->tail=next;
+    }
+  list_info->elements++;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s H a s h m a p E m p t y                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsHashmapEmpty() returns MagickTrue if the hash-map is empty.
+%
+%  The format of the IsHashmapEmpty method is:
+%
+%      MagickBooleanType IsHashmapEmpty(const HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport MagickBooleanType IsHashmapEmpty(const HashmapInfo *hashmap_info)
+{
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(hashmap_info->entries == 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s L i n k e d L i s t E m p t y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsLinkedListEmpty() returns MagickTrue if the linked-list is empty.
+%
+%  The format of the IsLinkedListEmpty method is:
+%
+%      MagickBooleanType IsLinkedListEmpty(LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+*/
+MagickExport MagickBooleanType IsLinkedListEmpty(
+  const LinkedListInfo *list_info)
+{
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(list_info->elements == 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L i n k e d L i s t T o A r r a y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LinkedListToArray() converts the linked-list to an array.
+%
+%  The format of the LinkedListToArray method is:
+%
+%      MagickBooleanType LinkedListToArray(LinkedListInfo *list_info,
+%        void **array)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+%    o array: the array.
+%
+*/
+MagickExport MagickBooleanType LinkedListToArray(LinkedListInfo *list_info,
+  void **array)
+{
+  register ElementInfo
+    *next;
+
+  register ssize_t
+    i;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (array == (void **) NULL)
+    return(MagickFalse);
+  LockSemaphoreInfo(list_info->semaphore);
+  next=list_info->head;
+  for (i=0; next != (ElementInfo *) NULL; i++)
+  {
+    array[i]=next->value;
+    next=next->next;
+  }
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w H a s h m a p                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewHashmap() returns a pointer to a HashmapInfo structure initialized
+%  to default values.  The capacity is an initial estimate.  The hashmap will
+%  increase capacity dynamically as the demand requires.
+%
+%  The format of the NewHashmap method is:
+%
+%      HashmapInfo *NewHashmap(const size_t capacity,
+%        size_t (*hash)(const void *),
+%        MagickBooleanType (*compare)(const void *,const void *),
+%        void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
+%
+%  A description of each parameter follows:
+%
+%    o capacity: the initial number entries in the hash-map: typically
+%      SmallHashmapSize, MediumHashmapSize, or LargeHashmapSize.  The
+%      hashmap will dynamically increase its capacity on demand.
+%
+%    o hash: the hash method, typically HashPointerType(), HashStringType(),
+%      or HashStringInfoType().
+%
+%    o compare: the compare method, typically NULL, CompareHashmapString(),
+%      or CompareHashmapStringInfo().
+%
+%    o relinquish_key: the key deallocation method, typically
+%      RelinquishMagickMemory(), called whenever a key is removed from the
+%      hash-map.
+%
+%    o relinquish_value: the value deallocation method;  typically
+%      RelinquishMagickMemory(), called whenever a value object is removed from
+%      the hash-map.
+%
+*/
+MagickExport HashmapInfo *NewHashmap(const size_t capacity,
+  size_t (*hash)(const void *),
+  MagickBooleanType (*compare)(const void *,const void *),
+  void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
+{
+  HashmapInfo
+    *hashmap_info;
+
+  hashmap_info=(HashmapInfo *) AcquireMagickMemory(sizeof(*hashmap_info));
+  if (hashmap_info == (HashmapInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(hashmap_info,0,sizeof(*hashmap_info));
+  hashmap_info->hash=HashPointerType;
+  if (hash != (size_t (*)(const void *)) NULL)
+    hashmap_info->hash=hash;
+  hashmap_info->compare=(MagickBooleanType (*)(const void *,const void *)) NULL;
+  if (compare != (MagickBooleanType (*)(const void *,const void *)) NULL)
+    hashmap_info->compare=compare;
+  hashmap_info->relinquish_key=relinquish_key;
+  hashmap_info->relinquish_value=relinquish_value;
+  hashmap_info->entries=0;
+  hashmap_info->capacity=capacity;
+  hashmap_info->map=(LinkedListInfo **) NULL;
+  if (~capacity >= 1UL)
+    hashmap_info->map=(LinkedListInfo **) AcquireQuantumMemory((size_t)
+      capacity+1UL,sizeof(*hashmap_info->map));
+  if (hashmap_info->map == (LinkedListInfo **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(hashmap_info->map,0,(size_t) capacity*
+    sizeof(*hashmap_info->map));
+  hashmap_info->debug=IsEventLogging();
+  hashmap_info->semaphore=AllocateSemaphoreInfo();
+  hashmap_info->signature=MagickSignature;
+  return(hashmap_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w L i n k e d L i s t I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewLinkedList() returns a pointer to a LinkedListInfo structure
+%  initialized to default values.
+%
+%  The format of the NewLinkedList method is:
+%
+%      LinkedListInfo *NewLinkedList(const size_t capacity)
+%
+%  A description of each parameter follows:
+%
+%    o capacity: the maximum number of elements in the list.
+%
+*/
+MagickExport LinkedListInfo *NewLinkedList(const size_t capacity)
+{
+  LinkedListInfo
+    *list_info;
+
+  list_info=(LinkedListInfo *) AcquireMagickMemory(sizeof(*list_info));
+  if (list_info == (LinkedListInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(list_info,0,sizeof(*list_info));
+  list_info->capacity=capacity == 0 ? (size_t) (~0) : capacity;
+  list_info->elements=0;
+  list_info->head=(ElementInfo *) NULL;
+  list_info->tail=(ElementInfo *) NULL;
+  list_info->next=(ElementInfo *) NULL;
+  list_info->debug=MagickFalse;
+  list_info->semaphore=AllocateSemaphoreInfo();
+  list_info->signature=MagickSignature;
+  return(list_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P u t E n t r y I n H a s h m a p                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PutEntryInHashmap() puts an entry in the hash-map.  If the key already
+%  exists in the map it is first removed.
+%
+%  The format of the PutEntryInHashmap method is:
+%
+%      MagickBooleanType PutEntryInHashmap(HashmapInfo *hashmap_info,
+%        const void *key,const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+%    o key: the key.
+%
+%    o value: the value.
+%
+*/
+
+static MagickBooleanType IncreaseHashmapCapacity(HashmapInfo *hashmap_info)
+{
+#define MaxCapacities  20
+
+  const size_t
+    capacities[MaxCapacities] =
+    {
+      17, 31, 61, 131, 257, 509, 1021, 2053, 4099, 8191, 16381, 32771,
+      65537, 131071, 262147, 524287, 1048573, 2097143, 4194301, 8388617
+    };
+
+  ElementInfo
+    *element;
+
+  EntryInfo
+    *entry;
+
+  LinkedListInfo
+    *list_info,
+    *map_info,
+    **map;
+
+  register ElementInfo
+    *next;
+
+  register ssize_t
+    i;
+
+  size_t
+    capacity;
+
+  /*
+    Increase to the next prime capacity.
+  */
+  for (i=0; i < MaxCapacities; i++)
+    if (hashmap_info->capacity < capacities[i])
+      break;
+  if (i >= (MaxCapacities-1))
+    return(MagickFalse);
+  capacity=capacities[i+1];
+  map=(LinkedListInfo **) AcquireQuantumMemory((size_t) capacity+1UL,
+    sizeof(*map));
+  if (map == (LinkedListInfo **) NULL)
+    return(MagickFalse);
+  (void) ResetMagickMemory(map,0,(size_t) capacity*sizeof(*map));
+  /*
+    Copy entries to new hashmap with increased capacity.
+  */
+  for (i=0; i < (ssize_t) hashmap_info->capacity; i++)
+  {
+    list_info=hashmap_info->map[i];
+    if (list_info == (LinkedListInfo *) NULL)
+      continue;
+    LockSemaphoreInfo(list_info->semaphore);
+    for (next=list_info->head; next != (ElementInfo *) NULL; )
+    {
+      element=next;
+      next=next->next;
+      entry=(EntryInfo *) element->value;
+      map_info=map[entry->hash % capacity];
+      if (map_info == (LinkedListInfo *) NULL)
+        {
+          map_info=NewLinkedList(0);
+          map[entry->hash % capacity]=map_info;
+        }
+      map_info->next=element;
+      element->next=map_info->head;
+      map_info->head=element;
+      map_info->elements++;
+    }
+    list_info->signature=(~MagickSignature);
+    UnlockSemaphoreInfo(list_info->semaphore);
+    DestroySemaphoreInfo(&list_info->semaphore);
+    list_info=(LinkedListInfo *) RelinquishMagickMemory(list_info);
+  }
+  hashmap_info->map=(LinkedListInfo **) RelinquishMagickMemory(
+    hashmap_info->map);
+  hashmap_info->map=map;
+  hashmap_info->capacity=capacity;
+  return(MagickTrue);
+}
+
+MagickExport MagickBooleanType PutEntryInHashmap(HashmapInfo *hashmap_info,
+  const void *key,const void *value)
+{
+  EntryInfo
+    *entry,
+    *next;
+
+  LinkedListInfo
+    *list_info;
+
+  register size_t
+    i;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if ((key == (void *) NULL) || (value == (void *) NULL))
+    return(MagickFalse);
+  next=(EntryInfo *) AcquireMagickMemory(sizeof(*next));
+  if (next == (EntryInfo *) NULL)
+    return(MagickFalse);
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  next->hash=hashmap_info->hash(key);
+  next->key=(void *) key;
+  next->value=(void *) value;
+  list_info=hashmap_info->map[next->hash % hashmap_info->capacity];
+  if (list_info == (LinkedListInfo *) NULL)
+    {
+      list_info=NewLinkedList(0);
+      hashmap_info->map[next->hash % hashmap_info->capacity]=list_info;
+    }
+  else
+    {
+      list_info->next=list_info->head;
+      entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      for (i=0; entry != (EntryInfo *) NULL; i++)
+      {
+        if (entry->hash == next->hash)
+          {
+            MagickBooleanType
+              compare;
+
+            compare=MagickTrue;
+            if (hashmap_info->compare !=
+                (MagickBooleanType (*)(const void *,const void *)) NULL)
+              compare=hashmap_info->compare(key,entry->key);
+            if (compare == MagickTrue)
+              {
+                (void) RemoveElementFromLinkedList(list_info,i);
+                if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
+                  entry->key=hashmap_info->relinquish_key(entry->key);
+                if (hashmap_info->relinquish_value != (void *(*)(void *)) NULL)
+                  entry->value=hashmap_info->relinquish_value(entry->value);
+                entry=(EntryInfo *) RelinquishMagickMemory(entry);
+                break;
+              }
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      }
+    }
+  if (InsertValueInLinkedList(list_info,0,next) == MagickFalse)
+    {
+      next=(EntryInfo *) RelinquishMagickMemory(next);
+      UnlockSemaphoreInfo(hashmap_info->semaphore);
+      return(MagickFalse);
+    }
+  if (list_info->elements >= (hashmap_info->capacity-1))
+    if (IncreaseHashmapCapacity(hashmap_info) == MagickFalse)
+      {
+        UnlockSemaphoreInfo(hashmap_info->semaphore);
+        return(MagickFalse);
+      }
+  hashmap_info->entries++;
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e E l e m e n t B y V a l u e F r o m L i n k e d L i s t       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveElementByValueFromLinkedList() removes an element from the linked-list
+%  by value.
+%
+%  The format of the RemoveElementByValueFromLinkedList method is:
+%
+%      void *RemoveElementByValueFromLinkedList(LinkedListInfo *list_info,
+%        const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the list info.
+%
+%    o value: the value.
+%
+*/
+MagickExport void *RemoveElementByValueFromLinkedList(LinkedListInfo *list_info,
+  const void *value)
+{
+  ElementInfo
+    *next;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if ((list_info->elements == 0) || (value == (const void *) NULL))
+    return((void *) NULL);
+  LockSemaphoreInfo(list_info->semaphore);
+  if (value == list_info->head->value)
+    {
+      if (list_info->next == list_info->head)
+        list_info->next=list_info->head->next;
+      next=list_info->head;
+      list_info->head=list_info->head->next;
+      next=(ElementInfo *) RelinquishMagickMemory(next);
+    }
+  else
+    {
+      ElementInfo
+        *element;
+
+      next=list_info->head;
+      while ((next->next != (ElementInfo *) NULL) &&
+             (next->next->value != value))
+        next=next->next;
+      if (next->next == (ElementInfo *) NULL)
+        {
+          UnlockSemaphoreInfo(list_info->semaphore);
+          return((void *) NULL);
+        }
+      element=next->next;
+      next->next=element->next;
+      if (element == list_info->tail)
+        list_info->tail=next;
+      if (list_info->next == element)
+        list_info->next=element->next;
+      element=(ElementInfo *) RelinquishMagickMemory(element);
+    }
+  list_info->elements--;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return((void *) value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e E l e m e n t F r o m L i n k e d L i s t                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveElementFromLinkedList() removes an element from the linked-list at the
+%  specified location.
+%
+%  The format of the RemoveElementFromLinkedList method is:
+%
+%      void *RemoveElementFromLinkedList(LinkedListInfo *list_info,
+%        const size_t index)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+%    o index: the index.
+%
+*/
+MagickExport void *RemoveElementFromLinkedList(LinkedListInfo *list_info,
+  const size_t index)
+{
+  ElementInfo
+    *next;
+
+  register ssize_t
+    i;
+
+  void
+    *value;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (index >= list_info->elements)
+    return((void *) NULL);
+  LockSemaphoreInfo(list_info->semaphore);
+  if (index == 0)
+    {
+      if (list_info->next == list_info->head)
+        list_info->next=list_info->head->next;
+      value=list_info->head->value;
+      next=list_info->head;
+      list_info->head=list_info->head->next;
+      next=(ElementInfo *) RelinquishMagickMemory(next);
+    }
+  else
+    {
+      ElementInfo
+        *element;
+
+      next=list_info->head;
+      for (i=1; i < (ssize_t) index; i++)
+        next=next->next;
+      element=next->next;
+      next->next=element->next;
+      if (element == list_info->tail)
+        list_info->tail=next;
+      if (list_info->next == element)
+        list_info->next=element->next;
+      value=element->value;
+      element=(ElementInfo *) RelinquishMagickMemory(element);
+    }
+  list_info->elements--;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e E n t r y F r o m H a s h m a p                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveEntryFromHashmap() removes an entry from the hash-map by its key.
+%
+%  The format of the RemoveEntryFromHashmap method is:
+%
+%      void *RemoveEntryFromHashmap(HashmapInfo *hashmap_info,void *key)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+%    o key: the key.
+%
+*/
+MagickExport void *RemoveEntryFromHashmap(HashmapInfo *hashmap_info,
+  const void *key)
+{
+  EntryInfo
+    *entry;
+
+  LinkedListInfo
+    *list_info;
+
+  register size_t
+    i;
+
+  size_t
+    hash;
+
+  void
+    *value;
+
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (key == (const void *) NULL)
+    return((void *) NULL);
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  hash=hashmap_info->hash(key);
+  list_info=hashmap_info->map[hash % hashmap_info->capacity];
+  if (list_info != (LinkedListInfo *) NULL)
+    {
+      list_info->next=list_info->head;
+      entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      for (i=0; entry != (EntryInfo *) NULL; i++)
+      {
+        if (entry->hash == hash)
+          {
+            MagickBooleanType
+              compare;
+
+            compare=MagickTrue;
+            if (hashmap_info->compare !=
+                (MagickBooleanType (*)(const void *,const void *)) NULL)
+              compare=hashmap_info->compare(key,entry->key);
+            if (compare == MagickTrue)
+              {
+                entry=(EntryInfo *) RemoveElementFromLinkedList(list_info,i);
+                if (entry == (EntryInfo *) NULL)
+                  {
+                    UnlockSemaphoreInfo(hashmap_info->semaphore);
+                    return((void *) NULL);
+                  }
+                if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
+                  entry->key=hashmap_info->relinquish_key(entry->key);
+                value=entry->value;
+                entry=(EntryInfo *) RelinquishMagickMemory(entry);
+                hashmap_info->entries--;
+                UnlockSemaphoreInfo(hashmap_info->semaphore);
+                return(value);
+              }
+          }
+        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
+      }
+    }
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+  return((void *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e L a s t E l e m e n t F r o m L i n k e d L i s t             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveLastElementFromLinkedList() removes the last element from the
+%  linked-list.
+%
+%  The format of the RemoveLastElementFromLinkedList method is:
+%
+%      void *RemoveLastElementFromLinkedList(LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+*/
+MagickExport void *RemoveLastElementFromLinkedList(LinkedListInfo *list_info)
+{
+  void
+    *value;
+
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (list_info->elements == 0)
+    return((void *) NULL);
+  LockSemaphoreInfo(list_info->semaphore);
+  if (list_info->next == list_info->tail)
+    list_info->next=(ElementInfo *) NULL;
+  if (list_info->elements == 1UL)
+    {
+      value=list_info->head->value;
+      list_info->head=(ElementInfo *) NULL;
+      list_info->tail=(ElementInfo *) RelinquishMagickMemory(list_info->tail);
+    }
+  else
+    {
+      ElementInfo
+        *next;
+
+      value=list_info->tail->value;
+      next=list_info->head;
+      while (next->next != list_info->tail)
+        next=next->next;
+      list_info->tail=(ElementInfo *) RelinquishMagickMemory(list_info->tail);
+      list_info->tail=next;
+      next->next=(ElementInfo *) NULL;
+    }
+  list_info->elements--;
+  UnlockSemaphoreInfo(list_info->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t H a s h m a p I t e r a t o r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetHashmapIterator() resets the hash-map iterator.  Use it in conjunction
+%  with GetNextKeyInHashmap() to iterate over all the keys in the hash-map.
+%
+%  The format of the ResetHashmapIterator method is:
+%
+%      ResetHashmapIterator(HashmapInfo *hashmap_info)
+%
+%  A description of each parameter follows:
+%
+%    o hashmap_info: the hashmap info.
+%
+*/
+MagickExport void ResetHashmapIterator(HashmapInfo *hashmap_info)
+{
+  assert(hashmap_info != (HashmapInfo *) NULL);
+  assert(hashmap_info->signature == MagickSignature);
+  if (hashmap_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(hashmap_info->semaphore);
+  hashmap_info->next=0;
+  hashmap_info->head_of_list=MagickFalse;
+  UnlockSemaphoreInfo(hashmap_info->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t L i n k e d L i s t I t e r a t o r                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetLinkedListIterator() resets the lined-list iterator.  Use it in
+%  conjunction with GetNextValueInLinkedList() to iterate over all the values
+%  in the linked-list.
+%
+%  The format of the ResetLinkedListIterator method is:
+%
+%      ResetLinkedListIterator(LinkedListInfo *list_info)
+%
+%  A description of each parameter follows:
+%
+%    o list_info: the linked-list info.
+%
+*/
+MagickExport void ResetLinkedListIterator(LinkedListInfo *list_info)
+{
+  assert(list_info != (LinkedListInfo *) NULL);
+  assert(list_info->signature == MagickSignature);
+  if (list_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(list_info->semaphore);
+  list_info->next=list_info->head;
+  UnlockSemaphoreInfo(list_info->semaphore);
+}
diff --git a/MagickCore/hashmap.h b/MagickCore/hashmap.h
new file mode 100644
index 0000000..0a91494
--- /dev/null
+++ b/MagickCore/hashmap.h
@@ -0,0 +1,83 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore hash methods.
+*/
+#ifndef _MAGICKCORE_HASHMAP_H
+#define _MAGICKCORE_HASHMAP_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define SmallHashmapSize  17
+#define MediumHashmapSize  509
+#define LargeHashmapSize  8191
+#define HugeHashmapSize  131071
+
+typedef struct _HashmapInfo
+  HashmapInfo;
+
+typedef struct _LinkedListInfo
+  LinkedListInfo;
+
+extern MagickExport HashmapInfo
+  *DestroyHashmap(HashmapInfo *),
+  *NewHashmap(const size_t,size_t (*)(const void *),MagickBooleanType (*)
+    (const void *,const void *),void *(*)(void *),void *(*)(void *));
+
+extern MagickExport LinkedListInfo
+  *DestroyLinkedList(LinkedListInfo *,void *(*)(void *)),
+  *NewLinkedList(const size_t);
+
+extern MagickExport MagickBooleanType
+  AppendValueToLinkedList(LinkedListInfo *,const void *),
+  CompareHashmapString(const void *,const void *),
+  CompareHashmapStringInfo(const void *,const void *),
+  InsertValueInLinkedList(LinkedListInfo *,const size_t,const void *),
+  InsertValueInSortedLinkedList(LinkedListInfo *,
+    int (*)(const void *,const void *),void **,const void *),
+  IsHashmapEmpty(const HashmapInfo *),
+  IsLinkedListEmpty(const LinkedListInfo *),
+  LinkedListToArray(LinkedListInfo *,void **),
+  PutEntryInHashmap(HashmapInfo *,const void *,const void *);
+
+extern MagickExport size_t
+  GetNumberOfElementsInLinkedList(const LinkedListInfo *),
+  GetNumberOfEntriesInHashmap(const HashmapInfo *),
+  HashPointerType(const void *),
+  HashStringType(const void *),
+  HashStringInfoType(const void *);
+
+extern MagickExport void
+  ClearLinkedList(LinkedListInfo *,void *(*)(void *)),
+  *GetLastValueInLinkedList(LinkedListInfo *),
+  *GetNextKeyInHashmap(HashmapInfo *),
+  *GetNextValueInHashmap(HashmapInfo *),
+  *GetNextValueInLinkedList(LinkedListInfo *),
+  *GetValueFromHashmap(HashmapInfo *,const void *),
+  *GetValueFromLinkedList(LinkedListInfo *,const size_t),
+  *RemoveElementByValueFromLinkedList(LinkedListInfo *,const void *),
+  *RemoveElementFromLinkedList(LinkedListInfo *,const size_t),
+  *RemoveEntryFromHashmap(HashmapInfo *,const void *),
+  *RemoveLastElementFromLinkedList(LinkedListInfo *),
+  ResetHashmapIterator(HashmapInfo *),
+  ResetLinkedListIterator(LinkedListInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/histogram.c b/MagickCore/histogram.c
new file mode 100644
index 0000000..1d2e5bc
--- /dev/null
+++ b/MagickCore/histogram.c
@@ -0,0 +1,1334 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%      H   H   IIIII   SSSSS  TTTTT   OOO    GGGG  RRRR    AAA   M   M        %
+%      H   H     I     SS       T    O   O  G      R   R  A   A  MM MM        %
+%      HHHHH     I      SSS     T    O   O  G  GG  RRRR   AAAAA  M M M        %
+%      H   H     I        SS    T    O   O  G   G  R R    A   A  M   M        %
+%      H   H   IIIII   SSSSS    T     OOO    GGG   R  R   A   A  M   M        %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Histogram Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                              Anthony Thyssen                                %
+%                               Fred Weinhaus                                 %
+%                                August 2009                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/image.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/prepress.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+
+/*
+  Define declarations.
+*/
+#define MaxTreeDepth  8
+#define NodesInAList  1536
+
+/*
+  Typedef declarations.
+*/
+typedef struct _NodeInfo
+{
+  struct _NodeInfo
+    *child[16];
+
+  PixelPacket
+    *list;
+
+  MagickSizeType
+    number_unique;
+
+  size_t
+    level;
+} NodeInfo;
+
+typedef struct _Nodes
+{
+  NodeInfo
+    nodes[NodesInAList];
+
+  struct _Nodes
+    *next;
+} Nodes;
+
+typedef struct _CubeInfo
+{
+  NodeInfo
+    *root;
+
+  ssize_t
+    x;
+
+  MagickOffsetType
+    progress;
+
+  size_t
+    colors,
+    free_nodes;
+
+  NodeInfo
+    *node_info;
+
+  Nodes
+    *node_queue;
+} CubeInfo;
+
+/*
+  Forward declarations.
+*/
+static CubeInfo
+  *GetCubeInfo(void);
+
+static NodeInfo
+  *GetNodeInfo(CubeInfo *,const size_t);
+
+static void
+  DestroyColorCube(const Image *,NodeInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l a s s i f y I m a g e C o l o r s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClassifyImageColors() builds a populated CubeInfo tree for the specified
+%  image.  The returned tree should be deallocated using DestroyCubeInfo()
+%  once it is no longer needed.
+%
+%  The format of the ClassifyImageColors() method is:
+%
+%      CubeInfo *ClassifyImageColors(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline size_t ColorToNodeId(const Image *image,
+  const PixelInfo *pixel,size_t index)
+{
+  size_t
+    id;
+
+  id=(size_t) (
+    ((ScaleQuantumToChar(ClampToQuantum(pixel->red)) >> index) & 0x01) |
+    ((ScaleQuantumToChar(ClampToQuantum(pixel->green)) >> index) & 0x01) << 1 |
+    ((ScaleQuantumToChar(ClampToQuantum(pixel->blue)) >> index) & 0x01) << 2);
+  if (image->matte != MagickFalse)
+    id|=((ScaleQuantumToChar(ClampToQuantum(pixel->alpha)) >> index) &
+      0x01) << 3;
+  return(id);
+}
+
+static CubeInfo *ClassifyImageColors(const Image *image,
+  ExceptionInfo *exception)
+{
+#define EvaluateImageTag  "  Compute image colors...  "
+
+  CacheView
+    *image_view;
+
+  CubeInfo
+    *cube_info;
+
+  MagickBooleanType
+    proceed;
+
+  PixelInfo
+    pixel,
+    target;
+
+  NodeInfo
+    *node_info;
+
+  register const Quantum
+    *p;
+
+  register size_t
+    id,
+    index,
+    level;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize color description tree.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cube_info=GetCubeInfo();
+  if (cube_info == (CubeInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(cube_info);
+    }
+  GetPixelInfo(image,&pixel);
+  GetPixelInfo(image,&target);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      /*
+        Start at the root and proceed level by level.
+      */
+      node_info=cube_info->root;
+      index=MaxTreeDepth-1;
+      for (level=1; level < MaxTreeDepth; level++)
+      {
+        SetPixelInfo(image,p,&pixel);
+        id=ColorToNodeId(image,&pixel,index);
+        if (node_info->child[id] == (NodeInfo *) NULL)
+          {
+            node_info->child[id]=GetNodeInfo(cube_info,level);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              {
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                  image->filename);
+                return(0);
+              }
+          }
+        node_info=node_info->child[id];
+        index--;
+      }
+      for (i=0; i < (ssize_t) node_info->number_unique; i++)
+      {
+        SetPixelInfoPacket(image,&node_info->list[i],&target);
+        if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
+          break;
+      }
+      if (i < (ssize_t) node_info->number_unique)
+        node_info->list[i].count++;
+      else
+        {
+          if (node_info->number_unique == 0)
+            node_info->list=(PixelPacket *) AcquireMagickMemory(
+              sizeof(*node_info->list));
+          else
+            node_info->list=(PixelPacket *) ResizeQuantumMemory(node_info->list,
+              (size_t) (i+1),sizeof(*node_info->list));
+          if (node_info->list == (PixelPacket *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+              return(0);
+            }
+          node_info->list[i].red=GetPixelRed(image,p);
+          node_info->list[i].green=GetPixelGreen(image,p);
+          node_info->list[i].blue=GetPixelBlue(image,p);
+          if (image->colorspace == CMYKColorspace)
+            node_info->list[i].black=GetPixelBlack(image,p);
+          node_info->list[i].alpha=GetPixelAlpha(image,p);
+          node_info->list[i].count=1;
+          node_info->number_unique++;
+          cube_info->colors++;
+        }
+      p+=GetPixelChannels(image);
+    }
+    proceed=SetImageProgress(image,EvaluateImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(cube_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f i n e I m a g e H i s t o g r a m                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineImageHistogram() traverses the color cube tree and notes each colormap
+%  entry.  A colormap entry is any node in the color cube tree where the
+%  of unique colors is not zero.
+%
+%  The format of the DefineImageHistogram method is:
+%
+%      DefineImageHistogram(const Image *image,NodeInfo *node_info,
+%        PixelPacket **unique_colors)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o node_info: the address of a structure of type NodeInfo which points to a
+%      node in the color cube tree that is to be pruned.
+%
+%    o histogram: the image histogram.
+%
+*/
+static void DefineImageHistogram(const Image *image,NodeInfo *node_info,
+  PixelPacket **histogram)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=image->matte == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      DefineImageHistogram(image,node_info->child[i],histogram);
+  if (node_info->level == (MaxTreeDepth-1))
+    {
+      register PixelPacket
+        *p;
+
+      p=node_info->list;
+      for (i=0; i < (ssize_t) node_info->number_unique; i++)
+      {
+        (*histogram)->red=p->red;
+        (*histogram)->green=p->green;
+        (*histogram)->blue=p->blue;
+        (*histogram)->black=p->black;
+        (*histogram)->alpha=p->alpha;
+        (*histogram)->count=p->count;
+        (*histogram)++;
+        p++;
+      }
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C u b e I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyCubeInfo() deallocates memory associated with a CubeInfo structure.
+%
+%  The format of the DestroyCubeInfo method is:
+%
+%      DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o cube_info: the address of a structure of type CubeInfo.
+%
+*/
+static CubeInfo *DestroyCubeInfo(const Image *image,CubeInfo *cube_info)
+{
+  register Nodes
+    *nodes;
+
+  /*
+    Release color cube tree storage.
+  */
+  DestroyColorCube(image,cube_info->root);
+  do
+  {
+    nodes=cube_info->node_queue->next;
+    cube_info->node_queue=(Nodes *)
+      RelinquishMagickMemory(cube_info->node_queue);
+    cube_info->node_queue=nodes;
+  } while (cube_info->node_queue != (Nodes *) NULL);
+  return((CubeInfo *) RelinquishMagickMemory(cube_info));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  D e s t r o y C o l o r C u b e                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyColorCube() traverses the color cube tree and frees the list of
+%  unique colors.
+%
+%  The format of the DestroyColorCube method is:
+%
+%      void DestroyColorCube(const Image *image,const NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o node_info: the address of a structure of type NodeInfo which points to a
+%      node in the color cube tree that is to be pruned.
+%
+*/
+static void DestroyColorCube(const Image *image,NodeInfo *node_info)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=image->matte == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      DestroyColorCube(image,node_info->child[i]);
+  if (node_info->list != (PixelPacket *) NULL)
+    node_info->list=(PixelPacket *) RelinquishMagickMemory(node_info->list);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C u b e I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCubeInfo() initializes the CubeInfo data structure.
+%
+%  The format of the GetCubeInfo method is:
+%
+%      cube_info=GetCubeInfo()
+%
+%  A description of each parameter follows.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+*/
+static CubeInfo *GetCubeInfo(void)
+{
+  CubeInfo
+    *cube_info;
+
+  /*
+    Initialize tree to describe color cube.
+  */
+  cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
+  if (cube_info == (CubeInfo *) NULL)
+    return((CubeInfo *) NULL);
+  (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
+  /*
+    Initialize root node.
+  */
+  cube_info->root=GetNodeInfo(cube_info,0);
+  if (cube_info->root == (NodeInfo *) NULL)
+    return((CubeInfo *) NULL);
+  return(cube_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t I m a g e H i s t o g r a m                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageHistogram() returns the unique colors in an image.
+%
+%  The format of the GetImageHistogram method is:
+%
+%      size_t GetImageHistogram(const Image *image,
+%        size_t *number_colors,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o file:  Write a histogram of the color distribution to this file handle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport PixelPacket *GetImageHistogram(const Image *image,
+  size_t *number_colors,ExceptionInfo *exception)
+{
+  PixelPacket
+    *histogram;
+
+  CubeInfo
+    *cube_info;
+
+  *number_colors=0;
+  histogram=(PixelPacket *) NULL;
+  cube_info=ClassifyImageColors(image,exception);
+  if (cube_info != (CubeInfo *) NULL)
+    {
+      histogram=(PixelPacket *) AcquireQuantumMemory((size_t) cube_info->colors,
+        sizeof(*histogram));
+      if (histogram == (PixelPacket *) NULL)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      else
+        {
+          PixelPacket
+            *root;
+
+          *number_colors=cube_info->colors;
+          root=histogram;
+          DefineImageHistogram(image,cube_info->root,&root);
+        }
+    }
+  cube_info=DestroyCubeInfo(image,cube_info);
+  return(histogram);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  G e t N o d e I n f o                                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNodeInfo() allocates memory for a new node in the color cube tree and
+%  presets all fields to zero.
+%
+%  The format of the GetNodeInfo method is:
+%
+%      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
+%
+%  A description of each parameter follows.
+%
+%    o cube_info: A pointer to the CubeInfo structure.
+%
+%    o level: Specifies the level in the storage_class the node resides.
+%
+*/
+static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t level)
+{
+  NodeInfo
+    *node_info;
+
+  if (cube_info->free_nodes == 0)
+    {
+      Nodes
+        *nodes;
+
+      /*
+        Allocate a new nodes of nodes.
+      */
+      nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
+      if (nodes == (Nodes *) NULL)
+        return((NodeInfo *) NULL);
+      nodes->next=cube_info->node_queue;
+      cube_info->node_queue=nodes;
+      cube_info->node_info=nodes->nodes;
+      cube_info->free_nodes=NodesInAList;
+    }
+  cube_info->free_nodes--;
+  node_info=cube_info->node_info++;
+  (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
+  node_info->level=level;
+  return(node_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I s H i s t o g r a m I m a g e                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsHistogramImage() returns MagickTrue if the image has 1024 unique colors or
+%  less.
+%
+%  The format of the IsHistogramImage method is:
+%
+%      MagickBooleanType IsHistogramImage(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsHistogramImage(const Image *image,
+  ExceptionInfo *exception)
+{
+#define MaximumUniqueColors  1024
+
+  CacheView
+    *image_view;
+
+  CubeInfo
+    *cube_info;
+
+  PixelInfo
+    pixel,
+    target;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    x;
+
+  register NodeInfo
+    *node_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    id,
+    index,
+    level;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((image->storage_class == PseudoClass) && (image->colors <= 256))
+    return(MagickTrue);
+  if (image->storage_class == PseudoClass)
+    return(MagickFalse);
+  /*
+    Initialize color description tree.
+  */
+  cube_info=GetCubeInfo();
+  if (cube_info == (CubeInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  GetPixelInfo(image,&pixel);
+  GetPixelInfo(image,&target);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      /*
+        Start at the root and proceed level by level.
+      */
+      node_info=cube_info->root;
+      index=MaxTreeDepth-1;
+      for (level=1; level < MaxTreeDepth; level++)
+      {
+        SetPixelInfo(image,p,&pixel);
+        id=ColorToNodeId(image,&pixel,index);
+        if (node_info->child[id] == (NodeInfo *) NULL)
+          {
+            node_info->child[id]=GetNodeInfo(cube_info,level);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              {
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                  image->filename);
+                break;
+              }
+          }
+        node_info=node_info->child[id];
+        index--;
+      }
+      if (level < MaxTreeDepth)
+        break;
+      for (i=0; i < (ssize_t) node_info->number_unique; i++)
+      {
+        SetPixelInfoPacket(image,&node_info->list[i],&target);
+        if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
+          break;
+      }
+      if (i < (ssize_t) node_info->number_unique)
+        node_info->list[i].count++;
+      else
+        {
+          /*
+            Add this unique color to the color list.
+          */
+          if (node_info->number_unique == 0)
+            node_info->list=(PixelPacket *) AcquireMagickMemory(
+              sizeof(*node_info->list));
+          else
+            node_info->list=(PixelPacket *) ResizeQuantumMemory(node_info->list,
+              (size_t) (i+1),sizeof(*node_info->list));
+          if (node_info->list == (PixelPacket *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+              break;
+            }
+          node_info->list[i].red=GetPixelRed(image,p);
+          node_info->list[i].green=GetPixelGreen(image,p);
+          node_info->list[i].blue=GetPixelBlue(image,p);
+          if (image->colorspace == CMYKColorspace)
+            node_info->list[i].black=GetPixelBlack(image,p);
+          node_info->list[i].alpha=GetPixelAlpha(image,p);
+          node_info->list[i].count=1;
+          node_info->number_unique++;
+          cube_info->colors++;
+          if (cube_info->colors > MaximumUniqueColors)
+            break;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (x < (ssize_t) image->columns)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  cube_info=DestroyCubeInfo(image,cube_info);
+  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I s P a l e t t e I m a g e                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsPaletteImage() returns MagickTrue if the image is PseudoClass and has 256
+%  unique colors or less.
+%
+%  The format of the IsPaletteImage method is:
+%
+%      MagickBooleanType IsPaletteImage(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsPaletteImage(const Image *image,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  CubeInfo
+    *cube_info;
+
+  PixelInfo
+    pixel,
+    target;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    x;
+
+  register NodeInfo
+    *node_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    id,
+    index,
+    level;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((image->storage_class == PseudoClass) && (image->colors <= 256))
+    return(MagickTrue);
+  if (image->storage_class == PseudoClass)
+    return(MagickFalse);
+  /*
+    Initialize color description tree.
+  */
+  cube_info=GetCubeInfo();
+  if (cube_info == (CubeInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  GetPixelInfo(image,&pixel);
+  GetPixelInfo(image,&target);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      /*
+        Start at the root and proceed level by level.
+      */
+      node_info=cube_info->root;
+      index=MaxTreeDepth-1;
+      for (level=1; level < MaxTreeDepth; level++)
+      {
+        SetPixelInfo(image,p,&pixel);
+        id=ColorToNodeId(image,&pixel,index);
+        if (node_info->child[id] == (NodeInfo *) NULL)
+          {
+            node_info->child[id]=GetNodeInfo(cube_info,level);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              {
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                  image->filename);
+                break;
+              }
+          }
+        node_info=node_info->child[id];
+        index--;
+      }
+      if (level < MaxTreeDepth)
+        break;
+      for (i=0; i < (ssize_t) node_info->number_unique; i++)
+      {
+        SetPixelInfoPacket(image,&node_info->list[i],&target);
+        if (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse)
+          break;
+      }
+      if (i < (ssize_t) node_info->number_unique)
+        node_info->list[i].count++;
+      else
+        {
+          /*
+            Add this unique color to the color list.
+          */
+          if (node_info->number_unique == 0)
+            node_info->list=(PixelPacket *) AcquireMagickMemory(
+              sizeof(*node_info->list));
+          else
+            node_info->list=(PixelPacket *) ResizeQuantumMemory(node_info->list,
+              (size_t) (i+1),sizeof(*node_info->list));
+          if (node_info->list == (PixelPacket *) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+              break;
+            }
+          node_info->list[i].red=GetPixelRed(image,p);
+          node_info->list[i].green=GetPixelGreen(image,p);
+          node_info->list[i].blue=GetPixelBlue(image,p);
+          if (image->colorspace == CMYKColorspace)
+            node_info->list[i].black=GetPixelBlack(image,p);
+          node_info->list[i].alpha=GetPixelAlpha(image,p);
+          node_info->list[i].count=1;
+          node_info->number_unique++;
+          cube_info->colors++;
+          if (cube_info->colors > 256)
+            break;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (x < (ssize_t) image->columns)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  cube_info=DestroyCubeInfo(image,cube_info);
+  return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M i n M a x S t r e t c h I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MinMaxStretchImage() uses the exact minimum and maximum values found in
+%  each of the channels given, as the BlackPoint and WhitePoint to linearly
+%  stretch the colors (and histogram) of the image.  The stretch points are
+%  also moved further inward by the adjustment values given.
+%
+%  If the adjustment values are both zero this function is equivalent to a
+%  perfect normalization (or autolevel) of the image.
+%
+%  Each channel is stretched independantally of each other (producing color
+%  distortion) unless the special 'SyncChannels' flag is also provided in the
+%  channels setting. If this flag is present the minimum and maximum point
+%  will be extracted from all the given channels, and those channels will be
+%  stretched by exactly the same amount (preventing color distortion).
+%
+%  In the special case that only ONE value is found in a channel of the image
+%  that value is not stretched, that value is left as is.
+%
+%  The 'SyncChannels' is turned on in the 'DefaultChannels' setting by
+%  default.
+%
+%  The format of the MinMaxStretchImage method is:
+%
+%      MagickBooleanType MinMaxStretchImage(Image *image,
+%        const ChannelType channel, const double black_adjust,
+%        const double white_adjust)
+%
+%  A description of each parameter follows:
+%
+%    o image: The image to auto-level
+%
+%    o channel: The channels to auto-level.  If the special 'SyncChannels'
+%      flag is set, all the given channels are stretched by the same amount.
+%
+%    o black_adjust, white_adjust:  Move the Black/White Point inward
+%      from the minimum and maximum points by this color value.
+%
+*/
+
+MagickExport MagickBooleanType MinMaxStretchImage(Image *image,
+  const ChannelType channel,const double black_value,const double white_value)
+{
+  double
+    min,
+    max;
+
+  MagickStatusType
+    status;
+
+  status=MagickTrue;
+  if ((channel & SyncChannels) != 0)
+    {
+      /*
+        Auto-level all channels equally.
+      */
+      (void) GetImageChannelRange(image,channel,&min,&max,&image->exception);
+      min+=black_value;
+      max-=white_value;
+      if (fabs(min-max) >= MagickEpsilon)
+        status&=LevelImageChannel(image,channel,min,max,1.0);
+      return(status != 0 ? MagickTrue : MagickFalse);
+    }
+  /*
+    Auto-level each channel separately.
+  */
+  if ((channel & RedChannel) != 0)
+    {
+      (void) GetImageChannelRange(image,RedChannel,&min,&max,&image->exception);
+      min+=black_value;
+      max-=white_value;
+      if (fabs(min-max) >= MagickEpsilon)
+        status&=LevelImageChannel(image,RedChannel,min,max,1.0);
+    }
+  if ((channel & GreenChannel) != 0)
+    {
+      (void) GetImageChannelRange(image,GreenChannel,&min,&max,
+        &image->exception);
+      min+=black_value;
+      max-=white_value;
+      if (fabs(min-max) >= MagickEpsilon)
+        status&=LevelImageChannel(image,GreenChannel,min,max,1.0);
+    }
+  if ((channel & BlueChannel) != 0)
+    {
+      (void) GetImageChannelRange(image,BlueChannel,&min,&max,
+        &image->exception);
+      min+=black_value;
+      max-=white_value;
+      if (fabs(min-max) >= MagickEpsilon)
+        status&=LevelImageChannel(image,BlueChannel,min,max,1.0);
+    }
+  if (((channel & BlackChannel) != 0) &&
+       (image->colorspace == CMYKColorspace))
+    {
+      (void) GetImageChannelRange(image,BlackChannel,&min,&max,
+        &image->exception);
+      min+=black_value;
+      max-=white_value;
+      if (fabs(min-max) >= MagickEpsilon)
+        status&=LevelImageChannel(image,BlackChannel,min,max,1.0);
+    }
+  if (((channel & OpacityChannel) != 0) &&
+       (image->matte == MagickTrue))
+    {
+      (void) GetImageChannelRange(image,OpacityChannel,&min,&max,
+        &image->exception);
+      min+=black_value;
+      max-=white_value;
+      if (fabs(min-max) >= MagickEpsilon)
+        status&=LevelImageChannel(image,OpacityChannel,min,max,1.0);
+    }
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t N u m b e r C o l o r s                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNumberColors() returns the number of unique colors in an image.
+%
+%  The format of the GetNumberColors method is:
+%
+%      size_t GetNumberColors(const Image *image,FILE *file,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o file:  Write a histogram of the color distribution to this file handle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int HistogramCompare(const void *x,const void *y)
+{
+  const PixelPacket
+    *color_1,
+    *color_2;
+
+  color_1=(const PixelPacket *) x;
+  color_2=(const PixelPacket *) y;
+  if (color_2->red != color_1->red)
+    return((int) color_1->red-(int) color_2->red);
+  if (color_2->green != color_1->green)
+    return((int) color_1->green-(int) color_2->green);
+  if (color_2->blue != color_1->blue)
+    return((int) color_1->blue-(int) color_2->blue);
+  return((int) color_2->count-(int) color_1->count);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport size_t GetNumberColors(const Image *image,FILE *file,
+  ExceptionInfo *exception)
+{
+#define HistogramImageTag  "Histogram/Image"
+
+  char
+    color[MaxTextExtent],
+    hex[MaxTextExtent],
+    tuple[MaxTextExtent];
+
+  PixelPacket
+    *histogram;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    pixel;
+
+  register PixelPacket
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_colors;
+
+  number_colors=0;
+  if (file == (FILE *) NULL)
+    {
+      CubeInfo
+        *cube_info;
+
+      cube_info=ClassifyImageColors(image,exception);
+      if (cube_info != (CubeInfo *) NULL)
+        number_colors=cube_info->colors;
+      cube_info=DestroyCubeInfo(image,cube_info);
+      return(number_colors);
+    }
+  histogram=GetImageHistogram(image,&number_colors,exception);
+  if (histogram == (PixelPacket *) NULL)
+    return(number_colors);
+  qsort((void *) histogram,(size_t) number_colors,sizeof(*histogram),
+    HistogramCompare);
+  GetPixelInfo(image,&pixel);
+  p=histogram;
+  status=MagickTrue;
+  for (i=0; i < (ssize_t) number_colors; i++)
+  {
+    SetPixelInfoPacket(image,p,&pixel);
+    (void) CopyMagickString(tuple,"(",MaxTextExtent);
+    ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
+    (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+    ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
+    (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+    ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
+    if (pixel.colorspace == CMYKColorspace)
+      {
+        (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+        ConcatenateColorComponent(&pixel,BlackChannel,X11Compliance,tuple);
+      }
+    if (pixel.matte != MagickFalse)
+      {
+        (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+        ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
+      }
+    (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
+    (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,exception);
+    GetColorTuple(&pixel,MagickTrue,hex);
+    (void) FormatLocaleFile(file,"%10" MagickSizeFormat,p->count);
+    (void) FormatLocaleFile(file,": %s %s %s\n",tuple,hex,color);
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,HistogramImageTag,(MagickOffsetType) i,
+          number_colors);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+    p++;
+  }
+  (void) fflush(file);
+  histogram=(PixelPacket *) RelinquishMagickMemory(histogram);
+  if (status == MagickFalse)
+    return(0);
+  return(number_colors);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  U n i q u e I m a g e C o l o r s                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UniqueImageColors() returns the unique colors of an image.
+%
+%  The format of the UniqueImageColors method is:
+%
+%      Image *UniqueImageColors(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void UniqueColorsToImage(Image *unique_image,CacheView *unique_view,
+  CubeInfo *cube_info,const NodeInfo *node_info,ExceptionInfo *exception)
+{
+#define UniqueColorsImageTag  "UniqueColors/Image"
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=unique_image->matte == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      UniqueColorsToImage(unique_image,unique_view,cube_info,
+        node_info->child[i],exception);
+  if (node_info->level == (MaxTreeDepth-1))
+    {
+      register PixelPacket
+        *p;
+
+      register Quantum
+        *restrict q;
+
+      status=MagickTrue;
+      p=node_info->list;
+      for (i=0; i < (ssize_t) node_info->number_unique; i++)
+      {
+        q=QueueCacheViewAuthenticPixels(unique_view,cube_info->x,0,1,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          continue;
+        SetPixelRed(unique_image,p->red,q);
+        SetPixelGreen(unique_image,p->green,q);
+        SetPixelBlue(unique_image,p->blue,q);
+        SetPixelAlpha(unique_image,p->alpha,q);
+        if (unique_image->colorspace == CMYKColorspace)
+          SetPixelBlack(unique_image,p->black,q);
+        if (SyncCacheViewAuthenticPixels(unique_view,exception) == MagickFalse)
+          break;
+        cube_info->x++;
+        p++;
+      }
+      if (unique_image->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+          proceed=SetImageProgress(unique_image,UniqueColorsImageTag,
+            cube_info->progress,cube_info->colors);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+      cube_info->progress++;
+      if (status == MagickFalse)
+        return;
+    }
+}
+
+MagickExport Image *UniqueImageColors(const Image *image,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *unique_view;
+
+  CubeInfo
+    *cube_info;
+
+  Image
+    *unique_image;
+
+  cube_info=ClassifyImageColors(image,exception);
+  if (cube_info == (CubeInfo *) NULL)
+    return((Image *) NULL);
+  unique_image=CloneImage(image,cube_info->colors,1,MagickTrue,exception);
+  if (unique_image == (Image *) NULL)
+    return(unique_image);
+  if (SetImageStorageClass(unique_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&unique_image->exception);
+      unique_image=DestroyImage(unique_image);
+      return((Image *) NULL);
+    }
+  unique_view=AcquireCacheView(unique_image);
+  UniqueColorsToImage(unique_image,unique_view,cube_info,cube_info->root,
+    exception);
+  unique_view=DestroyCacheView(unique_view);
+  if (cube_info->colors < MaxColormapSize)
+    {
+      QuantizeInfo
+        *quantize_info;
+
+      quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
+      quantize_info->number_colors=MaxColormapSize;
+      quantize_info->dither=MagickFalse;
+      quantize_info->tree_depth=8;
+      (void) QuantizeImage(quantize_info,unique_image);
+      quantize_info=DestroyQuantizeInfo(quantize_info);
+    }
+  cube_info=DestroyCubeInfo(image,cube_info);
+  return(unique_image);
+}
diff --git a/MagickCore/histogram.h b/MagickCore/histogram.h
new file mode 100644
index 0000000..a4151b5
--- /dev/null
+++ b/MagickCore/histogram.h
@@ -0,0 +1,43 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore histogram methods.
+*/
+#ifndef _MAGICKCORE_HISTOGRAM_H
+#define _MAGICKCORE_HISTOGRAM_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport PixelPacket
+  *GetImageHistogram(const Image *,size_t *,ExceptionInfo *);
+
+extern MagickExport Image
+  *UniqueImageColors(const Image *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  IsHistogramImage(const Image *,ExceptionInfo *),
+  IsPaletteImage(const Image *,ExceptionInfo *),
+  MinMaxStretchImage(Image *,const ChannelType,const double,const double);
+
+extern MagickExport size_t
+  GetNumberColors(const Image *,FILE *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/identify.c b/MagickCore/identify.c
new file mode 100644
index 0000000..6aa59e1
--- /dev/null
+++ b/MagickCore/identify.c
@@ -0,0 +1,1074 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           IIIII  DDDD   EEEEE  N   N  TTTTT  IIIII  FFFFF  Y   Y            %
+%             I    D   D  E      NN  N    T      I    F       Y Y             %
+%             I    D   D  EEE    N N N    T      I    FFF      Y              %
+%             I    D   D  E      N  NN    T      I    F        Y              %
+%           IIIII  DDDD   EEEEE  N   N    T    IIIII  F        Y              %
+%                                                                             %
+%                                                                             %
+%               Identify an Image Format and Characteristics.                 %
+%                                                                             %
+%                           Software Design                                   %
+%                             John Cristy                                     %
+%                            September 1994                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Identify describes the format and characteristics of one or more image
+%  files.  It will also report if an image is incomplete or corrupt.
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/client.h"
+#include "MagickCore/coder.h"
+#include "MagickCore/color.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/feature.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/identify.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/prepress.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/signature.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H)
+#include <lcms/lcms2.h>
+#elif defined(MAGICKCORE_HAVE_LCMS2_H)
+#include "lcms2.h"
+#elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
+#include <lcms/lcms.h>
+#else
+#include "lcms.h"
+#endif
+#endif
+
+/*
+  Define declarations.
+*/
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
+#define cmsUInt32Number  DWORD
+#endif
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I d e n t i f y I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IdentifyImage() identifies an image by printing its attributes to the file.
+%  Attributes include the image width, height, size, and others.
+%
+%  The format of the IdentifyImage method is:
+%
+%      MagickBooleanType IdentifyImage(Image *image,FILE *file,
+%        const MagickBooleanType verbose)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o file: the file, typically stdout.
+%
+%    o verbose: A value other than zero prints more detailed information
+%      about the image.
+%
+*/
+
+static ssize_t PrintChannelFeatures(FILE *file,const ChannelType channel,
+  const char *name,const ChannelFeatures *channel_features)
+{
+#define PrintFeature(feature) \
+  GetMagickPrecision(),(feature)[0], \
+  GetMagickPrecision(),(feature)[1], \
+  GetMagickPrecision(),(feature)[2], \
+  GetMagickPrecision(),(feature)[3], \
+  GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \
+
+#define FeaturesFormat "    %s:\n" \
+  "      Angular Second Moment:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Contrast:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Correlation:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Sum of Squares: Variance:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Inverse Difference Moment:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Sum Average:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Sum Variance:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Sum Entropy:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Entropy:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Difference Variance:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Difference Entropy:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Information Measure of Correlation 1:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Information Measure of Correlation 2:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n" \
+  "      Maximum Correlation Coefficient:\n" \
+  "        %.*g, %.*g, %.*g, %.*g, %.*g\n"
+
+  ssize_t
+    n;
+
+  n=FormatLocaleFile(file,FeaturesFormat,name,
+    PrintFeature(channel_features[channel].angular_second_moment),
+    PrintFeature(channel_features[channel].contrast),
+    PrintFeature(channel_features[channel].correlation),
+    PrintFeature(channel_features[channel].variance_sum_of_squares),
+    PrintFeature(channel_features[channel].inverse_difference_moment),
+    PrintFeature(channel_features[channel].sum_average),
+    PrintFeature(channel_features[channel].sum_variance),
+    PrintFeature(channel_features[channel].sum_entropy),
+    PrintFeature(channel_features[channel].entropy),
+    PrintFeature(channel_features[channel].difference_variance),
+    PrintFeature(channel_features[channel].difference_entropy),
+    PrintFeature(channel_features[channel].measure_of_correlation_1),
+    PrintFeature(channel_features[channel].measure_of_correlation_2),
+    PrintFeature(channel_features[channel].maximum_correlation_coefficient));
+  return(n);
+}
+
+static ssize_t PrintChannelStatistics(FILE *file,const ChannelType channel,
+  const char *name,const double scale,
+  const ChannelStatistics *channel_statistics)
+{
+#define StatisticsFormat "    %s:\n      min: " QuantumFormat  \
+  " (%g)\n      max: " QuantumFormat " (%g)\n"  \
+  "      mean: %g (%g)\n      standard deviation: %g (%g)\n"  \
+  "      kurtosis: %g\n      skewness: %g\n"
+
+  ssize_t
+    n;
+
+  n=FormatLocaleFile(file,StatisticsFormat,name,ClampToQuantum(scale*
+    channel_statistics[channel].minima),channel_statistics[channel].minima/
+    (double) QuantumRange,ClampToQuantum(scale*
+    channel_statistics[channel].maxima),channel_statistics[channel].maxima/
+    (double) QuantumRange,scale*channel_statistics[channel].mean,
+    channel_statistics[channel].mean/(double) QuantumRange,scale*
+    channel_statistics[channel].standard_deviation,
+    channel_statistics[channel].standard_deviation/(double) QuantumRange,
+    channel_statistics[channel].kurtosis,channel_statistics[channel].skewness);
+  return(n);
+}
+
+MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
+  const MagickBooleanType verbose)
+{
+  char
+    color[MaxTextExtent],
+    format[MaxTextExtent],
+    key[MaxTextExtent];
+
+  ChannelFeatures
+    *channel_features;
+
+  ChannelStatistics
+    *channel_statistics;
+
+  ColorspaceType
+    colorspace;
+
+  const char
+    *artifact,
+    *name,
+    *property,
+    *registry,
+    *value;
+
+  const MagickInfo
+    *magick_info;
+
+  double
+    elapsed_time,
+    user_time;
+
+  ExceptionInfo
+    *exception;
+
+  ImageType
+    type;
+
+  MagickBooleanType
+    ping;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    distance,
+    scale;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (file == (FILE *) NULL)
+    file=stdout;
+  *format='\0';
+  elapsed_time=GetElapsedTime(&image->timer);
+  user_time=GetUserTime(&image->timer);
+  GetTimerInfo(&image->timer);
+  if (verbose == MagickFalse)
+    {
+      /*
+        Display summary info about the image.
+      */
+      if (*image->magick_filename != '\0')
+        if (LocaleCompare(image->magick_filename,image->filename) != 0)
+          (void) FormatLocaleFile(file,"%s=>",image->magick_filename);
+       if ((GetPreviousImageInList(image) == (Image *) NULL) &&
+           (GetNextImageInList(image) == (Image *) NULL) &&
+           (image->scene == 0))
+        (void) FormatLocaleFile(file,"%s ",image->filename);
+      else
+        (void) FormatLocaleFile(file,"%s[%.20g] ",image->filename,(double)
+          image->scene);
+      (void) FormatLocaleFile(file,"%s ",image->magick);
+      if ((image->magick_columns != 0) || (image->magick_rows != 0))
+        if ((image->magick_columns != image->columns) ||
+            (image->magick_rows != image->rows))
+          (void) FormatLocaleFile(file,"%.20gx%.20g=>",(double)
+            image->magick_columns,(double) image->magick_rows);
+      (void) FormatLocaleFile(file,"%.20gx%.20g ",(double) image->columns,
+        (double) image->rows);
+      if ((image->page.width != 0) || (image->page.height != 0) ||
+          (image->page.x != 0) || (image->page.y != 0))
+        (void) FormatLocaleFile(file,"%.20gx%.20g%+.20g%+.20g ",(double)
+          image->page.width,(double) image->page.height,(double) image->page.x,
+          (double) image->page.y);
+      (void) FormatLocaleFile(file,"%.20g-bit ",(double) image->depth);
+      if (image->type != UndefinedType)
+        (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic(
+          MagickTypeOptions,(ssize_t) image->type));
+      if (image->storage_class == DirectClass)
+        {
+          (void) FormatLocaleFile(file,"DirectClass ");
+          if (image->total_colors != 0)
+            {
+              (void) FormatMagickSize(image->total_colors,MagickFalse,format);
+              (void) FormatLocaleFile(file,"%s ",format);
+            }
+        }
+      else
+        if (image->total_colors <= image->colors)
+          (void) FormatLocaleFile(file,"PseudoClass %.20gc ",(double)
+            image->colors);
+        else
+          (void) FormatLocaleFile(file,"PseudoClass %.20g=>%.20gc ",(double)
+            image->total_colors,(double) image->colors);
+      if (image->error.mean_error_per_pixel != 0.0)
+        (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double)
+          (image->error.mean_error_per_pixel+0.5),
+          image->error.normalized_mean_error,
+          image->error.normalized_maximum_error);
+      if (GetBlobSize(image) != 0)
+        {
+          (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format);
+          (void) FormatLocaleFile(file,"%s ",format);
+        }
+      (void) FormatLocaleFile(file,"%0.3fu %lu:%02lu.%03lu",user_time,
+        (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod(
+        elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-
+        floor(elapsed_time))));
+      (void) FormatLocaleFile(file,"\n");
+      (void) fflush(file);
+      return(ferror(file) != 0 ? MagickFalse : MagickTrue);
+    }
+  /*
+    Display verbose info about the image.
+  */
+  exception=AcquireExceptionInfo();
+  p=GetVirtualPixels(image,0,0,1,1,exception);
+  exception=DestroyExceptionInfo(exception);
+  ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse;
+  type=GetImageType(image,&image->exception);
+  (void) SignatureImage(image);
+  (void) FormatLocaleFile(file,"Image: %s\n",image->filename);
+  if (*image->magick_filename != '\0')
+    if (LocaleCompare(image->magick_filename,image->filename) != 0)
+      {
+        char
+          filename[MaxTextExtent];
+
+        GetPathComponent(image->magick_filename,TailPath,filename);
+        (void) FormatLocaleFile(file,"  Base filename: %s\n",filename);
+      }
+  magick_info=GetMagickInfo(image->magick,&image->exception);
+  if ((magick_info == (const MagickInfo *) NULL) ||
+      (*GetMagickDescription(magick_info) == '\0'))
+    (void) FormatLocaleFile(file,"  Format: %s\n",image->magick);
+  else
+    (void) FormatLocaleFile(file,"  Format: %s (%s)\n",image->magick,
+      GetMagickDescription(magick_info));
+  (void) FormatLocaleFile(file,"  Class: %s\n",CommandOptionToMnemonic(
+    MagickClassOptions,(ssize_t) image->storage_class));
+  (void) FormatLocaleFile(file,"  Geometry: %.20gx%.20g%+.20g%+.20g\n",(double)
+    image->columns,(double) image->rows,(double) image->tile_offset.x,(double)
+    image->tile_offset.y);
+  if ((image->magick_columns != 0) || (image->magick_rows != 0))
+    if ((image->magick_columns != image->columns) ||
+        (image->magick_rows != image->rows))
+      (void) FormatLocaleFile(file,"  Base geometry: %.20gx%.20g\n",(double)
+        image->magick_columns,(double) image->magick_rows);
+  if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
+    {
+      (void) FormatLocaleFile(file,"  Resolution: %gx%g\n",image->x_resolution,
+        image->y_resolution);
+      (void) FormatLocaleFile(file,"  Print size: %gx%g\n",(double)
+        image->columns/image->x_resolution,(double) image->rows/
+        image->y_resolution);
+    }
+  (void) FormatLocaleFile(file,"  Units: %s\n",CommandOptionToMnemonic(
+    MagickResolutionOptions,(ssize_t) image->units));
+  (void) FormatLocaleFile(file,"  Type: %s\n",CommandOptionToMnemonic(
+    MagickTypeOptions,(ssize_t) type));
+  if (image->type != UndefinedType)
+    (void) FormatLocaleFile(file,"  Base type: %s\n",CommandOptionToMnemonic(
+      MagickTypeOptions,(ssize_t) image->type));
+  (void) FormatLocaleFile(file,"  Endianess: %s\n",CommandOptionToMnemonic(
+    MagickEndianOptions,(ssize_t) image->endian));
+  /*
+    Detail channel depth and extrema.
+  */
+  (void) FormatLocaleFile(file,"  Colorspace: %s\n",CommandOptionToMnemonic(
+    MagickColorspaceOptions,(ssize_t) image->colorspace));
+  channel_statistics=(ChannelStatistics *) NULL;
+  channel_features=(ChannelFeatures *) NULL;
+  colorspace=image->colorspace;
+  if (ping == MagickFalse)
+    {
+      size_t
+        depth;
+
+      channel_statistics=GetImageChannelStatistics(image,&image->exception);
+      artifact=GetImageArtifact(image,"identify:features");
+      if (artifact != (const char *) NULL)
+        {
+          distance=StringToUnsignedLong(artifact);
+          channel_features=GetImageChannelFeatures(image,distance,
+            &image->exception);
+        }
+      depth=GetImageDepth(image,&image->exception);
+      if (image->depth == depth)
+        (void) FormatLocaleFile(file,"  Depth: %.20g-bit\n",(double)
+          image->depth);
+      else
+        (void) FormatLocaleFile(file,"  Depth: %.20g/%.20g-bit\n",(double)
+          image->depth,(double) depth);
+      (void) FormatLocaleFile(file,"  Channel depth:\n");
+      if (IsImageGray(image,&image->exception) != MagickFalse)
+        colorspace=GRAYColorspace;
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) FormatLocaleFile(file,"    red: %.20g-bit\n",(double)
+            channel_statistics[RedChannel].depth);
+          (void) FormatLocaleFile(file,"    green: %.20g-bit\n",(double)
+            channel_statistics[GreenChannel].depth);
+          (void) FormatLocaleFile(file,"    blue: %.20g-bit\n",(double)
+            channel_statistics[BlueChannel].depth);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) FormatLocaleFile(file,"    cyan: %.20g-bit\n",(double)
+            channel_statistics[CyanChannel].depth);
+          (void) FormatLocaleFile(file,"    magenta: %.20g-bit\n",(double)
+            channel_statistics[MagentaChannel].depth);
+          (void) FormatLocaleFile(file,"    yellow: %.20g-bit\n",(double)
+            channel_statistics[YellowChannel].depth);
+          (void) FormatLocaleFile(file,"    black: %.20g-bit\n",(double)
+            channel_statistics[BlackChannel].depth);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) FormatLocaleFile(file,"    gray: %.20g-bit\n",(double)
+            channel_statistics[GrayChannel].depth);
+          break;
+        }
+      }
+      if (image->matte != MagickFalse)
+        (void) FormatLocaleFile(file,"    alpha: %.20g-bit\n",(double)
+          channel_statistics[OpacityChannel].depth);
+      scale=1;
+      if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
+        scale=QuantumRange/((size_t) QuantumRange >> ((size_t)
+          MAGICKCORE_QUANTUM_DEPTH-image->depth));
+    }
+  if (channel_statistics != (ChannelStatistics *) NULL)
+    {
+      (void) FormatLocaleFile(file,"  Channel statistics:\n");
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) PrintChannelStatistics(file,RedChannel,"Red",1.0/scale,
+            channel_statistics);
+          (void) PrintChannelStatistics(file,GreenChannel,"Green",1.0/scale,
+            channel_statistics);
+          (void) PrintChannelStatistics(file,BlueChannel,"Blue",1.0/scale,
+            channel_statistics);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) PrintChannelStatistics(file,CyanChannel,"Cyan",1.0/scale,
+            channel_statistics);
+          (void) PrintChannelStatistics(file,MagentaChannel,"Magenta",1.0/scale,
+            channel_statistics);
+          (void) PrintChannelStatistics(file,YellowChannel,"Yellow",1.0/scale,
+            channel_statistics);
+          (void) PrintChannelStatistics(file,BlackChannel,"Black",1.0/scale,
+            channel_statistics);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) PrintChannelStatistics(file,GrayChannel,"Gray",1.0/scale,
+            channel_statistics);
+          break;
+        }
+      }
+      if (image->matte != MagickFalse)
+        (void) PrintChannelStatistics(file,AlphaChannel,"Alpha",1.0/scale,
+          channel_statistics);
+      if (colorspace != GRAYColorspace)
+        {
+          (void) FormatLocaleFile(file,"  Image statistics:\n");
+          (void) PrintChannelStatistics(file,CompositeChannels,"Overall",1.0/
+            scale,channel_statistics);
+        }
+      channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+        channel_statistics);
+    }
+  if (channel_features != (ChannelFeatures *) NULL)
+    {
+      (void) FormatLocaleFile(file,"  Channel features (horizontal, vertical, "
+        "left and right diagonals, average):\n");
+      switch (colorspace)
+      {
+        case RGBColorspace:
+        default:
+        {
+          (void) PrintChannelFeatures(file,RedChannel,"Red",channel_features);
+          (void) PrintChannelFeatures(file,GreenChannel,"Green",
+            channel_features);
+          (void) PrintChannelFeatures(file,BlueChannel,"Blue",channel_features);
+          break;
+        }
+        case CMYKColorspace:
+        {
+          (void) PrintChannelFeatures(file,CyanChannel,"Cyan",channel_features);
+          (void) PrintChannelFeatures(file,MagentaChannel,"Magenta",
+            channel_features);
+          (void) PrintChannelFeatures(file,YellowChannel,"Yellow",
+            channel_features);
+          (void) PrintChannelFeatures(file,BlackChannel,"Black",
+            channel_features);
+          break;
+        }
+        case GRAYColorspace:
+        {
+          (void) PrintChannelFeatures(file,GrayChannel,"Gray",channel_features);
+          break;
+        }
+      }
+      if (image->matte != MagickFalse)
+        (void) PrintChannelFeatures(file,AlphaChannel,"Alpha",channel_features);
+      channel_features=(ChannelFeatures *) RelinquishMagickMemory(
+        channel_features);
+    }
+  if (ping == MagickFalse)
+    {
+      if (image->colorspace == CMYKColorspace)
+        (void) FormatLocaleFile(file,"  Total ink density: %.0f%%\n",100.0*
+          GetImageTotalInkDensity(image)/(double) QuantumRange);
+      x=0;
+      if (image->matte != MagickFalse)
+        {
+          register const Quantum
+            *p;
+
+          p=(const Quantum *) NULL;
+          for (y=0; y < (ssize_t) image->rows; y++)
+          {
+            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) image->columns; x++)
+            {
+              if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)
+                break;
+              p+=GetPixelChannels(image);
+            }
+            if (x < (ssize_t) image->columns)
+              break;
+          }
+          if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows))
+            {
+              char
+                tuple[MaxTextExtent];
+
+              PixelInfo
+                pixel;
+
+              GetPixelInfo(image,&pixel);
+              SetPixelInfo(image,p,&pixel);
+              (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
+                &image->exception);
+              (void) FormatLocaleFile(file,"  Alpha: %s ",tuple);
+              GetColorTuple(&pixel,MagickTrue,tuple);
+              (void) FormatLocaleFile(file,"  %s\n",tuple);
+            }
+        }
+      artifact=GetImageArtifact(image,"identify:unique-colors");
+      if (IsHistogramImage(image,&image->exception) != MagickFalse)
+        {
+          (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
+            GetNumberColors(image,(FILE *) NULL,&image->exception));
+          (void) FormatLocaleFile(file,"  Histogram:\n");
+          (void) GetNumberColors(image,file,&image->exception);
+        }
+      else
+        if ((artifact != (const char *) NULL) &&
+            (IsMagickTrue(artifact) != MagickFalse))
+          (void) FormatLocaleFile(file,"  Colors: %.20g\n",(double)
+            GetNumberColors(image,(FILE *) NULL,&image->exception));
+    }
+  if (image->storage_class == PseudoClass)
+    {
+      (void) FormatLocaleFile(file,"  Colormap: %.20g\n",(double) image->colors);
+      if (image->colors <= 1024)
+        {
+          char
+            color[MaxTextExtent],
+            hex[MaxTextExtent],
+            tuple[MaxTextExtent];
+
+          PixelInfo
+            pixel;
+
+          register PixelPacket
+            *restrict p;
+
+          GetPixelInfo(image,&pixel);
+          p=image->colormap;
+          for (i=0; i < (ssize_t) image->colors; i++)
+          {
+            SetPixelInfoPacket(image,p,&pixel);
+            (void) CopyMagickString(tuple,"(",MaxTextExtent);
+            ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
+            (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+            ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
+            (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+            ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
+            if (pixel.colorspace == CMYKColorspace)
+              {
+                (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+                ConcatenateColorComponent(&pixel,BlackChannel,X11Compliance,
+                  tuple);
+              }
+            if (pixel.matte != MagickFalse)
+              {
+                (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+                ConcatenateColorComponent(&pixel,AlphaChannel,X11Compliance,
+                  tuple);
+              }
+            (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
+            (void) QueryMagickColorname(image,&pixel,SVGCompliance,color,
+              &image->exception);
+            GetColorTuple(&pixel,MagickTrue,hex);
+            (void) FormatLocaleFile(file,"  %8ld: %s %s %s\n",(long) i,tuple,
+              hex,color);
+            p++;
+          }
+        }
+    }
+  if (image->error.mean_error_per_pixel != 0.0)
+    (void) FormatLocaleFile(file,"  Mean error per pixel: %g\n",
+      image->error.mean_error_per_pixel);
+  if (image->error.normalized_mean_error != 0.0)
+    (void) FormatLocaleFile(file,"  Normalized mean error: %g\n",
+      image->error.normalized_mean_error);
+  if (image->error.normalized_maximum_error != 0.0)
+    (void) FormatLocaleFile(file,"  Normalized maximum error: %g\n",
+      image->error.normalized_maximum_error);
+  (void) FormatLocaleFile(file,"  Rendering intent: %s\n",
+    CommandOptionToMnemonic(MagickIntentOptions,(ssize_t)
+    image->rendering_intent));
+  if (image->gamma != 0.0)
+    (void) FormatLocaleFile(file,"  Gamma: %g\n",image->gamma);
+  if ((image->chromaticity.red_primary.x != 0.0) ||
+      (image->chromaticity.green_primary.x != 0.0) ||
+      (image->chromaticity.blue_primary.x != 0.0) ||
+      (image->chromaticity.white_point.x != 0.0))
+    {
+      /*
+        Display image chromaticity.
+      */
+      (void) FormatLocaleFile(file,"  Chromaticity:\n");
+      (void) FormatLocaleFile(file,"    red primary: (%g,%g)\n",
+        image->chromaticity.red_primary.x,image->chromaticity.red_primary.y);
+      (void) FormatLocaleFile(file,"    green primary: (%g,%g)\n",
+        image->chromaticity.green_primary.x,
+        image->chromaticity.green_primary.y);
+      (void) FormatLocaleFile(file,"    blue primary: (%g,%g)\n",
+        image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y);
+      (void) FormatLocaleFile(file,"    white point: (%g,%g)\n",
+        image->chromaticity.white_point.x,image->chromaticity.white_point.y);
+    }
+  if ((image->extract_info.width*image->extract_info.height) != 0)
+    (void) FormatLocaleFile(file,"  Tile geometry: %.20gx%.20g%+.20g%+.20g\n",
+      (double) image->extract_info.width,(double) image->extract_info.height,
+      (double) image->extract_info.x,(double) image->extract_info.y);
+  (void) FormatLocaleFile(file,"  Interlace: %s\n",CommandOptionToMnemonic(
+    MagickInterlaceOptions,(ssize_t) image->interlace));
+  (void) QueryColorname(image,&image->background_color,SVGCompliance,color,
+    &image->exception);
+  (void) FormatLocaleFile(file,"  Background color: %s\n",color);
+  (void) QueryColorname(image,&image->border_color,SVGCompliance,color,
+    &image->exception);
+  (void) FormatLocaleFile(file,"  Border color: %s\n",color);
+  (void) QueryColorname(image,&image->matte_color,SVGCompliance,color,
+    &image->exception);
+  (void) FormatLocaleFile(file,"  Matte color: %s\n",color);
+  (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color,
+    &image->exception);
+  (void) FormatLocaleFile(file,"  Transparent color: %s\n",color);
+  (void) FormatLocaleFile(file,"  Compose: %s\n",CommandOptionToMnemonic(
+    MagickComposeOptions,(ssize_t) image->compose));
+  if ((image->page.width != 0) || (image->page.height != 0) ||
+      (image->page.x != 0) || (image->page.y != 0))
+    (void) FormatLocaleFile(file,"  Page geometry: %.20gx%.20g%+.20g%+.20g\n",
+      (double) image->page.width,(double) image->page.height,(double)
+      image->page.x,(double) image->page.y);
+  if ((image->page.x != 0) || (image->page.y != 0))
+    (void) FormatLocaleFile(file,"  Origin geometry: %+.20g%+.20g\n",(double)
+      image->page.x,(double) image->page.y);
+  (void) FormatLocaleFile(file,"  Dispose: %s\n",CommandOptionToMnemonic(
+    MagickDisposeOptions,(ssize_t) image->dispose));
+  if (image->delay != 0)
+    (void) FormatLocaleFile(file,"  Delay: %.20gx%.20g\n",(double) image->delay,
+      (double) image->ticks_per_second);
+  if (image->iterations != 1)
+    (void) FormatLocaleFile(file,"  Iterations: %.20g\n",(double)
+      image->iterations);
+  if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
+    (void) FormatLocaleFile(file,"  Scene: %.20g of %.20g\n",(double)
+      image->scene,(double) GetImageListLength(image));
+  else
+    if (image->scene != 0)
+      (void) FormatLocaleFile(file,"  Scene: %.20g\n",(double) image->scene);
+  (void) FormatLocaleFile(file,"  Compression: %s\n",CommandOptionToMnemonic(
+    MagickCompressOptions,(ssize_t) image->compression));
+  if (image->quality != UndefinedCompressionQuality)
+    (void) FormatLocaleFile(file,"  Quality: %.20g\n",(double) image->quality);
+  (void) FormatLocaleFile(file,"  Orientation: %s\n",CommandOptionToMnemonic(
+    MagickOrientationOptions,(ssize_t) image->orientation));
+  if (image->montage != (char *) NULL)
+    (void) FormatLocaleFile(file,"  Montage: %s\n",image->montage);
+  if (image->directory != (char *) NULL)
+    {
+      Image
+        *tile;
+
+      ImageInfo
+        *image_info;
+
+      register char
+        *p,
+        *q;
+
+      WarningHandler
+        handler;
+
+      /*
+        Display visual image directory.
+      */
+      image_info=AcquireImageInfo();
+      (void) CloneString(&image_info->size,"64x64");
+      (void) FormatLocaleFile(file,"  Directory:\n");
+      for (p=image->directory; *p != '\0'; p++)
+      {
+        q=p;
+        while ((*q != '\n') && (*q != '\0'))
+          q++;
+        (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1));
+        p=q;
+        (void) FormatLocaleFile(file,"    %s",image_info->filename);
+        handler=SetWarningHandler((WarningHandler) NULL);
+        tile=ReadImage(image_info,&image->exception);
+        (void) SetWarningHandler(handler);
+        if (tile == (Image *) NULL)
+          {
+            (void) FormatLocaleFile(file,"\n");
+            continue;
+          }
+        (void) FormatLocaleFile(file," %.20gx%.20g %s\n",(double)
+          tile->magick_columns,(double) tile->magick_rows,tile->magick);
+        (void) SignatureImage(tile);
+        ResetImagePropertyIterator(tile);
+        property=GetNextImageProperty(tile);
+        while (property != (const char *) NULL)
+        {
+          (void) FormatLocaleFile(file,"  %s:\n",property);
+          value=GetImageProperty(tile,property);
+          if (value != (const char *) NULL)
+            (void) FormatLocaleFile(file,"%s\n",value);
+          property=GetNextImageProperty(tile);
+        }
+        tile=DestroyImage(tile);
+      }
+      image_info=DestroyImageInfo(image_info);
+    }
+  (void) GetImageProperty(image,"exif:*");
+  ResetImagePropertyIterator(image);
+  property=GetNextImageProperty(image);
+  if (property != (const char *) NULL)
+    {
+      /*
+        Display image properties.
+      */
+      (void) FormatLocaleFile(file,"  Properties:\n");
+      while (property != (const char *) NULL)
+      {
+        (void) FormatLocaleFile(file,"    %s: ",property);
+        value=GetImageProperty(image,property);
+        if (value != (const char *) NULL)
+          (void) FormatLocaleFile(file,"%s\n",value);
+        property=GetNextImageProperty(image);
+      }
+    }
+  (void) FormatLocaleString(key,MaxTextExtent,"8BIM:1999,2998:#1");
+  value=GetImageProperty(image,key);
+  if (value != (const char *) NULL)
+    {
+      /*
+        Display clipping path.
+      */
+      (void) FormatLocaleFile(file,"  Clipping path: ");
+      if (strlen(value) > 80)
+        (void) fputc('\n',file);
+      (void) FormatLocaleFile(file,"%s\n",value);
+    }
+  ResetImageProfileIterator(image);
+  name=GetNextImageProfile(image);
+  if (name != (char *) NULL)
+    {
+      const StringInfo
+        *profile;
+
+      /*
+        Identify image profiles.
+      */
+      (void) FormatLocaleFile(file,"  Profiles:\n");
+      while (name != (char *) NULL)
+      {
+        profile=GetImageProfile(image,name);
+        if (profile == (StringInfo *) NULL)
+          continue;
+        (void) FormatLocaleFile(file,"    Profile-%s: %.20g bytes\n",name,
+          (double) GetStringInfoLength(profile));
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+        if ((LocaleCompare(name,"icc") == 0) ||
+            (LocaleCompare(name,"icm") == 0))
+          {
+            cmsHPROFILE
+              icc_profile;
+
+            icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile),
+              (cmsUInt32Number) GetStringInfoLength(profile));
+            if (icc_profile != (cmsHPROFILE *) NULL)
+              {
+#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000)
+                const char
+                  *name;
+
+                name=cmsTakeProductName(icc_profile);
+                if (name != (const char *) NULL)
+                  (void) FormatLocaleFile(file,"      %s\n",name);
+#else
+                char
+                  info[MaxTextExtent];
+
+                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription,
+                  "en","US",info,MaxTextExtent);
+                (void) FormatLocaleFile(file,"      Description: %s\n",info);
+                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoManufacturer,
+                  "en","US",info,MaxTextExtent);
+                (void) FormatLocaleFile(file,"      Manufacturer: %s\n",info);
+                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoModel,"en",
+                  "US",info,MaxTextExtent);
+                (void) FormatLocaleFile(file,"      Model: %s\n",info);
+                (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoCopyright,
+                  "en","US",info,MaxTextExtent);
+                (void) FormatLocaleFile(file,"      Copyright: %s\n",info);
+#endif
+                (void) cmsCloseProfile(icc_profile);
+              }
+          }
+#endif
+        if (LocaleCompare(name,"iptc") == 0)
+          {
+            char
+              *attribute,
+              **attribute_list;
+
+            const char
+              *tag;
+
+            long
+              dataset,
+              record,
+              sentinel;
+
+            register ssize_t
+              j;
+
+            size_t
+              length,
+              profile_length;
+
+            profile_length=GetStringInfoLength(profile);
+            for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length)
+            {
+              length=1;
+              sentinel=GetStringInfoDatum(profile)[i++];
+              if (sentinel != 0x1c)
+                continue;
+              dataset=GetStringInfoDatum(profile)[i++];
+              record=GetStringInfoDatum(profile)[i++];
+              switch (record)
+              {
+                case 5: tag="Image Name"; break;
+                case 7: tag="Edit Status"; break;
+                case 10: tag="Priority"; break;
+                case 15: tag="Category"; break;
+                case 20: tag="Supplemental Category"; break;
+                case 22: tag="Fixture Identifier"; break;
+                case 25: tag="Keyword"; break;
+                case 30: tag="Release Date"; break;
+                case 35: tag="Release Time"; break;
+                case 40: tag="Special Instructions"; break;
+                case 45: tag="Reference Service"; break;
+                case 47: tag="Reference Date"; break;
+                case 50: tag="Reference Number"; break;
+                case 55: tag="Created Date"; break;
+                case 60: tag="Created Time"; break;
+                case 65: tag="Originating Program"; break;
+                case 70: tag="Program Version"; break;
+                case 75: tag="Object Cycle"; break;
+                case 80: tag="Byline"; break;
+                case 85: tag="Byline Title"; break;
+                case 90: tag="City"; break;
+                case 95: tag="Province State"; break;
+                case 100: tag="Country Code"; break;
+                case 101: tag="Country"; break;
+                case 103: tag="Original Transmission Reference"; break;
+                case 105: tag="Headline"; break;
+                case 110: tag="Credit"; break;
+                case 115: tag="Src"; break;
+                case 116: tag="Copyright String"; break;
+                case 120: tag="Caption"; break;
+                case 121: tag="Local Caption"; break;
+                case 122: tag="Caption Writer"; break;
+                case 200: tag="Custom Field 1"; break;
+                case 201: tag="Custom Field 2"; break;
+                case 202: tag="Custom Field 3"; break;
+                case 203: tag="Custom Field 4"; break;
+                case 204: tag="Custom Field 5"; break;
+                case 205: tag="Custom Field 6"; break;
+                case 206: tag="Custom Field 7"; break;
+                case 207: tag="Custom Field 8"; break;
+                case 208: tag="Custom Field 9"; break;
+                case 209: tag="Custom Field 10"; break;
+                case 210: tag="Custom Field 11"; break;
+                case 211: tag="Custom Field 12"; break;
+                case 212: tag="Custom Field 13"; break;
+                case 213: tag="Custom Field 14"; break;
+                case 214: tag="Custom Field 15"; break;
+                case 215: tag="Custom Field 16"; break;
+                case 216: tag="Custom Field 17"; break;
+                case 217: tag="Custom Field 18"; break;
+                case 218: tag="Custom Field 19"; break;
+                case 219: tag="Custom Field 20"; break;
+                default: tag="unknown"; break;
+              }
+              (void) FormatLocaleFile(file,"      %s[%.20g,%.20g]: ",tag,
+                (double) dataset,(double) record);
+              length=(size_t) (GetStringInfoDatum(profile)[i++] << 8);
+              length|=GetStringInfoDatum(profile)[i++];
+              attribute=(char *) NULL;
+              if (~length >= (MaxTextExtent-1))
+                attribute=(char *) AcquireQuantumMemory(length+
+                  MaxTextExtent,sizeof(*attribute));
+              if (attribute != (char *) NULL)
+                {
+                  (void) CopyMagickString(attribute,(char *)
+                    GetStringInfoDatum(profile)+i,length+1);
+                  attribute_list=StringToList(attribute);
+                  if (attribute_list != (char **) NULL)
+                    {
+                      for (j=0; attribute_list[j] != (char *) NULL; j++)
+                      {
+                        (void) fputs(attribute_list[j],file);
+                        (void) fputs("\n",file);
+                        attribute_list[j]=(char *) RelinquishMagickMemory(
+                          attribute_list[j]);
+                      }
+                      attribute_list=(char **) RelinquishMagickMemory(
+                        attribute_list);
+                    }
+                  attribute=DestroyString(attribute);
+                }
+            }
+          }
+        if (image->debug != MagickFalse)
+          PrintStringInfo(file,name,profile);
+        name=GetNextImageProfile(image);
+      }
+    }
+  ResetImageArtifactIterator(image);
+  artifact=GetNextImageArtifact(image);
+  if (artifact != (const char *) NULL)
+    {
+      /*
+        Display image artifacts.
+      */
+      (void) FormatLocaleFile(file,"  Artifacts:\n");
+      while (artifact != (const char *) NULL)
+      {
+        (void) FormatLocaleFile(file,"    %s: ",artifact);
+        value=GetImageArtifact(image,artifact);
+        if (value != (const char *) NULL)
+          (void) FormatLocaleFile(file,"%s\n",value);
+        artifact=GetNextImageArtifact(image);
+      }
+    }
+  ResetImageRegistryIterator();
+  registry=GetNextImageRegistry();
+  if (registry != (const char *) NULL)
+    {
+      /*
+        Display image registry.
+      */
+      (void) FormatLocaleFile(file,"  Registry:\n");
+      while (registry != (const char *) NULL)
+      {
+        (void) FormatLocaleFile(file,"    %s: ",registry);
+        value=(const char *) GetImageRegistry(StringRegistryType,registry,
+          &image->exception);
+        if (value != (const char *) NULL)
+          (void) FormatLocaleFile(file,"%s\n",value);
+        registry=GetNextImageRegistry();
+      }
+    }
+  (void) FormatLocaleFile(file,"  Tainted: %s\n",CommandOptionToMnemonic(
+    MagickBooleanOptions,(ssize_t) image->taint));
+  (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format);
+  (void) FormatLocaleFile(file,"  Filesize: %sB\n",format);
+  (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,
+     MagickFalse,format);
+  (void) FormatLocaleFile(file,"  Number pixels: %s\n",format);
+  (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/
+    elapsed_time+0.5),MagickFalse,format);
+  (void) FormatLocaleFile(file,"  Pixels per second: %s\n",format);
+  (void) FormatLocaleFile(file,"  User time: %0.3fu\n",user_time);
+  (void) FormatLocaleFile(file,"  Elapsed time: %lu:%02lu.%03lu\n",
+    (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(
+    elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor(
+    elapsed_time))));
+  (void) FormatLocaleFile(file,"  Version: %s\n",GetMagickVersion((size_t *)
+    NULL));
+  (void) fflush(file);
+  return(ferror(file) != 0 ? MagickFalse : MagickTrue);
+}
diff --git a/MagickCore/identify.h b/MagickCore/identify.h
new file mode 100644
index 0000000..28d274d
--- /dev/null
+++ b/MagickCore/identify.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image identify method.
+*/
+#ifndef _MAGICKCORE_IDENTIFY_H
+#define _MAGICKCORE_IDENTIFY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  IdentifyImage(Image *,FILE *,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/image-private.h b/MagickCore/image-private.h
new file mode 100644
index 0000000..49cbfb6
--- /dev/null
+++ b/MagickCore/image-private.h
@@ -0,0 +1,85 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image private methods.
+*/
+#ifndef _MAGICKCORE_IMAGE_PRIVATE_H
+#define _MAGICKCORE_IMAGE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define Magick2PI    6.28318530717958647692528676655900576839433879875020L
+#define MagickPI2    1.57079632679489661923132169163975144209858469968755L
+#define MagickSQ1_2  0.70710678118654752440084436210484903928483593768847L
+#define MagickSQ2    1.41421356237309504880168872420969807856967187537695L
+#define MagickSQ2PI  2.50662827463100024161235523934010416269302368164062L
+#define UndefinedTicksPerSecond  100L
+#define UndefinedCompressionQuality  0UL
+
+extern MagickExport const char
+  BackgroundColor[],
+  BorderColor[],
+  DefaultTileFrame[],
+  DefaultTileGeometry[],
+  DefaultTileLabel[],
+  ForegroundColor[],
+  MatteColor[],
+  LoadImageTag[],
+  LoadImagesTag[],
+  PSDensityGeometry[],
+  PSPageGeometry[],
+  SaveImageTag[],
+  SaveImagesTag[];
+
+extern MagickExport const double
+  DefaultResolution;
+
+static inline double DegreesToRadians(const double degrees)
+{
+  return((double) (MagickPI*degrees/180.0));
+}
+
+static inline MagickRealType RadiansToDegrees(const MagickRealType radians)
+{
+  return((MagickRealType) (180.0*radians/MagickPI));
+}
+
+static inline unsigned char ScaleColor5to8(const unsigned int color)
+{
+  return((unsigned char) (((color) << 3) | ((color) >> 2)));
+}
+
+static inline unsigned char ScaleColor6to8(const unsigned int color)
+{
+  return((unsigned char) (((color) << 2) | ((color) >> 4)));
+}
+
+static inline unsigned int ScaleColor8to5(const unsigned char color)
+{
+  return((unsigned int) (((color) & ~0x07) >> 3));
+}
+
+static inline unsigned int ScaleColor8to6(const unsigned char color)
+{
+  return((unsigned int) (((color) & ~0x03) >> 2));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/image-view.c b/MagickCore/image-view.c
new file mode 100644
index 0000000..4d33f66
--- /dev/null
+++ b/MagickCore/image-view.c
@@ -0,0 +1,1229 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                     IIIII  M   M   AAA    GGGG  EEEEE                       %
+%                       I    MM MM  A   A  G      E                           %
+%                       I    M M M  AAAAA  G  GG  EEE                         %
+%                       I    M   M  A   A  G   G  E                           %
+%                     IIIII  M   M  A   A   GGGG  EEEEE                       %
+%                                                                             %
+%                         V   V  IIIII  EEEEE  W   W                          %
+%                         V   V    I    E      W   W                          %
+%                         V   V    I    EEE    W W W                          %
+%                          V V     I    E      WW WW                          %
+%                           V    IIIII  EEEEE  W   W                          %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Image View Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                March 2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/MagickCore.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/thread-private.h"
+
+/*
+  Typedef declarations.
+*/
+struct _ImageView
+{
+  char
+    *description;
+
+  RectangleInfo
+    extent;
+
+  Image
+    *image;
+
+  CacheView
+    *view;
+
+  size_t
+    number_threads;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    debug;
+
+  size_t
+    signature;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e V i e w                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageView() makes a copy of the specified image view.
+%
+%  The format of the CloneImageView method is:
+%
+%      ImageView *CloneImageView(const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport ImageView *CloneImageView(const ImageView *image_view)
+{
+  ImageView
+    *clone_view;
+
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  clone_view=(ImageView *) AcquireMagickMemory(sizeof(*clone_view));
+  if (clone_view == (ImageView *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(clone_view,0,sizeof(*clone_view));
+  clone_view->description=ConstantString(image_view->description);
+  clone_view->extent=image_view->extent;
+  clone_view->view=CloneCacheView(image_view->view);
+  clone_view->number_threads=image_view->number_threads;
+  clone_view->exception=AcquireExceptionInfo();
+  InheritException(clone_view->exception,image_view->exception);
+  clone_view->debug=image_view->debug;
+  clone_view->signature=MagickSignature;
+  return(clone_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e V i e w                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageView() deallocates memory associated with a image view.
+%
+%  The format of the DestroyImageView method is:
+%
+%      ImageView *DestroyImageView(ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport ImageView *DestroyImageView(ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  if (image_view->description != (char *) NULL)
+    image_view->description=DestroyString(image_view->description);
+  image_view->view=DestroyCacheView(image_view->view);
+  image_view->exception=DestroyExceptionInfo(image_view->exception);
+  image_view->signature=(~MagickSignature);
+  image_view=(ImageView *) RelinquishMagickMemory(image_view);
+  return(image_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D u p l e x T r a n s f e r I m a g e V i e w I t e r a t o r             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DuplexTransferImageViewIterator() iterates over three image views in
+%  parallel and calls your transfer method for each scanline of the view.  The
+%  source and duplex pixel extent is not confined to the image canvas-- that is
+%  you can include negative offsets or widths or heights that exceed the image
+%  dimension.  However, the destination image view is confined to the image
+%  canvas-- that is no negative offsets or widths or heights that exceed the
+%  image dimension are permitted.
+%
+%  The callback signature is:
+%
+%      MagickBooleanType DuplexTransferImageViewMethod(const ImageView *source,
+%        const ImageView *duplex,ImageView *destination,const ssize_t y,
+%        const int thread_id,void *context)
+%
+%  Use this pragma if the view is not single threaded:
+%
+%    #pragma omp critical
+%
+%  to define a section of code in your callback transfer method that must be
+%  executed by a single thread at a time.
+%
+%  The format of the DuplexTransferImageViewIterator method is:
+%
+%      MagickBooleanType DuplexTransferImageViewIterator(ImageView *source,
+%        ImageView *duplex,ImageView *destination,
+%        DuplexTransferImageViewMethod transfer,void *context)
+%
+%  A description of each parameter follows:
+%
+%    o source: the source image view.
+%
+%    o duplex: the duplex image view.
+%
+%    o destination: the destination image view.
+%
+%    o transfer: the transfer callback method.
+%
+%    o context: the user defined context.
+%
+*/
+MagickExport MagickBooleanType DuplexTransferImageViewIterator(
+  ImageView *source,ImageView *duplex,ImageView *destination,
+  DuplexTransferImageViewMethod transfer,void *context)
+{
+  ExceptionInfo
+    *exception;
+
+  Image
+    *destination_image,
+    *source_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(source != (ImageView *) NULL);
+  assert(source->signature == MagickSignature);
+  if (transfer == (DuplexTransferImageViewMethod) NULL)
+    return(MagickFalse);
+  source_image=source->image;
+  destination_image=destination->image;
+  if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  progress=0;
+  exception=destination->exception;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
+#endif
+  for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict duplex_pixels,
+      *restrict pixels;
+
+    register Quantum
+      *restrict destination_pixels;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
+      source->extent.width,1,source->exception);
+    if (pixels == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    duplex_pixels=GetCacheViewVirtualPixels(duplex->view,duplex->extent.x,y,
+      duplex->extent.width,1,duplex->exception);
+    if (duplex_pixels == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    destination_pixels=GetCacheViewAuthenticPixels(destination->view,
+      destination->extent.x,y,destination->extent.width,1,exception);
+    if (destination_pixels == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    if (transfer(source,duplex,destination,y,id,context) == MagickFalse)
+      status=MagickFalse;
+    sync=SyncCacheViewAuthenticPixels(destination->view,exception);
+    if (sync == MagickFalse)
+      {
+        InheritException(destination->exception,GetCacheViewException(
+          source->view));
+        status=MagickFalse;
+      }
+    if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_DuplexTransferImageViewIterator)
+#endif
+        proceed=SetImageProgress(source_image,source->description,progress++,
+          source->extent.height);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w A u t h e n t i c M e t a c o n t e n t %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewAuthenticMetacontent() returns the image view authentic
+%  meta-content.
+%
+%  The format of the GetImageViewAuthenticPixels method is:
+%
+%      void *GetImageViewAuthenticMetacontent(
+%        const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport void *GetImageViewAuthenticMetacontent(
+  const ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  return(GetCacheViewAuthenticMetacontent(image_view->view));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w A u t h e n t i c P i x e l s                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewAuthenticPixels() returns the image view authentic pixels.
+%
+%  The format of the GetImageViewAuthenticPixels method is:
+%
+%      Quantum *GetImageViewAuthenticPixels(const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport Quantum *GetImageViewAuthenticPixels(
+  const ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  return(GetCacheViewAuthenticPixelQueue(image_view->view));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w E x c e p t i o n                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewException() returns the severity, reason, and description of any
+%  error that occurs when utilizing a image view.
+%
+%  The format of the GetImageViewException method is:
+%
+%      char *GetImageViewException(const PixelImage *image_view,
+%        ExceptionType *severity)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the pixel image_view.
+%
+%    o severity: the severity of the error is returned here.
+%
+*/
+MagickExport char *GetImageViewException(const ImageView *image_view,
+  ExceptionType *severity)
+{
+  char
+    *description;
+
+  assert(image_view != (const ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  assert(severity != (ExceptionType *) NULL);
+  *severity=image_view->exception->severity;
+  description=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
+    sizeof(*description));
+  if (description == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  *description='\0';
+  if (image_view->exception->reason != (char *) NULL)
+    (void) CopyMagickString(description,GetLocaleExceptionMessage(
+      image_view->exception->severity,image_view->exception->reason),
+        MaxTextExtent);
+  if (image_view->exception->description != (char *) NULL)
+    {
+      (void) ConcatenateMagickString(description," (",MaxTextExtent);
+      (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
+        image_view->exception->severity,image_view->exception->description),
+        MaxTextExtent);
+      (void) ConcatenateMagickString(description,")",MaxTextExtent);
+    }
+  return(description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w E x t e n t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewExtent() returns the image view extent.
+%
+%  The format of the GetImageViewExtent method is:
+%
+%      RectangleInfo GetImageViewExtent(const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport RectangleInfo GetImageViewExtent(const ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  return(image_view->extent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewImage() returns the image associated with the image view.
+%
+%  The format of the GetImageViewImage method is:
+%
+%      MagickCore *GetImageViewImage(const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport Image *GetImageViewImage(const ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  return(image_view->image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w I t e r a t o r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewIterator() iterates over the image view in parallel and calls
+%  your get method for each scanline of the view.  The pixel extent is
+%  not confined to the image canvas-- that is you can include negative offsets
+%  or widths or heights that exceed the image dimension.  Any updates to
+%  the pixels in your callback are ignored.
+%
+%  The callback signature is:
+%
+%      MagickBooleanType GetImageViewMethod(const ImageView *source,
+%        const ssize_t y,const int thread_id,void *context)
+%
+%  Use this pragma if the view is not single threaded:
+%
+%    #pragma omp critical
+%
+%  to define a section of code in your callback get method that must be
+%  executed by a single thread at a time.
+%
+%  The format of the GetImageViewIterator method is:
+%
+%      MagickBooleanType GetImageViewIterator(ImageView *source,
+%        GetImageViewMethod get,void *context)
+%
+%  A description of each parameter follows:
+%
+%    o source: the source image view.
+%
+%    o get: the get callback method.
+%
+%    o context: the user defined context.
+%
+*/
+MagickExport MagickBooleanType GetImageViewIterator(ImageView *source,
+  GetImageViewMethod get,void *context)
+{
+  Image
+    *source_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(source != (ImageView *) NULL);
+  assert(source->signature == MagickSignature);
+  if (get == (GetImageViewMethod) NULL)
+    return(MagickFalse);
+  source_image=source->image;
+  status=MagickTrue;
+  progress=0;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
+#endif
+  for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register const Quantum
+      *pixels;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
+      source->extent.width,1,source->exception);
+    if (pixels == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    if (get(source,y,id,context) == MagickFalse)
+      status=MagickFalse;
+    if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetImageViewIterator)
+#endif
+        proceed=SetImageProgress(source_image,source->description,progress++,
+          source->extent.height);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w V i r t u a l M e t a c o n t e n t     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewVirtualMetacontent() returns the image view virtual
+%  meta-content.
+%
+%  The format of the GetImageViewVirtualMetacontent method is:
+%
+%      const void *GetImageViewVirtualMetacontent(
+%        const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport const void *GetImageViewVirtualMetacontent(
+  const ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  return(GetCacheViewVirtualMetacontent(image_view->view));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i e w V i r t u a l P i x e l s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageViewVirtualPixels() returns the image view virtual pixels.
+%
+%  The format of the GetImageViewVirtualPixels method is:
+%
+%      const Quantum *GetImageViewVirtualPixels(const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport const Quantum *GetImageViewVirtualPixels(
+  const ImageView *image_view)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  return(GetCacheViewVirtualPixelQueue(image_view->view));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s I m a g e V i e w                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImageView() returns MagickTrue if the the parameter is verified as a image
+%  view object.
+%
+%  The format of the IsImageView method is:
+%
+%      MagickBooleanType IsImageView(const ImageView *image_view)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+*/
+MagickExport MagickBooleanType IsImageView(const ImageView *image_view)
+{
+  if (image_view == (const ImageView *) NULL)
+    return(MagickFalse);
+  if (image_view->signature != MagickSignature)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w I m a g e V i e w                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewImageView() returns a image view required for all other methods in the
+%  Image View API.
+%
+%  The format of the NewImageView method is:
+%
+%      ImageView *NewImageView(MagickCore *wand)
+%
+%  A description of each parameter follows:
+%
+%    o wand: the wand.
+%
+*/
+MagickExport ImageView *NewImageView(Image *image)
+{
+  ImageView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
+  if (image_view == (ImageView *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
+  image_view->description=ConstantString("ImageView");
+  image_view->image=image;
+  image_view->view=AcquireCacheView(image_view->image);
+  image_view->extent.width=image->columns;
+  image_view->extent.height=image->rows;
+  image_view->extent.x=0;
+  image_view->extent.y=0;
+  image_view->number_threads=GetOpenMPMaximumThreads();
+  image_view->exception=AcquireExceptionInfo();
+  image_view->debug=IsEventLogging();
+  image_view->signature=MagickSignature;
+  return(image_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w I m a g e V i e w R e g i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewImageViewRegion() returns a image view required for all other methods
+%  in the Image View API.
+%
+%  The format of the NewImageViewRegion method is:
+%
+%      ImageView *NewImageViewRegion(MagickCore *wand,const ssize_t x,
+%        const ssize_t y,const size_t width,const size_t height)
+%
+%  A description of each parameter follows:
+%
+%    o wand: the magick wand.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a extent of
+%      pixel_wands view.
+%
+*/
+MagickExport ImageView *NewImageViewRegion(Image *image,const ssize_t x,
+  const ssize_t y,const size_t width,const size_t height)
+{
+  ImageView
+    *image_view;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  image_view=(ImageView *) AcquireMagickMemory(sizeof(*image_view));
+  if (image_view == (ImageView *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(image_view,0,sizeof(*image_view));
+  image_view->description=ConstantString("ImageView");
+  image_view->view=AcquireCacheView(image_view->image);
+  image_view->image=image;
+  image_view->extent.width=width;
+  image_view->extent.height=height;
+  image_view->extent.x=x;
+  image_view->extent.y=y;
+  image_view->number_threads=GetOpenMPMaximumThreads();
+  image_view->exception=AcquireExceptionInfo();
+  image_view->debug=IsEventLogging();
+  image_view->signature=MagickSignature;
+  return(image_view);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e V i e w D e s c r i p t i o n                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageViewDescription() associates a description with an image view.
+%
+%  The format of the SetImageViewDescription method is:
+%
+%      void SetImageViewDescription(ImageView *image_view,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+%    o description: the image view description.
+%
+*/
+MagickExport void SetImageViewDescription(ImageView *image_view,
+  const char *description)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  image_view->description=ConstantString(description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e V i e w I t e r a t o r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageViewIterator() iterates over the image view in parallel and calls
+%  your set method for each scanline of the view.  The pixel extent is
+%  confined to the image canvas-- that is no negative offsets or widths or
+%  heights that exceed the image dimension.  The pixels are initiallly
+%  undefined and any settings you make in the callback method are automagically
+%  synced back to your image.
+%
+%  The callback signature is:
+%
+%      MagickBooleanType SetImageViewMethod(ImageView *destination,
+%        const ssize_t y,const int thread_id,void *context)
+%
+%  Use this pragma if the view is not single threaded:
+%
+%    #pragma omp critical
+%
+%  to define a section of code in your callback set method that must be
+%  executed by a single thread at a time.
+%
+%  The format of the SetImageViewIterator method is:
+%
+%      MagickBooleanType SetImageViewIterator(ImageView *destination,
+%        SetImageViewMethod set,void *context)
+%
+%  A description of each parameter follows:
+%
+%    o destination: the image view.
+%
+%    o set: the set callback method.
+%
+%    o context: the user defined context.
+%
+*/
+MagickExport MagickBooleanType SetImageViewIterator(ImageView *destination,
+  SetImageViewMethod set,void *context)
+{
+  ExceptionInfo
+    *exception;
+
+  Image
+    *destination_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(destination != (ImageView *) NULL);
+  assert(destination->signature == MagickSignature);
+  if (set == (SetImageViewMethod) NULL)
+    return(MagickFalse);
+  destination_image=destination->image;
+  if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  progress=0;
+  exception=destination->exception;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(destination->number_threads)
+#endif
+  for (y=destination->extent.y; y < (ssize_t) destination->extent.height; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    MagickBooleanType
+      sync;
+
+    register Quantum
+      *restrict pixels;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewAuthenticPixels(destination->view,destination->extent.x,
+      y,destination->extent.width,1,exception);
+    if (pixels == (Quantum *) NULL)
+      {
+        InheritException(destination->exception,GetCacheViewException(
+          destination->view));
+        status=MagickFalse;
+        continue;
+      }
+    if (set(destination,y,id,context) == MagickFalse)
+      status=MagickFalse;
+    sync=SyncCacheViewAuthenticPixels(destination->view,exception);
+    if (sync == MagickFalse)
+      {
+        InheritException(destination->exception,GetCacheViewException(
+          destination->view));
+        status=MagickFalse;
+      }
+    if (destination_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_SetImageViewIterator)
+#endif
+        proceed=SetImageProgress(destination_image,destination->description,
+          progress++,destination->extent.height);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e V i e w T h r e a d s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageViewThreads() sets the number of threads in a thread team.
+%
+%  The format of the SetImageViewDescription method is:
+%
+%      void SetImageViewThreads(ImageView *image_view,
+%        const size_t number_threads)
+%
+%  A description of each parameter follows:
+%
+%    o image_view: the image view.
+%
+%    o number_threads: the number of threads in a thread team.
+%
+*/
+MagickExport void SetImageViewThreads(ImageView *image_view,
+  const size_t number_threads)
+{
+  assert(image_view != (ImageView *) NULL);
+  assert(image_view->signature == MagickSignature);
+  image_view->number_threads=number_threads;
+  if (number_threads > GetOpenMPMaximumThreads())
+    image_view->number_threads=GetOpenMPMaximumThreads();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s f e r I m a g e V i e w I t e r a t o r                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransferImageViewIterator() iterates over two image views in parallel and
+%  calls your transfer method for each scanline of the view.  The source pixel
+%  extent is not confined to the image canvas-- that is you can include
+%  negative offsets or widths or heights that exceed the image dimension.
+%  However, the destination image view is confined to the image canvas-- that
+%  is no negative offsets or widths or heights that exceed the image dimension
+%  are permitted.
+%
+%  The callback signature is:
+%
+%      MagickBooleanType TransferImageViewMethod(const ImageView *source,
+%        ImageView *destination,const ssize_t y,const int thread_id,
+%        void *context)
+%
+%  Use this pragma if the view is not single threaded:
+%
+%    #pragma omp critical
+%
+%  to define a section of code in your callback transfer method that must be
+%  executed by a single thread at a time.
+%
+%  The format of the TransferImageViewIterator method is:
+%
+%      MagickBooleanType TransferImageViewIterator(ImageView *source,
+%        ImageView *destination,TransferImageViewMethod transfer,void *context)
+%
+%  A description of each parameter follows:
+%
+%    o source: the source image view.
+%
+%    o destination: the destination image view.
+%
+%    o transfer: the transfer callback method.
+%
+%    o context: the user defined context.
+%
+*/
+MagickExport MagickBooleanType TransferImageViewIterator(ImageView *source,
+  ImageView *destination,TransferImageViewMethod transfer,void *context)
+{
+  ExceptionInfo
+    *exception;
+
+  Image
+    *destination_image,
+    *source_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(source != (ImageView *) NULL);
+  assert(source->signature == MagickSignature);
+  if (transfer == (TransferImageViewMethod) NULL)
+    return(MagickFalse);
+  source_image=source->image;
+  destination_image=destination->image;
+  if (SetImageStorageClass(destination_image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  progress=0;
+  exception=destination->exception;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
+#endif
+  for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict pixels;
+
+    register Quantum
+      *restrict destination_pixels;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewVirtualPixels(source->view,source->extent.x,y,
+      source->extent.width,1,source->exception);
+    if (pixels == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    destination_pixels=GetCacheViewAuthenticPixels(destination->view,
+      destination->extent.x,y,destination->extent.width,1,exception);
+    if (destination_pixels == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    if (transfer(source,destination,y,id,context) == MagickFalse)
+      status=MagickFalse;
+    sync=SyncCacheViewAuthenticPixels(destination->view,exception);
+    if (sync == MagickFalse)
+      {
+        InheritException(destination->exception,GetCacheViewException(
+          source->view));
+        status=MagickFalse;
+      }
+    if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransferImageViewIterator)
+#endif
+        proceed=SetImageProgress(source_image,source->description,progress++,
+          source->extent.height);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   U p d a t e I m a g e V i e w I t e r a t o r                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UpdateImageViewIterator() iterates over the image view in parallel and calls
+%  your update method for each scanline of the view.  The pixel extent is
+%  confined to the image canvas-- that is no negative offsets or widths or
+%  heights that exceed the image dimension are permitted.  Updates to pixels
+%  in your callback are automagically synced back to the image.
+%
+%  The callback signature is:
+%
+%      MagickBooleanType UpdateImageViewMethod(ImageView *source,
+%        const ssize_t y,const int thread_id,void *context)
+%
+%  Use this pragma if the view is not single threaded:
+%
+%    #pragma omp critical
+%
+%  to define a section of code in your callback update method that must be
+%  executed by a single thread at a time.
+%
+%  The format of the UpdateImageViewIterator method is:
+%
+%      MagickBooleanType UpdateImageViewIterator(ImageView *source,
+%        UpdateImageViewMethod update,void *context)
+%
+%  A description of each parameter follows:
+%
+%    o source: the source image view.
+%
+%    o update: the update callback method.
+%
+%    o context: the user defined context.
+%
+*/
+MagickExport MagickBooleanType UpdateImageViewIterator(ImageView *source,
+  UpdateImageViewMethod update,void *context)
+{
+  ExceptionInfo
+    *exception;
+
+  Image
+    *source_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(source != (ImageView *) NULL);
+  assert(source->signature == MagickSignature);
+  if (update == (UpdateImageViewMethod) NULL)
+    return(MagickFalse);
+  source_image=source->image;
+  if (SetImageStorageClass(source_image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  progress=0;
+  exception=source->exception;
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,1) shared(progress,status) num_threads(source->number_threads)
+#endif
+  for (y=source->extent.y; y < (ssize_t) source->extent.height; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register Quantum
+      *restrict pixels;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewAuthenticPixels(source->view,source->extent.x,y,
+      source->extent.width,1,exception);
+    if (pixels == (Quantum *) NULL)
+      {
+        InheritException(source->exception,GetCacheViewException(source->view));
+        status=MagickFalse;
+        continue;
+      }
+    if (update(source,y,id,context) == MagickFalse)
+      status=MagickFalse;
+    if (SyncCacheViewAuthenticPixels(source->view,exception) == MagickFalse)
+      {
+        InheritException(source->exception,GetCacheViewException(source->view));
+        status=MagickFalse;
+      }
+    if (source_image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_UpdateImageViewIterator)
+#endif
+        proceed=SetImageProgress(source_image,source->description,progress++,
+          source->extent.height);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  return(status);
+}
diff --git a/MagickCore/image-view.h b/MagickCore/image-view.h
new file mode 100644
index 0000000..351ee87
--- /dev/null
+++ b/MagickCore/image-view.h
@@ -0,0 +1,83 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITTransferNS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image view methods.
+*/
+#ifndef _MAGICKIMAGE_IMAGE_VIEW_H
+#define _MAGICKIMAGE_IMAGE_VIEW_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _ImageView
+  ImageView;
+
+typedef MagickBooleanType
+  (*DuplexTransferImageViewMethod)(const ImageView *,const ImageView *,
+    ImageView *,const ssize_t,const int,void *),
+  (*GetImageViewMethod)(const ImageView *,const ssize_t,const int,void *),
+  (*SetImageViewMethod)(ImageView *,const ssize_t,const int,void *),
+  (*TransferImageViewMethod)(const ImageView *,ImageView *,const ssize_t,
+    const int,void *),
+  (*UpdateImageViewMethod)(ImageView *,const ssize_t,const int,void *);
+
+extern MagickExport char
+  *GetImageViewException(const ImageView *,ExceptionType *);
+
+extern MagickExport const Quantum
+  *GetImageViewVirtualPixels(const ImageView *);
+
+extern MagickExport const void
+  *GetImageViewVirtualMetacontent(const ImageView *);
+
+extern MagickExport Image
+  *GetImageViewImage(const ImageView *);
+
+extern MagickExport ImageView
+  *CloneImageView(const ImageView *),
+  *DestroyImageView(ImageView *),
+  *NewImageView(Image *),
+  *NewImageViewRegion(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t);
+
+extern MagickExport MagickBooleanType
+  DuplexTransferImageViewIterator(ImageView *,ImageView *,ImageView *,
+    DuplexTransferImageViewMethod,void *),
+  GetImageViewIterator(ImageView *,GetImageViewMethod,void *),
+  IsImageView(const ImageView *),
+  SetImageViewIterator(ImageView *,SetImageViewMethod,void *),
+  TransferImageViewIterator(ImageView *,ImageView *,TransferImageViewMethod,
+    void *),
+  UpdateImageViewIterator(ImageView *,UpdateImageViewMethod,void *);
+
+extern MagickExport Quantum
+  *GetImageViewAuthenticPixels(const ImageView *);
+
+extern MagickExport RectangleInfo
+  GetImageViewExtent(const ImageView *);
+
+extern MagickExport void
+  SetImageViewDescription(ImageView *,const char *),
+  SetImageViewThreads(ImageView *,const size_t);
+
+extern MagickExport void
+  *GetImageViewAuthenticMetacontent(const ImageView *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/image.c b/MagickCore/image.c
new file mode 100644
index 0000000..e4913ad
--- /dev/null
+++ b/MagickCore/image.c
@@ -0,0 +1,4481 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                     IIIII  M   M   AAA    GGGG  EEEEE                       %
+%                       I    MM MM  A   A  G      E                           %
+%                       I    M M M  AAAAA  G  GG  EEE                         %
+%                       I    M   M  A   A  G   G  E                           %
+%                     IIIII  M   M  A   A   GGGG  EEEEE                       %
+%                                                                             %
+%                                                                             %
+%                           MagickCore Image Methods                          %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/animate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/compress.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/display.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#include "MagickCore/xwindow-private.h"
+
+/*
+  Constant declaration.
+*/
+const char
+  BackgroundColor[] = "#ffffff",  /* white */
+  BorderColor[] = "#dfdfdf",  /* gray */
+  DefaultTileFrame[] = "15x15+3+3",
+  DefaultTileGeometry[] = "120x120+4+3>",
+  DefaultTileLabel[] = "%f\n%G\n%b",
+  ForegroundColor[] = "#000",  /* black */
+  LoadImageTag[] = "Load/Image",
+  LoadImagesTag[] = "Load/Images",
+  MatteColor[] = "#bdbdbd",  /* gray */
+  PSDensityGeometry[] = "72.0x72.0",
+  PSPageGeometry[] = "612x792",
+  SaveImageTag[] = "Save/Image",
+  SaveImagesTag[] = "Save/Images",
+  TransparentColor[] = "#00000000";  /* transparent black */
+
+const double
+  DefaultResolution = 72.0;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireImage() returns a pointer to an image structure initialized to
+%  default values.
+%
+%  The format of the AcquireImage method is:
+%
+%      Image *AcquireImage(const ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: Many of the image default values are set from this
+%      structure.  For example, filename, compression, depth, background color,
+%      and others.
+%
+*/
+MagickExport Image *AcquireImage(const ImageInfo *image_info)
+{
+  const char
+    *option;
+
+  Image
+    *image;
+
+  MagickStatusType
+    flags;
+
+  /*
+    Allocate image structure.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  image=(Image *) AcquireMagickMemory(sizeof(*image));
+  if (image == (Image *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(image,0,sizeof(*image));
+  /*
+    Initialize Image structure.
+  */
+  (void) CopyMagickString(image->magick,"MIFF",MaxTextExtent);
+  image->storage_class=DirectClass;
+  image->depth=MAGICKCORE_QUANTUM_DEPTH;
+  image->colorspace=RGBColorspace;
+  image->interlace=NoInterlace;
+  image->ticks_per_second=UndefinedTicksPerSecond;
+  image->compose=OverCompositeOp;
+  image->blur=1.0;
+  GetExceptionInfo(&image->exception);
+  (void) QueryColorDatabase(BackgroundColor,&image->background_color,
+    &image->exception);
+  (void) QueryColorDatabase(BorderColor,&image->border_color,&image->exception);
+  (void) QueryColorDatabase(MatteColor,&image->matte_color,&image->exception);
+  (void) QueryColorDatabase(TransparentColor,&image->transparent_color,
+    &image->exception);
+  image->x_resolution=DefaultResolution;
+  image->y_resolution=DefaultResolution;
+  image->units=PixelsPerInchResolution;
+  GetTimerInfo(&image->timer);
+  image->ping=MagickFalse;
+  image->cache=AcquirePixelCache(0);
+  image->component_map=AcquirePixelComponentMap();
+  image->blob=CloneBlobInfo((BlobInfo *) NULL);
+  image->debug=IsEventLogging();
+  image->reference_count=1;
+  image->semaphore=AllocateSemaphoreInfo();
+  image->signature=MagickSignature;
+  if (image_info == (ImageInfo *) NULL)
+    return(image);
+  /*
+    Transfer image info.
+  */
+  SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
+    MagickFalse);
+  (void) CopyMagickString(image->filename,image_info->filename,MaxTextExtent);
+  (void) CopyMagickString(image->magick_filename,image_info->filename,
+    MaxTextExtent);
+  (void) CopyMagickString(image->magick,image_info->magick,MaxTextExtent);
+  if (image_info->size != (char *) NULL)
+    {
+      (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
+      image->columns=image->extract_info.width;
+      image->rows=image->extract_info.height;
+      image->offset=image->extract_info.x;
+      image->extract_info.x=0;
+      image->extract_info.y=0;
+    }
+  if (image_info->extract != (char *) NULL)
+    {
+      RectangleInfo
+        geometry;
+
+      flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
+      if (((flags & XValue) != 0) || ((flags & YValue) != 0))
+        {
+          image->extract_info=geometry;
+          Swap(image->columns,image->extract_info.width);
+          Swap(image->rows,image->extract_info.height);
+        }
+    }
+  image->compression=image_info->compression;
+  image->quality=image_info->quality;
+  image->endian=image_info->endian;
+  image->interlace=image_info->interlace;
+  image->units=image_info->units;
+  if (image_info->density != (char *) NULL)
+    {
+      GeometryInfo
+        geometry_info;
+
+      flags=ParseGeometry(image_info->density,&geometry_info);
+      image->x_resolution=geometry_info.rho;
+      image->y_resolution=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->y_resolution=image->x_resolution;
+    }
+  if (image_info->page != (char *) NULL)
+    {
+      char
+        *geometry;
+
+      image->page=image->extract_info;
+      geometry=GetPageGeometry(image_info->page);
+      (void) ParseAbsoluteGeometry(geometry,&image->page);
+      geometry=DestroyString(geometry);
+    }
+  if (image_info->depth != 0)
+    image->depth=image_info->depth;
+  image->dither=image_info->dither;
+  image->background_color=image_info->background_color;
+  image->border_color=image_info->border_color;
+  image->matte_color=image_info->matte_color;
+  image->transparent_color=image_info->transparent_color;
+  image->ping=image_info->ping;
+  image->progress_monitor=image_info->progress_monitor;
+  image->client_data=image_info->client_data;
+  if (image_info->cache != (void *) NULL)
+    ClonePixelCacheMethods(image->cache,image_info->cache);
+  (void) SetImageVirtualPixelMethod(image,image_info->virtual_pixel_method);
+  (void) SyncImageSettings(image_info,image);
+  option=GetImageOption(image_info,"delay");
+  if (option != (const char *) NULL)
+    {
+      GeometryInfo
+        geometry_info;
+
+      flags=ParseGeometry(option,&geometry_info);
+      if ((flags & GreaterValue) != 0)
+        {
+          if (image->delay > (size_t) floor(geometry_info.rho+0.5))
+            image->delay=(size_t) floor(geometry_info.rho+0.5);
+        }
+      else
+        if ((flags & LessValue) != 0)
+          {
+            if (image->delay < (size_t) floor(geometry_info.rho+0.5))
+              image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
+          }
+        else
+          image->delay=(size_t) floor(geometry_info.rho+0.5);
+      if ((flags & SigmaValue) != 0)
+        image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
+    }
+  option=GetImageOption(image_info,"dispose");
+  if (option != (const char *) NULL)
+    image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
+      MagickFalse,option);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e I m a g e I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireImageInfo() allocates the ImageInfo structure.
+%
+%  The format of the AcquireImageInfo method is:
+%
+%      ImageInfo *AcquireImageInfo(void)
+%
+*/
+MagickExport ImageInfo *AcquireImageInfo(void)
+{
+  ImageInfo
+    *image_info;
+
+  image_info=(ImageInfo *) AcquireMagickMemory(sizeof(*image_info));
+  if (image_info == (ImageInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetImageInfo(image_info);
+  return(image_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e N e x t I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireNextImage() initializes the next image in a sequence to
+%  default values.  The next member of image points to the newly allocated
+%  image.  If there is a memory shortage, next is assigned NULL.
+%
+%  The format of the AcquireNextImage method is:
+%
+%      void AcquireNextImage(const ImageInfo *image_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: Many of the image default values are set from this
+%      structure.  For example, filename, compression, depth, background color,
+%      and others.
+%
+%    o image: the image.
+%
+*/
+MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image)
+{
+  /*
+    Allocate image structure.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  image->next=AcquireImage(image_info);
+  if (GetNextImageInList(image) == (Image *) NULL)
+    return;
+  (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
+    MaxTextExtent);
+  if (image_info != (ImageInfo *) NULL)
+    (void) CopyMagickString(GetNextImageInList(image)->filename,
+      image_info->filename,MaxTextExtent);
+  DestroyBlob(GetNextImageInList(image));
+  image->next->blob=ReferenceBlob(image->blob);
+  image->next->endian=image->endian;
+  image->next->scene=image->scene+1;
+  image->next->previous=image;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A p p e n d I m a g e s                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AppendImages() takes all images from the current image pointer to the end
+%  of the image list and appends them to each other top-to-bottom if the
+%  stack parameter is true, otherwise left-to-right.
+%
+%  The current gravity setting now effects how the image is justified in the
+%  final image.
+%
+%  The format of the AppendImages method is:
+%
+%      Image *AppendImages(const Image *images,const MagickBooleanType stack,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image sequence.
+%
+%    o stack: A value other than 0 stacks the images top-to-bottom.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *AppendImages(const Image *images,
+  const MagickBooleanType stack,ExceptionInfo *exception)
+{
+#define AppendImageTag  "Append/Image"
+
+  CacheView
+    *append_view,
+    *image_view;
+
+  const Image
+    *image;
+
+  Image
+    *append_image;
+
+  MagickBooleanType
+    matte,
+    proceed,
+    status;
+
+  MagickOffsetType
+    n;
+
+  RectangleInfo
+    geometry;
+
+  register const Image
+    *next;
+
+  size_t
+    height,
+    number_images,
+    width;
+
+  ssize_t
+    x_offset,
+    y,
+    y_offset;
+
+  /*
+    Compute maximum area of appended area.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  image=images;
+  matte=image->matte;
+  number_images=1;
+  width=image->columns;
+  height=image->rows;
+  next=GetNextImageInList(image);
+  for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    if (next->matte != MagickFalse)
+      matte=MagickTrue;
+    number_images++;
+    if (stack != MagickFalse)
+      {
+        if (next->columns > width)
+          width=next->columns;
+        height+=next->rows;
+        continue;
+      }
+    width+=next->columns;
+    if (next->rows > height)
+      height=next->rows;
+  }
+  /*
+    Append images.
+  */
+  append_image=CloneImage(image,width,height,MagickTrue,exception);
+  if (append_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(append_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&append_image->exception);
+      append_image=DestroyImage(append_image);
+      return((Image *) NULL);
+    }
+  append_image->matte=matte;
+  (void) SetImageBackgroundColor(append_image);
+  status=MagickTrue;
+  x_offset=0;
+  y_offset=0;
+  append_view=AcquireCacheView(append_image);
+  for (n=0; n < (MagickOffsetType) number_images; n++)
+  {
+    SetGeometry(append_image,&geometry);
+    GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
+    if (stack != MagickFalse)
+      x_offset-=geometry.x;
+    else
+      y_offset-=geometry.y;
+    image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+    #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+#endif
+    for (y=0; y < (ssize_t) image->rows; y++)
+    {
+      MagickBooleanType
+        sync;
+
+      register const Quantum
+        *restrict p;
+
+      register Quantum
+        *restrict q;
+
+      register ssize_t
+        x;
+
+      if (status == MagickFalse)
+        continue;
+      p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+      q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
+        image->columns,1,exception);
+      if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+        {
+          status=MagickFalse;
+          continue;
+        }
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        SetPixelRed(append_image,GetPixelRed(image,p),q);
+        SetPixelGreen(append_image,GetPixelGreen(image,p),q);
+        SetPixelBlue(append_image,GetPixelBlue(image,p),q);
+        if ((image->colorspace == CMYKColorspace) &&
+            (append_image->colorspace == CMYKColorspace))
+          SetPixelBlack(append_image,GetPixelBlack(image,p),q);
+        SetPixelAlpha(append_image,OpaqueAlpha,q);
+        if (image->matte != MagickFalse)
+          SetPixelAlpha(append_image,GetPixelAlpha(image,p),q);
+        p+=GetPixelChannels(image);
+        q+=GetPixelChannels(append_image);
+      }
+      sync=SyncCacheViewAuthenticPixels(append_view,exception);
+      if (sync == MagickFalse)
+        status=MagickFalse;
+    }
+    image_view=DestroyCacheView(image_view);
+    proceed=SetImageProgress(image,AppendImageTag,n,number_images);
+    if (proceed == MagickFalse)
+      break;
+    if (stack == MagickFalse)
+      {
+        x_offset+=(ssize_t) image->columns;
+        y_offset=0;
+      }
+    else
+      {
+        x_offset=0;
+        y_offset+=(ssize_t) image->rows;
+      }
+    image=GetNextImageInList(image);
+  }
+  append_view=DestroyCacheView(append_view);
+  if (status == MagickFalse)
+    append_image=DestroyImage(append_image);
+  return(append_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C a t c h I m a g e E x c e p t i o n                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CatchImageException() returns if no exceptions are found in the image
+%  sequence, otherwise it determines the most severe exception and reports
+%  it as a warning or error depending on the severity.
+%
+%  The format of the CatchImageException method is:
+%
+%      ExceptionType CatchImageException(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: An image sequence.
+%
+*/
+MagickExport ExceptionType CatchImageException(Image *image)
+{
+  ExceptionInfo
+    *exception;
+
+  ExceptionType
+    severity;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  exception=AcquireExceptionInfo();
+  GetImageException(image,exception);
+  CatchException(exception);
+  severity=exception->severity;
+  exception=DestroyExceptionInfo(exception);
+  return(severity);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l i p I m a g e P a t h                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClipImagePath() sets the image clip mask based any clipping path information
+%  if it exists.
+%
+%  The format of the ClipImagePath method is:
+%
+%      MagickBooleanType ClipImagePath(Image *image,const char *pathname,
+%        const MagickBooleanType inside)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o pathname: name of clipping path resource. If name is preceded by #, use
+%      clipping path numbered by name.
+%
+%    o inside: if non-zero, later operations take effect inside clipping path.
+%      Otherwise later operations take effect outside clipping path.
+%
+*/
+
+MagickExport MagickBooleanType ClipImage(Image *image)
+{
+  return(ClipImagePath(image,"#1",MagickTrue));
+}
+
+MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
+  const MagickBooleanType inside)
+{
+#define ClipImagePathTag  "ClipPath/Image"
+
+  char
+    *property;
+
+  const char
+    *value;
+
+  Image
+    *clip_mask;
+
+  ImageInfo
+    *image_info;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(pathname != NULL);
+  property=AcquireString(pathname);
+  (void) FormatLocaleString(property,MaxTextExtent,"8BIM:1999,2998:%s",
+    pathname);
+  value=GetImageProperty(image,property);
+  property=DestroyString(property);
+  if (value == (const char *) NULL)
+    {
+      ThrowFileException(&image->exception,OptionError,"NoClipPathDefined",
+        image->filename);
+      return(MagickFalse);
+    }
+  image_info=AcquireImageInfo();
+  (void) CopyMagickString(image_info->filename,image->filename,MaxTextExtent);
+  (void) ConcatenateMagickString(image_info->filename,pathname,MaxTextExtent);
+  clip_mask=BlobToImage(image_info,value,strlen(value),&image->exception);
+  image_info=DestroyImageInfo(image_info);
+  if (clip_mask == (Image *) NULL)
+    return(MagickFalse);
+  if (clip_mask->storage_class == PseudoClass)
+    {
+      (void) SyncImage(clip_mask);
+      if (SetImageStorageClass(clip_mask,DirectClass) == MagickFalse)
+        return(MagickFalse);
+    }
+  if (inside == MagickFalse)
+    (void) NegateImage(clip_mask,MagickFalse);
+  (void) FormatLocaleString(clip_mask->magick_filename,MaxTextExtent,
+    "8BIM:1999,2998:%s\nPS",pathname);
+  (void) SetImageClipMask(image,clip_mask);
+  clip_mask=DestroyImage(clip_mask);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImage() copies an image and returns the copy as a new image object.
+%
+%  If the specified columns and rows is 0, an exact copy of the image is
+%  returned, otherwise the pixel data is undefined and must be initialized
+%  with the QueueAuthenticPixels() and SyncAuthenticPixels() methods.  On
+%  failure, a NULL image is returned and exception describes the reason for the
+%  failure.
+%
+%  The format of the CloneImage method is:
+%
+%      Image *CloneImage(const Image *image,const size_t columns,
+%        const size_t rows,const MagickBooleanType orphan,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the cloned image.
+%
+%    o rows: the number of rows in the cloned image.
+%
+%    o detach:  With a value other than 0, the cloned image is detached from
+%      its parent I/O stream.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CloneImage(const Image *image,const size_t columns,
+  const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
+{
+  Image
+    *clone_image;
+
+  MagickRealType
+    scale;
+
+  size_t
+    length;
+
+  /*
+    Clone the image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  clone_image=(Image *) AcquireMagickMemory(sizeof(*clone_image));
+  if (clone_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(clone_image,0,sizeof(*clone_image));
+  clone_image->signature=MagickSignature;
+  clone_image->storage_class=image->storage_class;
+  clone_image->pixel_channels=image->pixel_channels;
+  clone_image->metacontent_extent=image->metacontent_extent;
+  clone_image->colorspace=image->colorspace;
+  clone_image->matte=image->matte;
+  clone_image->columns=image->columns;
+  clone_image->rows=image->rows;
+  clone_image->dither=image->dither;
+  if (image->colormap != (PixelPacket *) NULL)
+    {
+      /*
+        Allocate and copy the image colormap.
+      */
+      clone_image->colors=image->colors;
+      length=(size_t) image->colors;
+      clone_image->colormap=(PixelPacket *) AcquireQuantumMemory(length,
+        sizeof(*clone_image->colormap));
+      if (clone_image->colormap == (PixelPacket *) NULL)
+        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+      (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
+        sizeof(*clone_image->colormap));
+    }
+  (void) CloneImageProfiles(clone_image,image);
+  (void) CloneImageProperties(clone_image,image);
+  (void) CloneImageArtifacts(clone_image,image);
+  GetTimerInfo(&clone_image->timer);
+  GetExceptionInfo(&clone_image->exception);
+  InheritException(&clone_image->exception,&image->exception);
+  if (image->ascii85 != (void *) NULL)
+    Ascii85Initialize(clone_image);
+  clone_image->magick_columns=image->magick_columns;
+  clone_image->magick_rows=image->magick_rows;
+  clone_image->type=image->type;
+  clone_image->component_map=ClonePixelComponentMap(image->component_map);
+  (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
+    MaxTextExtent);
+  (void) CopyMagickString(clone_image->magick,image->magick,MaxTextExtent);
+  (void) CopyMagickString(clone_image->filename,image->filename,MaxTextExtent);
+  clone_image->progress_monitor=image->progress_monitor;
+  clone_image->client_data=image->client_data;
+  clone_image->reference_count=1;
+  clone_image->next=image->next;
+  clone_image->previous=image->previous;
+  clone_image->list=NewImageList();
+  clone_image->clip_mask=NewImageList();
+  clone_image->mask=NewImageList();
+  if (detach == MagickFalse)
+    clone_image->blob=ReferenceBlob(image->blob);
+  else
+    {
+      clone_image->next=NewImageList();
+      clone_image->previous=NewImageList();
+      clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
+    }
+  clone_image->ping=image->ping;
+  clone_image->debug=IsEventLogging();
+  clone_image->semaphore=AllocateSemaphoreInfo();
+  if ((columns == 0) && (rows == 0))
+    {
+      if (image->montage != (char *) NULL)
+        (void) CloneString(&clone_image->montage,image->montage);
+      if (image->directory != (char *) NULL)
+        (void) CloneString(&clone_image->directory,image->directory);
+      if (image->clip_mask != (Image *) NULL)
+        clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
+          exception);
+      if (image->mask != (Image *) NULL)
+        clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
+      clone_image->cache=ReferencePixelCache(image->cache);
+      return(clone_image);
+    }
+  if ((columns == image->columns) && (rows == image->rows))
+    {
+      if (image->clip_mask != (Image *) NULL)
+        clone_image->clip_mask=CloneImage(image->clip_mask,0,0,MagickTrue,
+          exception);
+      if (image->mask != (Image *) NULL)
+        clone_image->mask=CloneImage(image->mask,0,0,MagickTrue,exception);
+    }
+  scale=(MagickRealType) columns/(MagickRealType) image->columns;
+  clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
+  clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
+  clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
+  scale=(MagickRealType) rows/(MagickRealType) image->rows;
+  clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
+  clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
+  clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
+  clone_image->columns=columns;
+  clone_image->rows=rows;
+  clone_image->cache=ClonePixelCache(image->cache);
+  return(clone_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageInfo() makes a copy of the given image info structure.  If
+%  NULL is specified, a new image info structure is created initialized to
+%  default values.
+%
+%  The format of the CloneImageInfo method is:
+%
+%      ImageInfo *CloneImageInfo(const ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
+{
+  ImageInfo
+    *clone_info;
+
+  clone_info=AcquireImageInfo();
+  if (image_info == (ImageInfo *) NULL)
+    return(clone_info);
+  clone_info->compression=image_info->compression;
+  clone_info->temporary=image_info->temporary;
+  clone_info->adjoin=image_info->adjoin;
+  clone_info->antialias=image_info->antialias;
+  clone_info->scene=image_info->scene;
+  clone_info->number_scenes=image_info->number_scenes;
+  clone_info->depth=image_info->depth;
+  if (image_info->size != (char *) NULL)
+    (void) CloneString(&clone_info->size,image_info->size);
+  if (image_info->extract != (char *) NULL)
+    (void) CloneString(&clone_info->extract,image_info->extract);
+  if (image_info->scenes != (char *) NULL)
+    (void) CloneString(&clone_info->scenes,image_info->scenes);
+  if (image_info->page != (char *) NULL)
+    (void) CloneString(&clone_info->page,image_info->page);
+  clone_info->interlace=image_info->interlace;
+  clone_info->endian=image_info->endian;
+  clone_info->units=image_info->units;
+  clone_info->quality=image_info->quality;
+  if (image_info->sampling_factor != (char *) NULL)
+    (void) CloneString(&clone_info->sampling_factor,
+      image_info->sampling_factor);
+  if (image_info->server_name != (char *) NULL)
+    (void) CloneString(&clone_info->server_name,image_info->server_name);
+  if (image_info->font != (char *) NULL)
+    (void) CloneString(&clone_info->font,image_info->font);
+  if (image_info->texture != (char *) NULL)
+    (void) CloneString(&clone_info->texture,image_info->texture);
+  if (image_info->density != (char *) NULL)
+    (void) CloneString(&clone_info->density,image_info->density);
+  clone_info->pointsize=image_info->pointsize;
+  clone_info->fuzz=image_info->fuzz;
+  clone_info->background_color=image_info->background_color;
+  clone_info->border_color=image_info->border_color;
+  clone_info->matte_color=image_info->matte_color;
+  clone_info->transparent_color=image_info->transparent_color;
+  clone_info->dither=image_info->dither;
+  clone_info->monochrome=image_info->monochrome;
+  clone_info->colors=image_info->colors;
+  clone_info->colorspace=image_info->colorspace;
+  clone_info->type=image_info->type;
+  clone_info->orientation=image_info->orientation;
+  clone_info->preview_type=image_info->preview_type;
+  clone_info->group=image_info->group;
+  clone_info->ping=image_info->ping;
+  clone_info->verbose=image_info->verbose;
+  if (image_info->view != (char *) NULL)
+    (void) CloneString(&clone_info->view,image_info->view);
+  if (image_info->authenticate != (char *) NULL)
+    (void) CloneString(&clone_info->authenticate,image_info->authenticate);
+  (void) CloneImageOptions(clone_info,image_info);
+  clone_info->progress_monitor=image_info->progress_monitor;
+  clone_info->client_data=image_info->client_data;
+  clone_info->cache=image_info->cache;
+  if (image_info->cache != (void *) NULL)
+    clone_info->cache=ReferencePixelCache(image_info->cache);
+  if (image_info->profile != (void *) NULL)
+    clone_info->profile=(void *) CloneStringInfo((StringInfo *)
+      image_info->profile);
+  SetImageInfoFile(clone_info,image_info->file);
+  SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
+  clone_info->stream=image_info->stream;
+  clone_info->virtual_pixel_method=image_info->virtual_pixel_method;
+  (void) CopyMagickString(clone_info->magick,image_info->magick,MaxTextExtent);
+  (void) CopyMagickString(clone_info->unique,image_info->unique,MaxTextExtent);
+  (void) CopyMagickString(clone_info->zero,image_info->zero,MaxTextExtent);
+  (void) CopyMagickString(clone_info->filename,image_info->filename,
+    MaxTextExtent);
+  clone_info->channel=image_info->channel;
+  clone_info->debug=IsEventLogging();
+  clone_info->signature=image_info->signature;
+  return(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o m b i n e I m a g e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CombineImages() combines one or more images into a single image.  The
+%  grayscale value of the pixels of each image in the sequence is assigned in
+%  order to the specified channels of the combined image.   The typical
+%  ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
+%
+%  The format of the CombineImages method is:
+%
+%      Image *CombineImages(const Image *image,const ChannelType channel,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
+  ExceptionInfo *exception)
+{
+#define CombineImageTag  "Combine/Image"
+
+  CacheView
+    *combine_view;
+
+  const Image
+    *next;
+
+  Image
+    *combine_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  /*
+    Ensure the image are the same size.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    if ((next->columns != image->columns) || (next->rows != image->rows))
+      ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
+  }
+  combine_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (combine_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&combine_image->exception);
+      combine_image=DestroyImage(combine_image);
+      return((Image *) NULL);
+    }
+  if ((channel & AlphaChannel) != 0)
+    combine_image->matte=MagickTrue;
+  (void) SetImageBackgroundColor(combine_image);
+  /*
+    Combine images.
+  */
+  status=MagickTrue;
+  progress=0;
+  combine_view=AcquireCacheView(combine_image);
+  for (y=0; y < (ssize_t) combine_image->rows; y++)
+  {
+    CacheView
+      *image_view;
+
+    const Image
+      *next;
+
+    Quantum
+      *pixels;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
+      1,exception);
+    if (pixels == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    next=image;
+    if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
+      {
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (ssize_t) combine_image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelIntensity(image,p),q);
+          p+=GetPixelChannels(image);
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
+      {
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (ssize_t) combine_image->columns; x++)
+        {
+          SetPixelGreen(image,GetPixelIntensity(image,p),q);
+          p+=GetPixelChannels(image);
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
+      {
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (ssize_t) combine_image->columns; x++)
+        {
+          SetPixelBlue(image,GetPixelIntensity(image,p),q);
+          p+=GetPixelChannels(image);
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (((channel & BlackChannel) != 0) &&
+        (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
+      {
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (ssize_t) combine_image->columns; x++)
+        {
+          SetPixelBlack(image,GetPixelIntensity(image,p),q);
+          p+=GetPixelChannels(image);
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (((channel & AlphaChannel) != 0) && (next != (Image *) NULL))
+      {
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          continue;
+        q=pixels;
+        for (x=0; x < (ssize_t) combine_image->columns; x++)
+        {
+          SetPixelAlpha(image,GetPixelIntensity(image,p),q);
+          p+=GetPixelChannels(image);
+          q++;
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+    if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+        proceed=SetImageProgress(image,CombineImageTag,progress++,
+          combine_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  combine_view=DestroyCacheView(combine_view);
+  if (status == MagickFalse)
+    combine_image=DestroyImage(combine_image);
+  return(combine_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImage() dereferences an image, deallocating memory associated with
+%  the image if the reference count becomes zero.
+%
+%  The format of the DestroyImage method is:
+%
+%      Image *DestroyImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport Image *DestroyImage(Image *image)
+{
+  MagickBooleanType
+    destroy;
+
+  /*
+    Dereference image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  destroy=MagickFalse;
+  LockSemaphoreInfo(image->semaphore);
+  image->reference_count--;
+  if (image->reference_count == 0)
+    destroy=MagickTrue;
+  UnlockSemaphoreInfo(image->semaphore);
+  if (destroy == MagickFalse)
+    return((Image *) NULL);
+  /*
+    Destroy image.
+  */
+  DestroyImagePixels(image);
+  image->component_map=DestroyPixelComponentMap(image->component_map);
+  if (image->clip_mask != (Image *) NULL)
+    image->clip_mask=DestroyImage(image->clip_mask);
+  if (image->mask != (Image *) NULL)
+    image->mask=DestroyImage(image->mask);
+  if (image->montage != (char *) NULL)
+    image->montage=DestroyString(image->montage);
+  if (image->directory != (char *) NULL)
+    image->directory=DestroyString(image->directory);
+  if (image->colormap != (PixelPacket *) NULL)
+    image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
+  if (image->geometry != (char *) NULL)
+    image->geometry=DestroyString(image->geometry);
+  DestroyImageProfiles(image);
+  DestroyImageProperties(image);
+  DestroyImageArtifacts(image);
+  if (image->ascii85 != (Ascii85Info*) NULL)
+    image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
+  DestroyBlob(image);
+  (void) DestroyExceptionInfo(&image->exception);
+  if (image->semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&image->semaphore);
+  image->signature=(~MagickSignature);
+  image=(Image *) RelinquishMagickMemory(image);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageInfo() deallocates memory associated with an ImageInfo
+%  structure.
+%
+%  The format of the DestroyImageInfo method is:
+%
+%      ImageInfo *DestroyImageInfo(ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->size != (char *) NULL)
+    image_info->size=DestroyString(image_info->size);
+  if (image_info->extract != (char *) NULL)
+    image_info->extract=DestroyString(image_info->extract);
+  if (image_info->scenes != (char *) NULL)
+    image_info->scenes=DestroyString(image_info->scenes);
+  if (image_info->page != (char *) NULL)
+    image_info->page=DestroyString(image_info->page);
+  if (image_info->sampling_factor != (char *) NULL)
+    image_info->sampling_factor=DestroyString(
+      image_info->sampling_factor);
+  if (image_info->server_name != (char *) NULL)
+    image_info->server_name=DestroyString(
+      image_info->server_name);
+  if (image_info->font != (char *) NULL)
+    image_info->font=DestroyString(image_info->font);
+  if (image_info->texture != (char *) NULL)
+    image_info->texture=DestroyString(image_info->texture);
+  if (image_info->density != (char *) NULL)
+    image_info->density=DestroyString(image_info->density);
+  if (image_info->view != (char *) NULL)
+    image_info->view=DestroyString(image_info->view);
+  if (image_info->authenticate != (char *) NULL)
+    image_info->authenticate=DestroyString(
+      image_info->authenticate);
+  DestroyImageOptions(image_info);
+  if (image_info->cache != (void *) NULL)
+    image_info->cache=DestroyPixelCache(image_info->cache);
+  if (image_info->profile != (StringInfo *) NULL)
+    image_info->profile=(void *) DestroyStringInfo((StringInfo *)
+      image_info->profile);
+  image_info->signature=(~MagickSignature);
+  image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
+  return(image_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D i s a s s o c i a t e I m a g e S t r e a m                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DisassociateImageStream() disassociates the image stream.
+%
+%  The format of the DisassociateImageStream method is:
+%
+%      MagickBooleanType DisassociateImageStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DisassociateImageStream(Image *image)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  (void) DetachBlob(image->blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e A l p h a C h a n n e l                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
+%  not activated.  That is, the image is RGB rather than RGBA or CMYK rather
+%  than CMYKA.
+%
+%  The format of the GetImageAlphaChannel method is:
+%
+%      MagickBooleanType GetImageAlphaChannel(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
+{
+  assert(image != (const Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  return(image->matte);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C l i p M a s k                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageClipMask() returns the clip path associated with the image.
+%
+%  The format of the GetImageClipMask method is:
+%
+%      Image *GetImageClipMask(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport Image *GetImageClipMask(const Image *image,
+  ExceptionInfo *exception)
+{
+  assert(image != (const Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (image->clip_mask == (Image *) NULL)
+    return((Image *) NULL);
+  return(CloneImage(image->clip_mask,0,0,MagickTrue,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e E x c e p t i o n                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageException() traverses an image sequence and returns any
+%  error more severe than noted by the exception parameter.
+%
+%  The format of the GetImageException method is:
+%
+%      void GetImageException(Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: Specifies a pointer to a list of one or more images.
+%
+%    o exception: return the highest severity exception.
+%
+*/
+MagickExport void GetImageException(Image *image,ExceptionInfo *exception)
+{
+  register Image
+    *next;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    if (next->exception.severity == UndefinedException)
+      continue;
+    if (next->exception.severity > exception->severity)
+      InheritException(exception,&next->exception);
+    next->exception.severity=UndefinedException;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e I n f o                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageInfo() initializes image_info to default values.
+%
+%  The format of the GetImageInfo method is:
+%
+%      void GetImageInfo(ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport void GetImageInfo(ImageInfo *image_info)
+{
+  const char
+    *synchronize;
+
+  ExceptionInfo
+    *exception;
+
+  /*
+    File and image dimension members.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image_info != (ImageInfo *) NULL);
+  (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
+  image_info->adjoin=MagickTrue;
+  image_info->interlace=NoInterlace;
+  image_info->channel=DefaultChannels;
+  image_info->quality=UndefinedCompressionQuality;
+  image_info->antialias=MagickTrue;
+  image_info->dither=MagickTrue;
+  synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
+  if (synchronize != (const char *) NULL)
+    image_info->synchronize=IsMagickTrue(synchronize);
+  exception=AcquireExceptionInfo();
+  (void) QueryColorDatabase(BackgroundColor,&image_info->background_color,
+    exception);
+  (void) QueryColorDatabase(BorderColor,&image_info->border_color,exception);
+  (void) QueryColorDatabase(MatteColor,&image_info->matte_color,exception);
+  (void) QueryColorDatabase(TransparentColor,&image_info->transparent_color,
+    exception);
+  exception=DestroyExceptionInfo(exception);
+  image_info->debug=IsEventLogging();
+  image_info->signature=MagickSignature;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e I n f o F i l e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageInfoFile() returns the image info file member.
+%
+%  The format of the GetImageInfoFile method is:
+%
+%      FILE *GetImageInfoFile(const ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
+{
+  return(image_info->file);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e M a s k                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageMask() returns the mask associated with the image.
+%
+%  The format of the GetImageMask method is:
+%
+%      Image *GetImageMask(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
+{
+  assert(image != (const Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (image->mask == (Image *) NULL)
+    return((Image *) NULL);
+  return(CloneImage(image->mask,0,0,MagickTrue,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e R e f e r e n c e C o u n t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageReferenceCount() returns the image reference count.
+%
+%  The format of the GetReferenceCount method is:
+%
+%      ssize_t GetImageReferenceCount(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport ssize_t GetImageReferenceCount(Image *image)
+{
+  ssize_t
+    reference_count;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  LockSemaphoreInfo(image->semaphore);
+  reference_count=image->reference_count;
+  UnlockSemaphoreInfo(image->semaphore);
+  return(reference_count);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e V i r t u a l P i x e l M e t h o d                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
+%  image.  A virtual pixel is any pixel access that is outside the boundaries
+%  of the image cache.
+%
+%  The format of the GetImageVirtualPixelMethod() method is:
+%
+%      VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(GetPixelCacheVirtualMethod(image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I n t e r p r e t I m a g e F i l e n a m e                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpretImageFilename() interprets embedded characters in an image filename.
+%  The filename length is returned.
+%
+%  The format of the InterpretImageFilename method is:
+%
+%      size_t InterpretImageFilename(const ImageInfo *image_info,
+%        Image *image,const char *format,int value,char *filename)
+%
+%  A description of each parameter follows.
+%
+%    o image_info: the image info..
+%
+%    o image: the image.
+%
+%    o format:  A filename describing the format to use to write the numeric
+%      argument. Only the first numeric format identifier is replaced.
+%
+%    o value:  Numeric value to substitute into format filename.
+%
+%    o filename:  return the formatted filename in this character buffer.
+%
+*/
+MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
+  Image *image,const char *format,int value,char *filename)
+{
+  char
+    *q;
+
+  int
+    c;
+
+  MagickBooleanType
+    canonical;
+
+  register const char
+    *p;
+
+  canonical=MagickFalse;
+  (void) CopyMagickString(filename,format,MaxTextExtent);
+  for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
+  {
+    q=(char *) p+1;
+    if (*q == '%')
+      {
+        p=q+1;
+        continue;
+      }
+    if (*q == '0')
+      {
+        ssize_t
+          value;
+
+        value=(ssize_t) strtol(q,&q,10);
+        (void) value;
+      }
+    switch (*q)
+    {
+      case 'd':
+      case 'o':
+      case 'x':
+      {
+        q++;
+        c=(*q);
+        *q='\0';
+        (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
+          (p-format)),p,value);
+        *q=c;
+        (void) ConcatenateMagickString(filename,q,MaxTextExtent);
+        canonical=MagickTrue;
+        if (*(q-1) != '%')
+          break;
+        p++;
+        break;
+      }
+      case '[':
+      {
+        char
+          pattern[MaxTextExtent];
+
+        const char
+          *value;
+
+        register char
+          *r;
+
+        register ssize_t
+          i;
+
+        ssize_t
+          depth;
+
+        /*
+          Image option.
+        */
+        if (strchr(p,']') == (char *) NULL)
+          break;
+        depth=1;
+        r=q+1;
+        for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
+        {
+          if (*r == '[')
+            depth++;
+          if (*r == ']')
+            depth--;
+          if (depth <= 0)
+            break;
+          pattern[i]=(*r++);
+        }
+        pattern[i]='\0';
+        if (LocaleNCompare(pattern,"filename:",9) != 0)
+          break;
+        value=(const char *) NULL;
+        if ((image_info != (const ImageInfo *) NULL) &&
+            (image != (const Image *) NULL))
+          value=GetMagickProperty(image_info,image,pattern);
+        else
+          if (image != (Image *) NULL)
+            value=GetImageProperty(image,pattern);
+          else
+            if (image_info != (ImageInfo *) NULL)
+              value=GetImageOption(image_info,pattern);
+        if (value == (const char *) NULL)
+          break;
+        q--;
+        c=(*q);
+        *q='\0';
+        (void) CopyMagickString(filename+(p-format),value,(size_t)
+          (MaxTextExtent-(p-format)));
+        *q=c;
+        (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
+        canonical=MagickTrue;
+        if (*(q-1) != '%')
+          break;
+        p++;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  for (q=filename; *q != '\0'; q++)
+    if ((*q == '%') && (*(q+1) == '%'))
+      {
+        (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
+        canonical=MagickTrue;
+      }
+  if (canonical == MagickFalse)
+    (void) CopyMagickString(filename,format,MaxTextExtent);
+  return(strlen(filename));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s H i g h D y n a m i c R a n g e I m a g e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
+%  non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
+%  0..65535.
+%
+%  The format of the IsHighDynamicRangeImage method is:
+%
+%      MagickBooleanType IsHighDynamicRangeImage(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
+  ExceptionInfo *exception)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  (void) image;
+  (void) exception;
+  return(MagickFalse);
+#else
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  status=MagickTrue;
+  GetPixelInfo(image,&zero);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register const Quantum
+      *p;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,p,&pixel);
+      if ((pixel.red < 0.0) || (pixel.red > QuantumRange) ||
+          (pixel.red != (QuantumAny) pixel.red))
+        break;
+      if ((pixel.green < 0.0) || (pixel.green > QuantumRange) ||
+          (pixel.green != (QuantumAny) pixel.green))
+        break;
+      if ((pixel.blue < 0.0) || (pixel.blue > QuantumRange) ||
+          (pixel.blue != (QuantumAny) pixel.blue))
+        break;
+      if (pixel.colorspace == CMYKColorspace)
+        {
+          if ((pixel.black < 0.0) || (pixel.black > QuantumRange) ||
+              (pixel.black != (QuantumAny) pixel.black))
+            break;
+        }
+      if (pixel.matte != MagickFalse)
+        {
+          if ((pixel.alpha < 0.0) || (pixel.alpha > QuantumRange) ||
+              (pixel.alpha != (QuantumAny) pixel.alpha))
+            break;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (x < (ssize_t) image->columns)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status != MagickFalse ? MagickFalse : MagickTrue);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s I m a g e O b j e c t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsImageObject() returns MagickTrue if the image sequence contains a valid
+%  set of image objects.
+%
+%  The format of the IsImageObject method is:
+%
+%      MagickBooleanType IsImageObject(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType IsImageObject(const Image *image)
+{
+  register const Image
+    *p;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
+    if (p->signature != MagickSignature)
+      return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s T a i n t I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsTaintImage() returns MagickTrue any pixel in the image has been altered
+%  since it was first constituted.
+%
+%  The format of the IsTaintImage method is:
+%
+%      MagickBooleanType IsTaintImage(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType IsTaintImage(const Image *image)
+{
+  char
+    magick[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  register const Image
+    *p;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  (void) CopyMagickString(magick,image->magick,MaxTextExtent);
+  (void) CopyMagickString(filename,image->filename,MaxTextExtent);
+  for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
+  {
+    if (p->taint != MagickFalse)
+      return(MagickTrue);
+    if (LocaleCompare(p->magick,magick) != 0)
+      return(MagickTrue);
+    if (LocaleCompare(p->filename,filename) != 0)
+      return(MagickTrue);
+  }
+  return(MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M o d i f y I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ModifyImage() ensures that there is only a single reference to the image
+%  to be modified, updating the provided image pointer to point to a clone of
+%  the original image if necessary.
+%
+%  The format of the ModifyImage method is:
+%
+%      MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ModifyImage(Image **image,
+  ExceptionInfo *exception)
+{
+  Image
+    *clone_image;
+
+  assert(image != (Image **) NULL);
+  assert(*image != (Image *) NULL);
+  assert((*image)->signature == MagickSignature);
+  if ((*image)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
+  if (GetImageReferenceCount(*image) <= 1)
+    return(MagickTrue);
+  clone_image=CloneImage(*image,0,0,MagickTrue,exception);
+  LockSemaphoreInfo((*image)->semaphore);
+  (*image)->reference_count--;
+  UnlockSemaphoreInfo((*image)->semaphore);
+  *image=clone_image;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w M a g i c k I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewMagickImage() creates a blank image canvas of the specified size and
+%  background color.
+%
+%  The format of the NewMagickImage method is:
+%
+%      Image *NewMagickImage(const ImageInfo *image_info,
+%        const size_t width,const size_t height,
+%        const PixelInfo *background)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o width: the image width.
+%
+%    o height: the image height.
+%
+%    o background: the image color.
+%
+*/
+MagickExport Image *NewMagickImage(const ImageInfo *image_info,
+  const size_t width,const size_t height,
+  const PixelInfo *background)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *image;
+
+  ssize_t
+    y;
+
+  MagickBooleanType
+    status;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image_info->signature == MagickSignature);
+  assert(background != (const PixelInfo *) NULL);
+  image=AcquireImage(image_info);
+  image->columns=width;
+  image->rows=height;
+  image->colorspace=background->colorspace;
+  image->matte=background->matte;
+  image->fuzz=background->fuzz;
+  image->depth=background->depth;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelPixelInfo(image,background,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    image=DestroyImage(image);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e f e r e n c e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReferenceImage() increments the reference count associated with an image
+%  returning a pointer to the image.
+%
+%  The format of the ReferenceImage method is:
+%
+%      Image *ReferenceImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport Image *ReferenceImage(Image *image)
+{
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  LockSemaphoreInfo(image->semaphore);
+  image->reference_count++;
+  UnlockSemaphoreInfo(image->semaphore);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e P a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImagePage() resets the image page canvas and position.
+%
+%  The format of the ResetImagePage method is:
+%
+%      MagickBooleanType ResetImagePage(Image *image,const char *page)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o page: the relative page specification.
+%
+*/
+MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
+{
+  MagickStatusType
+    flags;
+
+  RectangleInfo
+    geometry;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  flags=ParseAbsoluteGeometry(page,&geometry);
+  if ((flags & WidthValue) != 0)
+    {
+      if ((flags & HeightValue) == 0)
+        geometry.height=geometry.width;
+      image->page.width=geometry.width;
+      image->page.height=geometry.height;
+    }
+  if ((flags & AspectValue) != 0)
+    {
+      if ((flags & XValue) != 0)
+        image->page.x+=geometry.x;
+      if ((flags & YValue) != 0)
+        image->page.y+=geometry.y;
+    }
+  else
+    {
+      if ((flags & XValue) != 0)
+        {
+          image->page.x=geometry.x;
+          if ((image->page.width == 0) && (geometry.x > 0))
+            image->page.width=image->columns+geometry.x;
+        }
+      if ((flags & YValue) != 0)
+        {
+          image->page.y=geometry.y;
+          if ((image->page.height == 0) && (geometry.y > 0))
+            image->page.height=image->rows+geometry.y;
+        }
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S e p a r a t e I m a g e C h a n n e l                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SeparateImageChannel() separates a channel from the image and returns it as
+%  a grayscale image.  A channel is a particular color component of each pixel
+%  in the image.
+%
+%  The format of the SeparateImageChannel method is:
+%
+%      MagickBooleanType SeparateImageChannel(Image *image,
+%        const ChannelType channel)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: Identify which channel to extract: RedChannel, GreenChannel,
+%      BlueChannel, AlphaChannel, CyanChannel, MagentaChannel,
+%      YellowChannel, or BlackChannel.
+%
+*/
+MagickExport MagickBooleanType SeparateImageChannel(Image *image,
+  const ChannelType channel)
+{
+#define SeparateImageTag  "Separate/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  /*
+    Separate image channels.
+  */
+  status=MagickTrue;
+  if (channel == GrayChannels)
+    image->matte=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    switch (channel)
+    {
+      case RedChannel:
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelGreen(image,GetPixelRed(image,q),q);
+          SetPixelBlue(image,GetPixelRed(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case GreenChannel:
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelGreen(image,q),q);
+          SetPixelBlue(image,GetPixelGreen(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case BlueChannel:
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelBlue(image,q),q);
+          SetPixelGreen(image,GetPixelBlue(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case AlphaChannel:
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelAlpha(image,q),q);
+          SetPixelGreen(image,GetPixelAlpha(image,q),q);
+          SetPixelBlue(image,GetPixelAlpha(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case BlackChannel:
+      {
+        if ((image->storage_class != PseudoClass) &&
+            (image->colorspace != CMYKColorspace))
+          break;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelBlack(image,q),q);
+          SetPixelGreen(image,GetPixelBlack(image,q),q);
+          SetPixelBlue(image,GetPixelBlack(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case TrueAlphaChannel:
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,GetPixelAlpha(image,q),q);
+          SetPixelGreen(image,GetPixelAlpha(image,q),q);
+          SetPixelBlue(image,GetPixelAlpha(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case GrayChannels:
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelAlpha(image,GetPixelIntensity(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      default:
+        break;
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_SeparateImageChannel)
+#endif
+        proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (channel != GrayChannels)
+    image->matte=MagickFalse;
+  (void) SetImageColorspace(image,RGBColorspace);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S e p a r a t e I m a g e s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SeparateImages() returns a separate grayscale image for each channel
+%  specified.
+%
+%  The format of the SeparateImages method is:
+%
+%      MagickBooleanType SeparateImages(const Image *image,
+%        const ChannelType channel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: Identify which channels to extract: RedChannel, GreenChannel,
+%      BlueChannel, AlphaChannel, CyanChannel, MagentaChannel,
+%      YellowChannel, or BlackChannel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
+  ExceptionInfo *exception)
+{
+  Image
+    *images,
+    *separate_image;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  images=NewImageList();
+  if ((channel & RedChannel) != 0)
+    {
+      separate_image=CloneImage(image,0,0,MagickTrue,exception);
+      (void) SeparateImageChannel(separate_image,RedChannel);
+      AppendImageToList(&images,separate_image);
+    }
+  if ((channel & GreenChannel) != 0)
+    {
+      separate_image=CloneImage(image,0,0,MagickTrue,exception);
+      (void) SeparateImageChannel(separate_image,GreenChannel);
+      AppendImageToList(&images,separate_image);
+    }
+  if ((channel & BlueChannel) != 0)
+    {
+      separate_image=CloneImage(image,0,0,MagickTrue,exception);
+      (void) SeparateImageChannel(separate_image,BlueChannel);
+      AppendImageToList(&images,separate_image);
+    }
+  if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
+    {
+      separate_image=CloneImage(image,0,0,MagickTrue,exception);
+      (void) SeparateImageChannel(separate_image,BlackChannel);
+      AppendImageToList(&images,separate_image);
+    }
+  if ((channel & AlphaChannel) != 0)
+    {
+      separate_image=CloneImage(image,0,0,MagickTrue,exception);
+      (void) SeparateImageChannel(separate_image,AlphaChannel);
+      AppendImageToList(&images,separate_image);
+    }
+  return(images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e A l p h a C h a n n e l                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
+%  channel.
+%
+%  The format of the SetImageAlphaChannel method is:
+%
+%      MagickBooleanType SetImageAlphaChannel(Image *image,
+%        const AlphaChannelType alpha_type)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o alpha_type:  The alpha channel type: ActivateAlphaChannel,
+%      CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
+%      OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
+%      TransparentAlphaChannel.
+%
+*/
+MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
+  const AlphaChannelType alpha_type)
+{
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  status=MagickFalse;
+  switch (alpha_type)
+  {
+    case ActivateAlphaChannel:
+    {
+      image->matte=MagickTrue;
+      break;
+    }
+    case BackgroundAlphaChannel:
+    {
+      CacheView
+        *image_view;
+
+      ExceptionInfo
+        *exception;
+
+      MagickBooleanType
+        status;
+
+      PixelInfo
+        background;
+
+      PixelPacket
+        pixel;
+
+      ssize_t
+        y;
+
+      /*
+        Set transparent pixels to background color.
+      */
+      if (image->matte == MagickFalse)
+        break;
+      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+        break;
+      GetPixelInfo(image,&background);
+      SetPixelInfoPacket(image,&image->background_color,&background);
+      if (image->colorspace == CMYKColorspace)
+        ConvertRGBToCMYK(&background);
+      SetPacketPixelInfo(image,&background,&pixel);
+      status=MagickTrue;
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+      #if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp parallel for schedule(dynamic,4) shared(status)
+      #endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        register Quantum
+          *restrict q;
+
+        register ssize_t
+          x;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          if (GetPixelAlpha(image,q) == TransparentAlpha)
+            {
+              SetPixelRed(image,pixel.red,q);
+              SetPixelGreen(image,pixel.green,q);
+              SetPixelBlue(image,pixel.blue,q);
+              if (image->colorspace == CMYKColorspace)
+                SetPixelBlack(image,pixel.black,q);
+            }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      return(status);
+    }
+    case DeactivateAlphaChannel:
+    {
+      image->matte=MagickFalse;
+      break;
+    }
+    case ShapeAlphaChannel:
+    case CopyAlphaChannel:
+    {
+      /*
+        Special usage case for SeparateImageChannel(): copy grayscale color to
+        the alpha channel.
+      */
+      status=SeparateImageChannel(image,GrayChannels);
+      image->matte=MagickTrue; /* make sure transparency is now on! */
+      if (alpha_type == ShapeAlphaChannel)
+        {
+          PixelInfo
+            background;
+
+          /*
+            Reset all color channels to background color.
+          */
+          GetPixelInfo(image,&background);
+          SetPixelInfoPacket(image,&(image->background_color),&background);
+          (void) LevelColorsImage(image,&background,&background,MagickTrue);
+        }
+      break;
+    }
+    case ExtractAlphaChannel:
+    {
+      status=SeparateImageChannel(image,TrueAlphaChannel);
+      image->matte=MagickFalse;
+      break;
+    }
+    case OpaqueAlphaChannel:
+    {
+      status=SetImageOpacity(image,OpaqueAlpha);
+      image->matte=MagickTrue;
+      break;
+    }
+    case TransparentAlphaChannel:
+    {
+      status=SetImageOpacity(image,TransparentAlpha);
+      image->matte=MagickTrue;
+      break;
+    }
+    case SetAlphaChannel:
+    {
+      if (image->matte == MagickFalse)
+        {
+          status=SetImageOpacity(image,OpaqueAlpha);
+          image->matte=MagickTrue;
+        }
+      break;
+    }
+    case UndefinedAlphaChannel:
+      break;
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e B a c k g r o u n d C o l o r                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageBackgroundColor() initializes the image pixels to the image
+%  background color.  The background color is defined by the background_color
+%  member of the image structure.
+%
+%  The format of the SetImage method is:
+%
+%      MagickBooleanType SetImageBackgroundColor(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType SetImageBackgroundColor(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    background;
+
+  PixelPacket
+    pixel;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->background_color.alpha != OpaqueAlpha)
+    image->matte=MagickTrue;
+  GetPixelInfo(image,&background);
+  SetPixelInfoPacket(image,&image->background_color,&background);
+  if (image->colorspace == CMYKColorspace)
+    ConvertRGBToCMYK(&background);
+  SetPacketPixelInfo(image,&background,&pixel);
+  /*
+    Set image background color.
+  */
+  status=MagickTrue;
+  pixel.black=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelPacket(image,&pixel,q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(image,pixel.black,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e C o l o r                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageColor() set the entire image canvas to the specified color.
+%
+%  The format of the SetImageColor method is:
+%
+%      MagickBooleanType SetImageColor(Image *image,
+%        const PixelInfo *color)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o background: the image color.
+%
+*/
+MagickExport MagickBooleanType SetImageColor(Image *image,
+  const PixelInfo *color)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  assert(color != (const PixelInfo *) NULL);
+  image->colorspace=color->colorspace;
+  image->matte=color->matte;
+  image->fuzz=color->fuzz;
+  image->depth=color->depth;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelPixelInfo(image,color,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e S t o r a g e C l a s s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageStorageClass() sets the image class: DirectClass for true color
+%  images or PseudoClass for colormapped images.
+%
+%  The format of the SetImageStorageClass method is:
+%
+%      MagickBooleanType SetImageStorageClass(Image *image,
+%        const ClassType storage_class)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o storage_class:  The image class.
+%
+*/
+MagickExport MagickBooleanType SetImageStorageClass(Image *image,
+  const ClassType storage_class)
+{
+  image->storage_class=storage_class;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e C l i p M a s k                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageClipMask() associates a clip path with the image.  The clip path
+%  must be the same dimensions as the image.  Set any pixel component of
+%  the clip path to TransparentAlpha to prevent that corresponding image
+%  pixel component from being updated when SyncAuthenticPixels() is applied.
+%
+%  The format of the SetImageClipMask method is:
+%
+%      MagickBooleanType SetImageClipMask(Image *image,const Image *clip_mask)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o clip_mask: the image clip path.
+%
+*/
+MagickExport MagickBooleanType SetImageClipMask(Image *image,
+  const Image *clip_mask)
+{
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (clip_mask != (const Image *) NULL)
+    if ((clip_mask->columns != image->columns) ||
+        (clip_mask->rows != image->rows))
+      ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
+  if (image->clip_mask != (Image *) NULL)
+    image->clip_mask=DestroyImage(image->clip_mask);
+  image->clip_mask=NewImageList();
+  if (clip_mask == (Image *) NULL)
+    return(MagickTrue);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  image->clip_mask=CloneImage(clip_mask,0,0,MagickTrue,&image->exception);
+  if (image->clip_mask == (Image *) NULL)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e E x t e n t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageExtent() sets the image size (i.e. columns & rows).
+%
+%  The format of the SetImageExtent method is:
+%
+%      MagickBooleanType SetImageExtent(Image *image,
+%        const size_t columns,const size_t rows)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns:  The image width in pixels.
+%
+%    o rows:  The image height in pixels.
+%
+*/
+MagickExport MagickBooleanType SetImageExtent(Image *image,
+  const size_t columns,const size_t rows)
+{
+  if ((columns == 0) || (rows == 0))
+    return(MagickFalse);
+  image->columns=columns;
+  image->rows=rows;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t I m a g e I n f o                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageInfo() initializes the `magick' field of the ImageInfo structure.
+%  It is set to a type of image format based on the prefix or suffix of the
+%  filename.  For example, `ps:image' returns PS indicating a Postscript image.
+%  JPEG is returned for this filename: `image.jpg'.  The filename prefix has
+%  precendence over the suffix.  Use an optional index enclosed in brackets
+%  after a file name to specify a desired scene of a multi-resolution image
+%  format like Photo CD (e.g. img0001.pcd[4]).  A True (non-zero) return value
+%  indicates success.
+%
+%  The format of the SetImageInfo method is:
+%
+%      MagickBooleanType SetImageInfo(ImageInfo *image_info,
+%        const unsigned int frames,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o frames: the number of images you intend to write.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
+  const unsigned int frames,ExceptionInfo *exception)
+{
+  char
+    extension[MaxTextExtent],
+    filename[MaxTextExtent],
+    magic[MaxTextExtent],
+    *q,
+    subimage[MaxTextExtent];
+
+  const MagicInfo
+    *magic_info;
+
+  const MagickInfo
+    *magick_info;
+
+  ExceptionInfo
+    *sans_exception;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  register const char
+    *p;
+
+  ssize_t
+    count;
+
+  unsigned char
+    magick[2*MaxTextExtent];
+
+  /*
+    Look for 'image.format' in filename.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  *subimage='\0';
+  if (frames == 0)
+    {
+      GetPathComponent(image_info->filename,SubimagePath,subimage);
+      if (*subimage != '\0')
+        {
+          /*
+            Look for scene specification (e.g. img0001.pcd[4]).
+          */
+          if (IsSceneGeometry(subimage,MagickFalse) == MagickFalse)
+            {
+              if (IsGeometry(subimage) != MagickFalse)
+                (void) CloneString(&image_info->extract,subimage);
+            }
+          else
+            {
+              size_t
+                first,
+                last;
+
+              (void) CloneString(&image_info->scenes,subimage);
+              image_info->scene=StringToUnsignedLong(image_info->scenes);
+              image_info->number_scenes=image_info->scene;
+              p=image_info->scenes;
+              for (q=(char *) image_info->scenes; *q != '\0'; p++)
+              {
+                while ((isspace((int) ((unsigned char) *p)) != 0) ||
+                       (*p == ','))
+                  p++;
+                first=(size_t) strtol(p,&q,10);
+                last=first;
+                while (isspace((int) ((unsigned char) *q)) != 0)
+                  q++;
+                if (*q == '-')
+                  last=(size_t) strtol(q+1,&q,10);
+                if (first > last)
+                  Swap(first,last);
+                if (first < image_info->scene)
+                  image_info->scene=first;
+                if (last > image_info->number_scenes)
+                  image_info->number_scenes=last;
+                p=q;
+              }
+              image_info->number_scenes-=image_info->scene-1;
+            }
+        }
+    }
+  *extension='\0';
+  GetPathComponent(image_info->filename,ExtensionPath,extension);
+#if defined(MAGICKCORE_ZLIB_DELEGATE)
+  if (*extension != '\0')
+    if ((LocaleCompare(extension,"gz") == 0) ||
+        (LocaleCompare(extension,"Z") == 0) ||
+        (LocaleCompare(extension,"wmz") == 0))
+      {
+        char
+          path[MaxTextExtent];
+
+        (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
+        path[strlen(path)-strlen(extension)-1]='\0';
+        GetPathComponent(path,ExtensionPath,extension);
+      }
+#endif
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+  if (*extension != '\0')
+    if (LocaleCompare(extension,"bz2") == 0)
+      {
+        char
+          path[MaxTextExtent];
+
+        (void) CopyMagickString(path,image_info->filename,MaxTextExtent);
+        path[strlen(path)-strlen(extension)-1]='\0';
+        GetPathComponent(path,ExtensionPath,extension);
+      }
+#endif
+  image_info->affirm=MagickFalse;
+  sans_exception=AcquireExceptionInfo();
+  if (*extension != '\0')
+    {
+      MagickFormatType
+        format_type;
+
+      register ssize_t
+        i;
+
+      static const char
+        *format_type_formats[] =
+        {
+          "AUTOTRACE",
+          "BROWSE",
+          "DCRAW",
+          "EDIT",
+          "EPHEMERAL",
+          "LAUNCH",
+          "MPEG:DECODE",
+          "MPEG:ENCODE",
+          "PRINT",
+          "PS:ALPHA",
+          "PS:CMYK",
+          "PS:COLOR",
+          "PS:GRAY",
+          "PS:MONO",
+          "SCAN",
+          "SHOW",
+          "WIN",
+          (char *) NULL
+        };
+
+      /*
+        User specified image format.
+      */
+      (void) CopyMagickString(magic,extension,MaxTextExtent);
+      LocaleUpper(magic);
+      /*
+        Look for explicit image formats.
+      */
+      format_type=UndefinedFormatType;
+      i=0;
+      while ((format_type == UndefinedFormatType) &&
+             (format_type_formats[i] != (char *) NULL))
+      {
+        if ((*magic == *format_type_formats[i]) &&
+            (LocaleCompare(magic,format_type_formats[i]) == 0))
+          format_type=ExplicitFormatType;
+        i++;
+      }
+      magick_info=GetMagickInfo(magic,sans_exception);
+      if ((magick_info != (const MagickInfo *) NULL) &&
+          (magick_info->format_type != UndefinedFormatType))
+        format_type=magick_info->format_type;
+      if (format_type == UndefinedFormatType)
+        (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
+      else
+        if (format_type == ExplicitFormatType)
+          {
+            image_info->affirm=MagickTrue;
+            (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
+          }
+      if (LocaleCompare(magic,"RGB") == 0)
+        image_info->affirm=MagickFalse;  /* maybe SGI disguised as RGB */
+    }
+  /*
+    Look for explicit 'format:image' in filename.
+  */
+  *magic='\0';
+  GetPathComponent(image_info->filename,MagickPath,magic);
+  if (*magic == '\0')
+    (void) CopyMagickString(magic,image_info->magick,MaxTextExtent);
+  else
+    {
+      /*
+        User specified image format.
+      */
+      LocaleUpper(magic);
+      if (IsMagickConflict(magic) == MagickFalse)
+        {
+          (void) CopyMagickString(image_info->magick,magic,MaxTextExtent);
+          if (LocaleCompare(magic,"EPHEMERAL") != 0)
+            image_info->affirm=MagickTrue;
+          else
+            image_info->temporary=MagickTrue;
+        }
+    }
+  magick_info=GetMagickInfo(magic,sans_exception);
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  if ((magick_info == (const MagickInfo *) NULL) ||
+      (GetMagickEndianSupport(magick_info) == MagickFalse))
+    image_info->endian=UndefinedEndian;
+  GetPathComponent(image_info->filename,CanonicalPath,filename);
+  (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+  if ((image_info->adjoin != MagickFalse) && (frames > 1))
+    {
+      /*
+        Test for multiple image support (e.g. image%02d.png).
+      */
+      (void) InterpretImageFilename(image_info,(Image *) NULL,
+        image_info->filename,(int) image_info->scene,filename);
+      if ((LocaleCompare(filename,image_info->filename) != 0) &&
+          (strchr(filename,'%') == (char *) NULL))
+        image_info->adjoin=MagickFalse;
+    }
+  if ((image_info->adjoin != MagickFalse) && (frames > 0))
+    {
+      /*
+        Some image formats do not support multiple frames per file.
+      */
+      magick_info=GetMagickInfo(magic,exception);
+      if (magick_info != (const MagickInfo *) NULL)
+        if (GetMagickAdjoin(magick_info) == MagickFalse)
+          image_info->adjoin=MagickFalse;
+    }
+  if (image_info->affirm != MagickFalse)
+    return(MagickTrue);
+  if (frames == 0)
+    {
+      /*
+        Determine the image format from the first few bytes of the file.
+      */
+      image=AcquireImage(image_info);
+      (void) CopyMagickString(image->filename,image_info->filename,
+        MaxTextExtent);
+      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
+      if (status == MagickFalse)
+        {
+          image=DestroyImage(image);
+          return(MagickFalse);
+        }
+      if ((IsBlobSeekable(image) == MagickFalse) ||
+          (IsBlobExempt(image) != MagickFalse))
+        {
+          /*
+            Copy standard input or pipe to temporary file.
+          */
+          *filename='\0';
+          status=ImageToFile(image,filename,exception);
+          (void) CloseBlob(image);
+          if (status == MagickFalse)
+            {
+              image=DestroyImage(image);
+              return(MagickFalse);
+            }
+          SetImageInfoFile(image_info,(FILE *) NULL);
+          (void) CopyMagickString(image->filename,filename,MaxTextExtent);
+          status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
+          if (status == MagickFalse)
+            {
+              image=DestroyImage(image);
+              return(MagickFalse);
+            }
+          (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
+          image_info->temporary=MagickTrue;
+        }
+      (void) ResetMagickMemory(magick,0,sizeof(magick));
+      count=ReadBlob(image,2*MaxTextExtent,magick);
+      (void) CloseBlob(image);
+      image=DestroyImage(image);
+      /*
+        Check magic.xml configuration file.
+      */
+      sans_exception=AcquireExceptionInfo();
+      magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
+      if ((magic_info != (const MagicInfo *) NULL) &&
+          (GetMagicName(magic_info) != (char *) NULL))
+        {
+          (void) CopyMagickString(image_info->magick,GetMagicName(magic_info),
+            MaxTextExtent);
+          magick_info=GetMagickInfo(image_info->magick,sans_exception);
+          if ((magick_info == (const MagickInfo *) NULL) ||
+              (GetMagickEndianSupport(magick_info) == MagickFalse))
+            image_info->endian=UndefinedEndian;
+          sans_exception=DestroyExceptionInfo(sans_exception);
+          return(MagickTrue);
+        }
+      magick_info=GetMagickInfo(image_info->magick,sans_exception);
+      if ((magick_info == (const MagickInfo *) NULL) ||
+          (GetMagickEndianSupport(magick_info) == MagickFalse))
+        image_info->endian=UndefinedEndian;
+      sans_exception=DestroyExceptionInfo(sans_exception);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e I n f o B l o b                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageInfoBlob() sets the image info blob member.
+%
+%  The format of the SetImageInfoBlob method is:
+%
+%      void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
+%        const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o blob: the blob.
+%
+%    o length: the blob length.
+%
+*/
+MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
+  const size_t length)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  image_info->blob=(void *) blob;
+  image_info->length=length;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e I n f o F i l e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageInfoFile() sets the image info file member.
+%
+%  The format of the SetImageInfoFile method is:
+%
+%      void SetImageInfoFile(ImageInfo *image_info,FILE *file)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o file: the file.
+%
+*/
+MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  image_info->file=file;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e M a s k                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageMask() associates a mask with the image.  The mask must be the same
+%  dimensions as the image.
+%
+%  The format of the SetImageMask method is:
+%
+%      MagickBooleanType SetImageMask(Image *image,const Image *mask)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o mask: the image mask.
+%
+*/
+MagickExport MagickBooleanType SetImageMask(Image *image,
+  const Image *mask)
+{
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (mask != (const Image *) NULL)
+    if ((mask->columns != image->columns) || (mask->rows != image->rows))
+      ThrowBinaryException(ImageError,"ImageSizeDiffers",image->filename);
+  if (image->mask != (Image *) NULL)
+    image->mask=DestroyImage(image->mask);
+  image->mask=NewImageList();
+  if (mask == (Image *) NULL)
+    return(MagickTrue);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  image->mask=CloneImage(mask,0,0,MagickTrue,&image->exception);
+  if (image->mask == (Image *) NULL)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S e t I m a g e O p a c i t y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageOpacity() sets the opacity levels of the image.
+%
+%  The format of the SetImageOpacity method is:
+%
+%      MagickBooleanType SetImageOpacity(Image *image,const Quantum opacity)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o opacity: the level of transparency: 0 is fully opaque and QuantumRange is
+%      fully transparent.
+%
+*/
+MagickExport MagickBooleanType SetImageOpacity(Image *image,
+  const Quantum opacity)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  image->matte=opacity != OpaqueAlpha ? MagickTrue : MagickFalse;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelAlpha(image,opacity,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e T y p e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageType() sets the type of image.  Choose from these types:
+%
+%        Bilevel        Grayscale       GrayscaleMatte
+%        Palette        PaletteMatte    TrueColor
+%        TrueColorMatte ColorSeparation ColorSeparationMatte
+%        OptimizeType
+%
+%  The format of the SetImageType method is:
+%
+%      MagickBooleanType SetImageType(Image *image,const ImageType type)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o type: Image type.
+%
+*/
+MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type)
+{
+  const char
+    *artifact;
+
+  ImageInfo
+    *image_info;
+
+  MagickBooleanType
+    status;
+
+  QuantizeInfo
+    *quantize_info;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  status=MagickTrue;
+  image_info=AcquireImageInfo();
+  image_info->dither=image->dither;
+  artifact=GetImageArtifact(image,"dither");
+  if (artifact != (const char *) NULL)
+    (void) SetImageOption(image_info,"dither",artifact);
+  switch (type)
+  {
+    case BilevelType:
+    {
+      if (IsImageGray(image,&image->exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace);
+      if (IsImageMonochrome(image,&image->exception) == MagickFalse)
+        {
+          quantize_info=AcquireQuantizeInfo(image_info);
+          quantize_info->number_colors=2;
+          quantize_info->colorspace=GRAYColorspace;
+          status=QuantizeImage(quantize_info,image);
+          quantize_info=DestroyQuantizeInfo(quantize_info);
+        }
+      image->matte=MagickFalse;
+      break;
+    }
+    case GrayscaleType:
+    {
+      if (IsImageGray(image,&image->exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace);
+      image->matte=MagickFalse;
+      break;
+    }
+    case GrayscaleMatteType:
+    {
+      if (IsImageGray(image,&image->exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace);
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      break;
+    }
+    case PaletteType:
+    {
+      if (image->colorspace != RGBColorspace)
+        status=TransformImageColorspace(image,RGBColorspace);
+      if ((image->storage_class == DirectClass) || (image->colors > 256))
+        {
+          quantize_info=AcquireQuantizeInfo(image_info);
+          quantize_info->number_colors=256;
+          status=QuantizeImage(quantize_info,image);
+          quantize_info=DestroyQuantizeInfo(quantize_info);
+        }
+      image->matte=MagickFalse;
+      break;
+    }
+    case PaletteBilevelMatteType:
+    {
+      if (image->colorspace != RGBColorspace)
+        status=TransformImageColorspace(image,RGBColorspace);
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      (void) BilevelImageChannel(image,AlphaChannel,(double) QuantumRange/2.0);
+      quantize_info=AcquireQuantizeInfo(image_info);
+      status=QuantizeImage(quantize_info,image);
+      quantize_info=DestroyQuantizeInfo(quantize_info);
+      break;
+    }
+    case PaletteMatteType:
+    {
+      if (image->colorspace != RGBColorspace)
+        status=TransformImageColorspace(image,RGBColorspace);
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      quantize_info=AcquireQuantizeInfo(image_info);
+      quantize_info->colorspace=TransparentColorspace;
+      status=QuantizeImage(quantize_info,image);
+      quantize_info=DestroyQuantizeInfo(quantize_info);
+      break;
+    }
+    case TrueColorType:
+    {
+      if (image->colorspace != RGBColorspace)
+        status=TransformImageColorspace(image,RGBColorspace);
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass);
+      image->matte=MagickFalse;
+      break;
+    }
+    case TrueColorMatteType:
+    {
+      if (image->colorspace != RGBColorspace)
+        status=TransformImageColorspace(image,RGBColorspace);
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass);
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      break;
+    }
+    case ColorSeparationType:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          if (image->colorspace != RGBColorspace)
+            status=TransformImageColorspace(image,RGBColorspace);
+          status=TransformImageColorspace(image,CMYKColorspace);
+        }
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass);
+      image->matte=MagickFalse;
+      break;
+    }
+    case ColorSeparationMatteType:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          if (image->colorspace != RGBColorspace)
+            status=TransformImageColorspace(image,RGBColorspace);
+          status=TransformImageColorspace(image,CMYKColorspace);
+        }
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass);
+      if (image->matte == MagickFalse)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+      break;
+    }
+    case OptimizeType:
+    case UndefinedType:
+      break;
+  }
+  image->type=type;
+  image_info=DestroyImageInfo(image_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e V i r t u a l P i x e l M e t h o d                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
+%  image and returns the previous setting.  A virtual pixel is any pixel access
+%  that is outside the boundaries of the image cache.
+%
+%  The format of the SetImageVirtualPixelMethod() method is:
+%
+%      VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
+%        const VirtualPixelMethod virtual_pixel_method)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: choose the type of virtual pixel.
+%
+*/
+MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  return(SetPixelCacheVirtualMethod(image,virtual_pixel_method));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S m u s h I m a g e s                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SmushImages() takes all images from the current image pointer to the end
+%  of the image list and smushes them to each other top-to-bottom if the
+%  stack parameter is true, otherwise left-to-right.
+%
+%  The current gravity setting now effects how the image is justified in the
+%  final image.
+%
+%  The format of the SmushImages method is:
+%
+%      Image *SmushImages(const Image *images,const MagickBooleanType stack,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image sequence.
+%
+%    o stack: A value other than 0 stacks the images top-to-bottom.
+%
+%    o offset: minimum distance in pixels between images.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static ssize_t SmushXGap(const Image *smush_image,const Image *images,
+  const ssize_t offset,ExceptionInfo *exception)
+{
+  CacheView
+    *left_view,
+    *right_view;
+
+  const Image
+    *left_image,
+    *right_image;
+
+  RectangleInfo
+    left_geometry,
+    right_geometry;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    y;
+
+  size_t
+    gap;
+
+  ssize_t
+    x;
+
+  if (images->previous == (Image *) NULL)
+    return(0);
+  right_image=images;
+  SetGeometry(smush_image,&right_geometry);
+  GravityAdjustGeometry(right_image->columns,right_image->rows,
+    right_image->gravity,&right_geometry);
+  left_image=images->previous;
+  SetGeometry(smush_image,&left_geometry);
+  GravityAdjustGeometry(left_image->columns,left_image->rows,
+    left_image->gravity,&left_geometry);
+  gap=right_image->columns;
+  left_view=AcquireCacheView(left_image);
+  right_view=AcquireCacheView(right_image);
+  for (y=0; y < (ssize_t) smush_image->rows; y++)
+  {
+    for (x=(ssize_t) left_image->columns-1; x > 0; x--)
+    {
+      p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
+      if ((p == (const Quantum *) NULL) ||
+          (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
+          ((left_image->columns-x-1) >= gap))
+        break;
+    }
+    i=(ssize_t) left_image->columns-x-1;
+    for (x=0; x < (ssize_t) right_image->columns; x++)
+    {
+      p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
+        exception);
+      if ((p == (const Quantum *) NULL) ||
+          (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
+          ((x+i) >= (ssize_t) gap))
+        break;
+    }
+    if ((x+i) < (ssize_t) gap)
+      gap=(size_t) (x+i);
+  }
+  right_view=DestroyCacheView(right_view);
+  left_view=DestroyCacheView(left_view);
+  if (y < (ssize_t) smush_image->rows)
+    return(offset);
+  return((ssize_t) gap-offset);
+}
+
+static ssize_t SmushYGap(const Image *smush_image,const Image *images,
+  const ssize_t offset,ExceptionInfo *exception)
+{
+  CacheView
+    *bottom_view,
+    *top_view;
+
+  const Image
+    *bottom_image,
+    *top_image;
+
+  RectangleInfo
+    bottom_geometry,
+    top_geometry;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    gap;
+
+  ssize_t
+    y;
+
+  if (images->previous == (Image *) NULL)
+    return(0);
+  bottom_image=images;
+  SetGeometry(smush_image,&bottom_geometry);
+  GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
+    bottom_image->gravity,&bottom_geometry);
+  top_image=images->previous;
+  SetGeometry(smush_image,&top_geometry);
+  GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
+    &top_geometry);
+  gap=bottom_image->rows;
+  top_view=AcquireCacheView(top_image);
+  bottom_view=AcquireCacheView(bottom_image);
+  for (x=0; x < (ssize_t) smush_image->columns; x++)
+  {
+    for (y=(ssize_t) top_image->rows-1; y > 0; y--)
+    {
+      p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
+      if ((p == (const Quantum *) NULL) ||
+          (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
+          ((top_image->rows-y-1) >= gap))
+        break;
+    }
+    i=(ssize_t) top_image->rows-y-1;
+    for (y=0; y < (ssize_t) bottom_image->rows; y++)
+    {
+      p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
+        exception);
+      if ((p == (const Quantum *) NULL) ||
+          (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
+          ((y+i) >= (ssize_t) gap))
+        break;
+    }
+    if ((y+i) < (ssize_t) gap)
+      gap=(size_t) (y+i);
+  }
+  bottom_view=DestroyCacheView(bottom_view);
+  top_view=DestroyCacheView(top_view);
+  if (x < (ssize_t) smush_image->columns)
+    return(offset);
+  return((ssize_t) gap-offset);
+}
+
+MagickExport Image *SmushImages(const Image *images,
+  const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
+{
+#define SmushImageTag  "Smush/Image"
+
+  CacheView
+    *smush_view;
+
+  const Image
+    *image;
+
+  Image
+    *smush_image;
+
+  MagickBooleanType
+    matte,
+    proceed,
+    status;
+
+  MagickOffsetType
+    n;
+
+  RectangleInfo
+    geometry;
+
+  register const Image
+    *next;
+
+  size_t
+    height,
+    number_images,
+    width;
+
+  ssize_t
+    x_offset,
+    y_offset;
+
+  /*
+    Compute maximum area of smushed area.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  image=images;
+  matte=image->matte;
+  number_images=1;
+  width=image->columns;
+  height=image->rows;
+  next=GetNextImageInList(image);
+  for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    if (next->matte != MagickFalse)
+      matte=MagickTrue;
+    number_images++;
+    if (stack != MagickFalse)
+      {
+        if (next->columns > width)
+          width=next->columns;
+        height+=next->rows;
+        if (next->previous != (Image *) NULL)
+          height+=offset;
+        continue;
+      }
+    width+=next->columns;
+    if (next->previous != (Image *) NULL)
+      width+=offset;
+    if (next->rows > height)
+      height=next->rows;
+  }
+  /*
+    Smush images.
+  */
+  smush_image=CloneImage(image,width,height,MagickTrue,exception);
+  if (smush_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(smush_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&smush_image->exception);
+      smush_image=DestroyImage(smush_image);
+      return((Image *) NULL);
+    }
+  smush_image->matte=matte;
+  (void) SetImageBackgroundColor(smush_image);
+  status=MagickTrue;
+  x_offset=0;
+  y_offset=0;
+  smush_view=AcquireCacheView(smush_image);
+  for (n=0; n < (MagickOffsetType) number_images; n++)
+  {
+    SetGeometry(smush_image,&geometry);
+    GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
+    if (stack != MagickFalse)
+      {
+        x_offset-=geometry.x;
+        y_offset-=SmushYGap(smush_image,image,offset,exception);
+      }
+    else
+      {
+        x_offset-=SmushXGap(smush_image,image,offset,exception);
+        y_offset-=geometry.y;
+      }
+    status=CompositeImage(smush_image,OverCompositeOp,image,x_offset,y_offset);
+    proceed=SetImageProgress(image,SmushImageTag,n,number_images);
+    if (proceed == MagickFalse)
+      break;
+    if (stack == MagickFalse)
+      {
+        x_offset+=(ssize_t) image->columns;
+        y_offset=0;
+      }
+    else
+      {
+        x_offset=0;
+        y_offset+=(ssize_t) image->rows;
+      }
+    image=GetNextImageInList(image);
+  }
+  if (stack == MagickFalse)
+    smush_image->columns=(size_t) x_offset;
+  else
+    smush_image->rows=(size_t) y_offset;
+  smush_view=DestroyCacheView(smush_view);
+  if (status == MagickFalse)
+    smush_image=DestroyImage(smush_image);
+  return(smush_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i p I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StripImage() strips an image of all profiles and comments.
+%
+%  The format of the StripImage method is:
+%
+%      MagickBooleanType StripImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType StripImage(Image *image)
+{
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  DestroyImageProfiles(image);
+  (void) DeleteImageProperty(image,"comment");
+  (void) DeleteImageProperty(image,"date:create");
+  (void) DeleteImageProperty(image,"date:modify");
+  (void) SetImageArtifact(image,"png:include-chunk","none,gama");
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S y n c I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncImage() initializes the red, green, and blue intensities of each pixel
+%  as defined by the colormap index.
+%
+%  The format of the SyncImage method is:
+%
+%      MagickBooleanType SyncImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+
+static inline Quantum PushColormapIndex(Image *image,
+  const size_t index,MagickBooleanType *range_exception)
+{
+  if (index < image->colors)
+    return((Quantum) index);
+  *range_exception=MagickTrue;
+  return((Quantum) 0);
+}
+
+MagickExport MagickBooleanType SyncImage(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    range_exception,
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (image->storage_class == DirectClass)
+    return(MagickFalse);
+  range_exception=MagickFalse;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    Quantum
+      index;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      index=PushColormapIndex(image,(size_t) GetPixelIndex(image,q),
+        &range_exception);
+      SetPixelPacket(image,image->colormap+(ssize_t) index,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  if (range_exception != MagickFalse)
+    (void) ThrowMagickException(&image->exception,GetMagickModule(),
+      CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c I m a g e S e t t i n g s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncImageSettings() sync the image info options to the image.
+%
+%  The format of the SyncImageSettings method is:
+%
+%      MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
+%        Image *image)
+%      MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
+%        Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+
+MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
+  Image *images)
+{
+  Image
+    *image;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  image=images;
+  for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
+    (void) SyncImageSettings(image_info,image);
+  (void) DeleteImageOption(image_info,"page");
+  return(MagickTrue);
+}
+
+MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
+  Image *image)
+{
+  char
+    property[MaxTextExtent];
+
+  const char
+    *option,
+    *value;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickStatusType
+    flags;
+
+  ResolutionType
+    units;
+
+  /*
+    Sync image options.
+  */
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  option=GetImageOption(image_info,"background");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&image->background_color,
+      &image->exception);
+  option=GetImageOption(image_info,"bias");
+  if (option != (const char *) NULL)
+    image->bias=SiPrefixToDouble(option,QuantumRange);
+  option=GetImageOption(image_info,"black-point-compensation");
+  if (option != (const char *) NULL)
+    image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
+      MagickBooleanOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"blue-primary");
+  if (option != (const char *) NULL)
+    {
+      flags=ParseGeometry(option,&geometry_info);
+      image->chromaticity.blue_primary.x=geometry_info.rho;
+      image->chromaticity.blue_primary.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
+    }
+  option=GetImageOption(image_info,"bordercolor");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&image->border_color,&image->exception);
+  option=GetImageOption(image_info,"colors");
+  if (option != (const char *) NULL)
+    image->colors=StringToUnsignedLong(option);
+  option=GetImageOption(image_info,"compose");
+  if (option != (const char *) NULL)
+    image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"compress");
+  if (option != (const char *) NULL)
+    image->compression=(CompressionType) ParseCommandOption(
+      MagickCompressOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"debug");
+  if (option != (const char *) NULL)
+    image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"density");
+  if (option != (const char *) NULL)
+    {
+      GeometryInfo
+        geometry_info;
+
+      /*
+        Set image density.
+      */
+      flags=ParseGeometry(option,&geometry_info);
+      image->x_resolution=geometry_info.rho;
+      image->y_resolution=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->y_resolution=image->x_resolution;
+    }
+  option=GetImageOption(image_info,"depth");
+  if (option != (const char *) NULL)
+    image->depth=StringToUnsignedLong(option);
+  option=GetImageOption(image_info,"endian");
+  if (option != (const char *) NULL)
+    image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"filter");
+  if (option != (const char *) NULL)
+    image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"fuzz");
+  if (option != (const char *) NULL)
+    image->fuzz=SiPrefixToDouble(option,QuantumRange);
+  option=GetImageOption(image_info,"gravity");
+  if (option != (const char *) NULL)
+    image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"green-primary");
+  if (option != (const char *) NULL)
+    {
+      flags=ParseGeometry(option,&geometry_info);
+      image->chromaticity.green_primary.x=geometry_info.rho;
+      image->chromaticity.green_primary.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
+    }
+  option=GetImageOption(image_info,"intent");
+  if (option != (const char *) NULL)
+    image->rendering_intent=(RenderingIntent) ParseCommandOption(
+      MagickIntentOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"interlace");
+  if (option != (const char *) NULL)
+    image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"interpolate");
+  if (option != (const char *) NULL)
+    image->interpolate=(InterpolatePixelMethod) ParseCommandOption(
+      MagickInterpolateOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"loop");
+  if (option != (const char *) NULL)
+    image->iterations=StringToUnsignedLong(option);
+  option=GetImageOption(image_info,"mattecolor");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&image->matte_color,&image->exception);
+  option=GetImageOption(image_info,"orient");
+  if (option != (const char *) NULL)
+    image->orientation=(OrientationType) ParseCommandOption(
+      MagickOrientationOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"page");
+  if (option != (const char *) NULL)
+    {
+      char
+        *geometry;
+
+      geometry=GetPageGeometry(option);
+      flags=ParseAbsoluteGeometry(geometry,&image->page);
+      geometry=DestroyString(geometry);
+    }
+  option=GetImageOption(image_info,"quality");
+  if (option != (const char *) NULL)
+    image->quality=StringToUnsignedLong(option);
+  option=GetImageOption(image_info,"red-primary");
+  if (option != (const char *) NULL)
+    {
+      flags=ParseGeometry(option,&geometry_info);
+      image->chromaticity.red_primary.x=geometry_info.rho;
+      image->chromaticity.red_primary.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
+    }
+  if (image_info->quality != UndefinedCompressionQuality)
+    image->quality=image_info->quality;
+  option=GetImageOption(image_info,"scene");
+  if (option != (const char *) NULL)
+    image->scene=StringToUnsignedLong(option);
+  option=GetImageOption(image_info,"taint");
+  if (option != (const char *) NULL)
+    image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
+      MagickFalse,option);
+  option=GetImageOption(image_info,"tile-offset");
+  if (option != (const char *) NULL)
+    {
+      char
+        *geometry;
+
+      geometry=GetPageGeometry(option);
+      flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
+      geometry=DestroyString(geometry);
+    }
+  option=GetImageOption(image_info,"transparent-color");
+  if (option != (const char *) NULL)
+    (void) QueryColorDatabase(option,&image->transparent_color,
+      &image->exception);
+  option=GetImageOption(image_info,"type");
+  if (option != (const char *) NULL)
+    image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
+      option);
+  option=GetImageOption(image_info,"units");
+  if (option != (const char *) NULL)
+    units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
+      MagickFalse,option);
+  else
+    units = image_info->units;
+  if (units != UndefinedResolution)
+    {
+      if (image->units != units)
+        switch (image->units)
+        {
+          case PixelsPerInchResolution:
+          {
+            if (units == PixelsPerCentimeterResolution)
+              {
+                image->x_resolution/=2.54;
+                image->y_resolution/=2.54;
+              }
+            break;
+          }
+          case PixelsPerCentimeterResolution:
+          {
+            if (units == PixelsPerInchResolution)
+              {
+                image->x_resolution=(double) ((size_t) (100.0*2.54*
+                  image->x_resolution+0.5))/100.0;
+                image->y_resolution=(double) ((size_t) (100.0*2.54*
+                  image->y_resolution+0.5))/100.0;
+              }
+            break;
+          }
+          default:
+            break;
+        }
+      image->units=units;
+    }
+  option=GetImageOption(image_info,"white-point");
+  if (option != (const char *) NULL)
+    {
+      flags=ParseGeometry(option,&geometry_info);
+      image->chromaticity.white_point.x=geometry_info.rho;
+      image->chromaticity.white_point.y=geometry_info.sigma;
+      if ((flags & SigmaValue) == 0)
+        image->chromaticity.white_point.y=image->chromaticity.white_point.x;
+    }
+  ResetImageOptionIterator(image_info);
+  for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
+  {
+    value=GetImageOption(image_info,option);
+    if (value != (const char *) NULL)
+      {
+        (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
+        (void) SetImageArtifact(image,property,value);
+      }
+    option=GetNextImageOption(image_info);
+  }
+  return(MagickTrue);
+}
diff --git a/MagickCore/image.h b/MagickCore/image.h
new file mode 100644
index 0000000..0c99204
--- /dev/null
+++ b/MagickCore/image.h
@@ -0,0 +1,552 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image methods.
+*/
+#ifndef _MAGICKCORE_IMAGE_H
+#define _MAGICKCORE_IMAGE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/color.h>
+
+#define OpaqueAlpha  ((Quantum) QuantumRange)
+#define TransparentAlpha  ((Quantum) 0UL)
+
+typedef enum
+{
+  UndefinedAlphaChannel,
+  ActivateAlphaChannel,
+  BackgroundAlphaChannel,
+  CopyAlphaChannel,
+  DeactivateAlphaChannel,
+  ExtractAlphaChannel,
+  OpaqueAlphaChannel,
+  SetAlphaChannel,
+  ShapeAlphaChannel,
+  TransparentAlphaChannel
+} AlphaChannelType;
+
+typedef enum
+{
+  UndefinedType,
+  BilevelType,
+  GrayscaleType,
+  GrayscaleMatteType,
+  PaletteType,
+  PaletteMatteType,
+  TrueColorType,
+  TrueColorMatteType,
+  ColorSeparationType,
+  ColorSeparationMatteType,
+  OptimizeType,
+  PaletteBilevelMatteType
+} ImageType;
+
+typedef enum
+{
+  UndefinedInterlace,
+  NoInterlace,
+  LineInterlace,
+  PlaneInterlace,
+  PartitionInterlace,
+  GIFInterlace,
+  JPEGInterlace,
+  PNGInterlace
+} InterlaceType;
+
+typedef enum
+{
+  UndefinedOrientation,
+  TopLeftOrientation,
+  TopRightOrientation,
+  BottomRightOrientation,
+  BottomLeftOrientation,
+  LeftTopOrientation,
+  RightTopOrientation,
+  RightBottomOrientation,
+  LeftBottomOrientation
+} OrientationType;
+
+typedef enum
+{
+  UndefinedResolution,
+  PixelsPerInchResolution,
+  PixelsPerCentimeterResolution
+} ResolutionType;
+
+typedef struct _PrimaryInfo
+{
+  double
+    x,
+    y,
+    z;
+} PrimaryInfo;
+
+typedef struct _SegmentInfo
+{
+  double
+    x1,
+    y1,
+    x2,
+    y2;
+} SegmentInfo;
+
+typedef enum
+{
+  UndefinedTransmitType,
+  FileTransmitType,
+  BlobTransmitType,
+  StreamTransmitType,
+  ImageTransmitType
+} TransmitType;
+
+typedef struct _ChromaticityInfo
+{
+  PrimaryInfo
+    red_primary,
+    green_primary,
+    blue_primary,
+    white_point;
+} ChromaticityInfo;
+
+#include "MagickCore/blob.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/compress.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/timer.h"
+
+struct _Image
+{
+  ClassType
+    storage_class;
+
+  ColorspaceType
+    colorspace;      /* colorspace of image data */
+
+  CompressionType
+    compression;     /* compression of image when read/write */
+
+  size_t
+    quality;         /* compression quality setting, meaning varies */
+
+  OrientationType
+    orientation;     /* photo orientation of image */
+
+  MagickBooleanType
+    taint,           /* has image been modified since reading */
+    matte;           /* is transparency channel defined and active */
+
+  size_t
+    columns,         /* physical size of image */
+    rows,
+    depth,           /* depth of image on read/write */
+    colors;          /* size of color table on read */
+
+  PixelPacket
+    *colormap,
+    background_color, /* current background color attribute */
+    border_color,     /* current bordercolor attribute */
+    matte_color;      /* current mattecolor attribute */
+
+  double
+    gamma;
+
+  ChromaticityInfo
+    chromaticity;
+
+  RenderingIntent
+    rendering_intent;
+
+  void
+    *profiles;
+
+  ResolutionType
+    units;          /* resolution/density  ppi or ppc */
+
+  char
+    *montage,
+    *directory,
+    *geometry;
+
+  ssize_t
+    offset;
+
+  double
+    x_resolution,   /* image resolution/density */
+    y_resolution;
+
+  RectangleInfo
+    page,           /* virtual canvas size and offset of image */
+    extract_info;
+
+  double
+    bias,
+    blur,
+    fuzz;           /* current color fuzz attribute */
+
+  FilterTypes
+    filter;         /* resize/distort filter to apply */
+
+  InterlaceType
+    interlace;
+
+  EndianType
+    endian;         /* raw data integer ordering on read/write */
+
+  GravityType
+    gravity;        /* Gravity attribute for positioning in image */
+
+  CompositeOperator
+    compose;        /* alpha composition method for layered images */
+
+  DisposeType
+    dispose;        /* GIF animation disposal method */
+
+  struct _Image
+    *clip_mask;
+
+  size_t
+    scene,          /* index of image in multi-image file */
+    delay;          /* Animation delay time */
+
+  ssize_t
+    ticks_per_second;  /* units for delay time, default 100 for GIF */
+
+  size_t
+    iterations,
+    total_colors;
+
+  ssize_t
+    start_loop;
+
+  InterpolatePixelMethod
+    interpolate;       /* Interpolation of color for between pixel lookups */
+
+  MagickBooleanType
+    black_point_compensation;
+
+  PixelPacket
+    transparent_color; /* color for 'transparent' color index in GIF */
+
+  struct _Image
+    *mask;
+
+  RectangleInfo
+    tile_offset;
+
+  void
+    *properties,       /* per image properities */
+    *artifacts;        /* per image sequence image artifacts */
+
+  ImageType
+    type;
+
+  MagickBooleanType
+    dither;            /* dithering method during color reduction */
+
+  MagickSizeType
+    extent;
+
+  MagickBooleanType
+    ping;
+
+  size_t
+    pixel_channels,
+    metacontent_extent;
+
+  PixelComponentMap
+    *component_map;
+
+  void
+    *cache;
+
+  ErrorInfo
+    error;
+
+  TimerInfo
+    timer;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  void
+    *client_data;
+
+  Ascii85Info
+    *ascii85;
+
+  ProfileInfo
+    color_profile,
+    iptc_profile,
+    *generic_profile;
+
+  char
+    filename[MaxTextExtent],   /* images input filename */
+    magick_filename[MaxTextExtent],
+    magick[MaxTextExtent];
+
+  size_t
+    magick_columns,
+    magick_rows;
+
+  BlobInfo
+    *blob;
+
+  ExceptionInfo
+    exception;        /* Error handling report */
+
+  MagickBooleanType
+    debug;            /* debug output attribute */
+
+  volatile ssize_t
+    reference_count;
+
+  SemaphoreInfo
+    *semaphore;
+
+  struct _Image
+    *previous,         /* Image sequence list links */
+    *list,
+    *next;
+
+  size_t
+    signature;
+};
+
+struct _ImageInfo
+{
+  CompressionType
+    compression;
+
+  OrientationType
+    orientation;
+
+  MagickBooleanType
+    temporary,
+    adjoin,
+    affirm,
+    antialias;
+
+  char
+    *size,
+    *extract,
+    *page,
+    *scenes;
+
+  size_t
+    scene,
+    number_scenes,
+    depth;
+
+  InterlaceType
+    interlace;
+
+  EndianType
+    endian;
+
+  ResolutionType
+    units;
+
+  size_t
+    quality;
+
+  char
+    *sampling_factor,
+    *server_name,
+    *font,
+    *texture,
+    *density;
+
+  double
+    pointsize,
+    fuzz;
+
+  PixelPacket
+    background_color,
+    border_color,
+    matte_color;
+
+  MagickBooleanType
+    dither,
+    monochrome;
+
+  size_t
+    colors;
+
+  ColorspaceType
+    colorspace;
+
+  ImageType
+    type;
+
+  PreviewType
+    preview_type;
+
+  ssize_t
+    group;
+
+  MagickBooleanType
+    ping,
+    verbose;
+
+  char
+    *view,
+    *authenticate;
+
+  ChannelType
+    channel;
+
+  void
+    *options;
+
+  VirtualPixelMethod
+    virtual_pixel_method;
+
+  PixelPacket
+    transparent_color;
+
+  void
+    *profile;
+
+  MagickBooleanType
+    synchronize;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  void
+    *client_data,
+    *cache;
+
+  StreamHandler
+    stream;
+
+  FILE
+    *file;
+
+  void
+    *blob;
+
+  size_t
+    length;
+
+  char
+    magick[MaxTextExtent],
+    unique[MaxTextExtent],
+    zero[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  MagickBooleanType
+    debug;
+
+  size_t
+    signature;
+};
+
+extern MagickExport ExceptionType
+  CatchImageException(Image *);
+
+extern MagickExport FILE
+  *GetImageInfoFile(const ImageInfo *);
+
+extern MagickExport Image
+  *AcquireImage(const ImageInfo *),
+  *AppendImages(const Image *,const MagickBooleanType,ExceptionInfo *),
+  *CloneImage(const Image *,const size_t,const size_t,const MagickBooleanType,
+    ExceptionInfo *),
+  *CombineImages(const Image *,const ChannelType,ExceptionInfo *),
+  *DestroyImage(Image *),
+  *GetImageClipMask(const Image *,ExceptionInfo *),
+  *GetImageMask(const Image *,ExceptionInfo *),
+  *NewMagickImage(const ImageInfo *,const size_t,const size_t,
+    const PixelInfo *),
+  *ReferenceImage(Image *),
+  *SeparateImages(const Image *,const ChannelType,ExceptionInfo *),
+  *SmushImages(const Image *,const MagickBooleanType,const ssize_t,
+    ExceptionInfo *);
+
+extern MagickExport ImageInfo
+  *AcquireImageInfo(void),
+  *CloneImageInfo(const ImageInfo *),
+  *DestroyImageInfo(ImageInfo *);
+
+extern MagickExport MagickBooleanType
+  ClipImage(Image *),
+  ClipImagePath(Image *,const char *,const MagickBooleanType),
+  GetImageAlphaChannel(const Image *),
+  IsTaintImage(const Image *),
+  IsMagickConflict(const char *),
+  IsHighDynamicRangeImage(const Image *,ExceptionInfo *),
+  IsImageObject(const Image *),
+  ListMagickInfo(FILE *,ExceptionInfo *),
+  ModifyImage(Image **,ExceptionInfo *),
+  ResetImagePage(Image *,const char *),
+  SeparateImageChannel(Image *,const ChannelType),
+  SetImageAlphaChannel(Image *,const AlphaChannelType),
+  SetImageBackgroundColor(Image *),
+  SetImageClipMask(Image *,const Image *),
+  SetImageColor(Image *,const PixelInfo *),
+  SetImageExtent(Image *,const size_t,const size_t),
+  SetImageInfo(ImageInfo *,const unsigned int,ExceptionInfo *),
+  SetImageMask(Image *,const Image *),
+  SetImageOpacity(Image *,const Quantum),
+  SetImageStorageClass(Image *,const ClassType),
+  SetImageType(Image *,const ImageType),
+  StripImage(Image *),
+  SyncImage(Image *),
+  SyncImageSettings(const ImageInfo *,Image *),
+  SyncImagesSettings(ImageInfo *,Image *);
+
+extern MagickExport size_t
+  InterpretImageFilename(const ImageInfo *,Image *,const char *,int,char *);
+
+extern MagickExport ssize_t
+  GetImageReferenceCount(Image *);
+
+extern MagickExport VirtualPixelMethod
+  GetImageVirtualPixelMethod(const Image *),
+  SetImageVirtualPixelMethod(const Image *,const VirtualPixelMethod);
+
+extern MagickExport void
+  AcquireNextImage(const ImageInfo *,Image *),
+  DestroyImagePixels(Image *),
+  DisassociateImageStream(Image *),
+  GetImageException(Image *,ExceptionInfo *),
+  GetImageInfo(ImageInfo *),
+  SetImageInfoBlob(ImageInfo *,const void *,const size_t),
+  SetImageInfoFile(ImageInfo *,FILE *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/layer.c b/MagickCore/layer.c
new file mode 100644
index 0000000..b4e440d
--- /dev/null
+++ b/MagickCore/layer.c
@@ -0,0 +1,2034 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                     L       AAA   Y   Y  EEEEE  RRRR                        %
+%                     L      A   A   Y Y   E      R   R                       %
+%                     L      AAAAA    Y    EEE    RRRR                        %
+%                     L      A   A    Y    E      R R                         %
+%                     LLLLL  A   A    Y    EEEEE  R  R                        %
+%                                                                             %
+%                      MagickCore Image Layering Methods                      %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                              Anthony Thyssen                                %
+%                               January 2006                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/transform.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     C l e a r B o u n d s                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClearBounds() Clear the area specified by the bounds in an image to
+%  transparency.  This typically used to handle Background Disposal
+%  for the previous frame in an animation sequence.
+%
+%  WARNING: no bounds checks are performed, except for the null or
+%  missed image, for images that don't change. in all other cases
+%  bound must fall within the image.
+%
+%  The format is:
+%
+%      void ClearBounds(Image *image,RectangleInfo *bounds)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to had the area cleared in
+%
+%    o bounds: the area to be clear within the imag image
+%
+*/
+static void ClearBounds(Image *image,RectangleInfo *bounds)
+{
+  ExceptionInfo
+    *exception;
+
+  ssize_t
+    y;
+
+  if (bounds->x < 0)
+    return;
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  exception=(&image->exception);
+  for (y=0; y < (ssize_t) bounds->height; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=GetAuthenticPixels(image,bounds->x,bounds->y+y,bounds->width,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) bounds->width; x++)
+    {
+      SetPixelAlpha(image,TransparentAlpha,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      break;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     I s B o u n d s C l e a r e d                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsBoundsCleared() tests whether any pixel in the bounds given, gets cleared
+%  when going from the first image to the second image.  This typically used
+%  to check if a proposed disposal method will work successfully to generate
+%  the second frame image from the first disposed form of the previous frame.
+%
+%  The format is:
+%
+%      MagickBooleanType IsBoundsCleared(const Image *image1,
+%        const Image *image2,RectangleInfo bounds,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image1, image 2: the images to check for cleared pixels
+%
+%    o bounds: the area to be clear within the imag image
+%
+%    o exception: return any errors or warnings in this structure.
+%
+%  WARNING: no bounds checks are performed, except for the null or
+%  missed image, for images that don't change. in all other cases
+%  bound must fall within the image.
+%
+*/
+static MagickBooleanType IsBoundsCleared(const Image *image1,
+  const Image *image2,RectangleInfo *bounds,ExceptionInfo *exception)
+{
+  register ssize_t
+    x;
+
+  register const Quantum
+    *p,
+    *q;
+
+  ssize_t
+    y;
+
+#if 0
+  assert(image1->matte==MagickTrue);
+  assert(image2->matte==MagickTrue);
+#endif
+
+  if ( bounds->x< 0 ) return(MagickFalse);
+
+  for (y=0; y < (ssize_t) bounds->height; y++)
+  {
+    p=GetVirtualPixels(image1,bounds->x,bounds->y+y,bounds->width,1,
+      exception);
+    q=GetVirtualPixels(image2,bounds->x,bounds->y+y,bounds->width,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      break;
+    for (x=0; x < (ssize_t) bounds->width; x++)
+    {
+      if ((GetPixelAlpha(image1,p) <= (Quantum) (QuantumRange/2)) &&
+          (GetPixelAlpha(image1,q) > (Quantum) (QuantumRange/2)))
+        break;
+      p+=GetPixelChannels(image1);
+      q++;
+    }
+    if (x < (ssize_t) bounds->width)
+      break;
+  }
+  return(y < (ssize_t) bounds->height ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o a l e s c e I m a g e s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CoalesceImages() composites a set of images while respecting any page
+%  offsets and disposal methods.  GIF, MIFF, and MNG animation sequences
+%  typically start with an image background and each subsequent image
+%  varies in size and offset.  A new image sequence is returned with all
+%  images the same size as the first images virtual canvas and composited
+%  with the next image in the sequence.
+%
+%  The format of the CoalesceImages method is:
+%
+%      Image *CoalesceImages(Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image sequence.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
+{
+  Image
+    *coalesce_image,
+    *dispose_image,
+    *previous;
+
+  register Image
+    *next;
+
+  RectangleInfo
+    bounds;
+
+  /*
+    Coalesce the image sequence.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  /* initialise first image */
+  next=GetFirstImageInList(image);
+  bounds=next->page;
+  if (bounds.width == 0)
+    {
+      bounds.width=next->columns;
+      if (bounds.x > 0)
+        bounds.width+=bounds.x;
+    }
+  if (bounds.height == 0)
+    {
+      bounds.height=next->rows;
+      if (bounds.y > 0)
+        bounds.height+=bounds.y;
+    }
+  bounds.x=0;
+  bounds.y=0;
+  coalesce_image=CloneImage(next,bounds.width,bounds.height,MagickTrue,
+    exception);
+  if (coalesce_image == (Image *) NULL)
+    return((Image *) NULL);
+  coalesce_image->page=bounds;
+  coalesce_image->dispose=NoneDispose;
+  coalesce_image->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(coalesce_image);
+  /*
+    Coalesce rest of the images.
+  */
+  dispose_image=CloneImage(coalesce_image,0,0,MagickTrue,exception);
+  (void) CompositeImage(coalesce_image,CopyCompositeOp,next,next->page.x,
+    next->page.y);
+  next=GetNextImageInList(next);
+  for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
+  {
+    /*
+      Determine the bounds that was overlaid in the previous image.
+    */
+    previous=GetPreviousImageInList(next);
+    bounds=previous->page;
+    bounds.width=previous->columns;
+    bounds.height=previous->rows;
+    if (bounds.x < 0)
+      {
+        bounds.width+=bounds.x;
+        bounds.x=0;
+      }
+    if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) coalesce_image->columns)
+      bounds.width=coalesce_image->columns-bounds.x;
+    if (bounds.y < 0)
+      {
+        bounds.height+=bounds.y;
+        bounds.y=0;
+      }
+    if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) coalesce_image->rows)
+      bounds.height=coalesce_image->rows-bounds.y;
+    /*
+      Replace the dispose image with the new coalesced image.
+    */
+    if (GetPreviousImageInList(next)->dispose != PreviousDispose)
+      {
+        dispose_image=DestroyImage(dispose_image);
+        dispose_image=CloneImage(coalesce_image,0,0,MagickTrue,exception);
+        if (dispose_image == (Image *) NULL)
+          {
+            coalesce_image=DestroyImageList(coalesce_image);
+            return((Image *) NULL);
+          }
+      }
+    /*
+      Clear the overlaid area of the coalesced bounds for background disposal
+    */
+    if (next->previous->dispose == BackgroundDispose)
+      ClearBounds(dispose_image, &bounds);
+    /*
+      Next image is the dispose image, overlaid with next frame in sequence.
+    */
+    coalesce_image->next=CloneImage(dispose_image,0,0,MagickTrue,exception);
+    coalesce_image->next->previous=coalesce_image;
+    previous=coalesce_image;
+    coalesce_image=GetNextImageInList(coalesce_image);
+    coalesce_image->matte=MagickTrue;
+    (void) CompositeImage(coalesce_image,next->matte != MagickFalse ?
+      OverCompositeOp : CopyCompositeOp,next,next->page.x,next->page.y);
+    (void) CloneImageProfiles(coalesce_image,next);
+    (void) CloneImageProperties(coalesce_image,next);
+    (void) CloneImageArtifacts(coalesce_image,next);
+    coalesce_image->page=previous->page;
+    /*
+      If a pixel goes opaque to transparent, use background dispose.
+    */
+    if (IsBoundsCleared(previous,coalesce_image,&bounds,exception))
+      coalesce_image->dispose=BackgroundDispose;
+    else
+      coalesce_image->dispose=NoneDispose;
+    previous->dispose=coalesce_image->dispose;
+  }
+  dispose_image=DestroyImage(dispose_image);
+  return(GetFirstImageInList(coalesce_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D i s p o s e I m a g e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DisposeImages() returns the coalesced frames of a GIF animation as it would
+%  appear after the GIF dispose method of that frame has been applied.  That
+%  is it returned the appearance of each frame before the next is overlaid.
+%
+%  The format of the DisposeImages method is:
+%
+%      Image *DisposeImages(Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image sequence.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *DisposeImages(const Image *image,ExceptionInfo *exception)
+{
+  Image
+    *dispose_image,
+    *dispose_images;
+
+  register Image
+    *curr;
+
+  RectangleInfo
+    bounds;
+
+  /*
+    Run the image through the animation sequence
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  curr=GetFirstImageInList(image);
+  dispose_image=CloneImage(curr,curr->page.width,curr->page.height,MagickTrue,
+    exception);
+  if (dispose_image == (Image *) NULL)
+    return((Image *) NULL);
+  dispose_image->page=curr->page;
+  dispose_image->page.x=0;
+  dispose_image->page.y=0;
+  dispose_image->dispose=NoneDispose;
+  dispose_image->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(dispose_image);
+  dispose_images=NewImageList();
+  for ( ; curr != (Image *) NULL; curr=GetNextImageInList(curr))
+  {
+    Image
+      *current_image;
+
+    /*
+      Overlay this frame's image over the previous disposal image.
+    */
+    current_image=CloneImage(dispose_image,0,0,MagickTrue,exception);
+    if (current_image == (Image *) NULL)
+      {
+        dispose_images=DestroyImageList(dispose_images);
+        dispose_image=DestroyImage(dispose_image);
+        return((Image *) NULL);
+      }
+    (void) CompositeImage(current_image,curr->matte != MagickFalse ?
+      OverCompositeOp : CopyCompositeOp,curr,curr->page.x,curr->page.y);
+
+    /*
+      Handle Background dispose: image is displayed for the delay period.
+    */
+    if (curr->dispose == BackgroundDispose)
+      {
+        bounds=curr->page;
+        bounds.width=curr->columns;
+        bounds.height=curr->rows;
+        if (bounds.x < 0)
+          {
+            bounds.width+=bounds.x;
+            bounds.x=0;
+          }
+        if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) current_image->columns)
+          bounds.width=current_image->columns-bounds.x;
+        if (bounds.y < 0)
+          {
+            bounds.height+=bounds.y;
+            bounds.y=0;
+          }
+        if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) current_image->rows)
+          bounds.height=current_image->rows-bounds.y;
+        ClearBounds(current_image,&bounds);
+      }
+    /*
+      Select the appropriate previous/disposed image.
+    */
+    if (curr->dispose == PreviousDispose)
+      current_image=DestroyImage(current_image);
+    else
+      {
+        dispose_image=DestroyImage(dispose_image);
+        dispose_image=current_image;
+        current_image=(Image *)NULL;
+      }
+    /*
+      Save the dispose image just calculated for return.
+    */
+    {
+      Image
+        *dispose;
+
+      dispose=CloneImage(dispose_image,0,0,MagickTrue,exception);
+      if (dispose == (Image *) NULL)
+        {
+          dispose_images=DestroyImageList(dispose_images);
+          dispose_image=DestroyImage(dispose_image);
+          return((Image *) NULL);
+        }
+      (void) CloneImageProfiles(dispose,curr);
+      (void) CloneImageProperties(dispose,curr);
+      (void) CloneImageArtifacts(dispose,curr);
+      dispose->page.x=0;
+      dispose->page.y=0;
+      dispose->dispose=curr->dispose;
+      AppendImageToList(&dispose_images,dispose);
+    }
+  }
+  dispose_image=DestroyImage(dispose_image);
+  return(GetFirstImageInList(dispose_images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     C o m p a r e P i x e l s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ComparePixels() Compare the two pixels and return true if the pixels
+%  differ according to the given LayerType comparision method.
+%
+%  This currently only used internally by CompareImageBounds(). It is
+%  doubtful that this sub-routine will be useful outside this module.
+%
+%  The format of the ComparePixels method is:
+%
+%      MagickBooleanType *ComparePixels(const ImageLayerMethod method,
+%        const PixelInfo *p,const PixelInfo *q)
+%
+%  A description of each parameter follows:
+%
+%    o method: What differences to look for. Must be one of
+%              CompareAnyLayer, CompareClearLayer, CompareOverlayLayer.
+%
+%    o p, q: the pixels to test for appropriate differences.
+%
+*/
+
+static MagickBooleanType ComparePixels(const ImageLayerMethod method,
+  const PixelInfo *p,const PixelInfo *q)
+{
+  MagickRealType
+    o1,
+    o2;
+
+  /*
+    Any change in pixel values
+  */
+  if (method == CompareAnyLayer)
+    return((MagickBooleanType)(IsFuzzyEquivalencePixelInfo(p,q) == MagickFalse));
+
+  o1 = (p->matte != MagickFalse) ? p->alpha : OpaqueAlpha;
+  o2 = (q->matte != MagickFalse) ? q->alpha : OpaqueAlpha;
+
+  /*
+    Pixel goes from opaque to transprency
+  */
+  if (method == CompareClearLayer)
+    return((MagickBooleanType) ( (o1 <= ((MagickRealType) QuantumRange/2.0)) &&
+      (o2 > ((MagickRealType) QuantumRange/2.0)) ) );
+
+  /*
+    overlay would change first pixel by second
+  */
+  if (method == CompareOverlayLayer)
+    {
+      if (o2 > ((MagickRealType) QuantumRange/2.0))
+        return MagickFalse;
+      return((MagickBooleanType) (IsFuzzyEquivalencePixelInfo(p,q) == MagickFalse));
+    }
+  return(MagickFalse);
+}
+
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     C o m p a r e I m a g e B o u n d s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareImageBounds() Given two images return the smallest rectangular area
+%  by which the two images differ, accourding to the given 'Compare...'
+%  layer method.
+%
+%  This currently only used internally in this module, but may eventually
+%  be used by other modules.
+%
+%  The format of the CompareImageBounds method is:
+%
+%      RectangleInfo *CompareImageBounds(const ImageLayerMethod method,
+%        const Image *image1, const Image *image2, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o method: What differences to look for. Must be one of CompareAnyLayer,
+%      CompareClearLayer, CompareOverlayLayer.
+%
+%    o image1, image2: the two images to compare.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static RectangleInfo CompareImageBounds(const Image *image1,const Image *image2,
+  const ImageLayerMethod method,ExceptionInfo *exception)
+{
+  RectangleInfo
+    bounds;
+
+  PixelInfo
+    pixel1,
+    pixel2;
+
+  register const Quantum
+    *p,
+    *q;
+
+  register ssize_t
+    x;
+
+  ssize_t
+    y;
+
+  /*
+    Set bounding box of the differences between images.
+  */
+  GetPixelInfo(image1,&pixel1);
+  GetPixelInfo(image2,&pixel2);
+  for (x=0; x < (ssize_t) image1->columns; x++)
+  {
+    p=GetVirtualPixels(image1,x,0,1,image1->rows,exception);
+    q=GetVirtualPixels(image2,x,0,1,image2->rows,exception);
+    if ((p == (const Quantum *) NULL) ||
+        (q == (const Quantum *) NULL))
+      break;
+    for (y=0; y < (ssize_t) image1->rows; y++)
+    {
+      SetPixelInfo(image1,p,&pixel1);
+      SetPixelInfo(image2,q,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p+=GetPixelChannels(image1);
+      q++;
+    }
+    if (y < (ssize_t) image1->rows)
+      break;
+  }
+  if (x >= (ssize_t) image1->columns)
+    {
+      /*
+        Images are identical, return a null image.
+      */
+      bounds.x=-1;
+      bounds.y=-1;
+      bounds.width=1;
+      bounds.height=1;
+      return(bounds);
+    }
+  bounds.x=x;
+  for (x=(ssize_t) image1->columns-1; x >= 0; x--)
+  {
+    p=GetVirtualPixels(image1,x,0,1,image1->rows,exception);
+    q=GetVirtualPixels(image2,x,0,1,image2->rows,exception);
+    if ((p == (const Quantum *) NULL) ||
+        (q == (const Quantum *) NULL))
+      break;
+    for (y=0; y < (ssize_t) image1->rows; y++)
+    {
+      SetPixelInfo(image1,p,&pixel1);
+      SetPixelInfo(image2,q,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p+=GetPixelChannels(image1);
+      q++;
+    }
+    if (y < (ssize_t) image1->rows)
+      break;
+  }
+  bounds.width=(size_t) (x-bounds.x+1);
+  for (y=0; y < (ssize_t) image1->rows; y++)
+  {
+    p=GetVirtualPixels(image1,0,y,image1->columns,1,exception);
+    q=GetVirtualPixels(image2,0,y,image2->columns,1,exception);
+    if ((p == (const Quantum *) NULL) ||
+        (q == (const Quantum *) NULL))
+      break;
+    for (x=0; x < (ssize_t) image1->columns; x++)
+    {
+      SetPixelInfo(image1,p,&pixel1);
+      SetPixelInfo(image2,q,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p+=GetPixelChannels(image1);
+      q++;
+    }
+    if (x < (ssize_t) image1->columns)
+      break;
+  }
+  bounds.y=y;
+  for (y=(ssize_t) image1->rows-1; y >= 0; y--)
+  {
+    p=GetVirtualPixels(image1,0,y,image1->columns,1,exception);
+    q=GetVirtualPixels(image2,0,y,image2->columns,1,exception);
+    if ((p == (const Quantum *) NULL) ||
+        (q == (const Quantum *) NULL))
+      break;
+    for (x=0; x < (ssize_t) image1->columns; x++)
+    {
+      SetPixelInfo(image1,p,&pixel1);
+      SetPixelInfo(image2,q,&pixel2);
+      if (ComparePixels(method,&pixel1,&pixel2))
+        break;
+      p+=GetPixelChannels(image1);
+      q++;
+    }
+    if (x < (ssize_t) image1->columns)
+      break;
+  }
+  bounds.height=(size_t) (y-bounds.y+1);
+  return(bounds);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o m p a r e I m a g e L a y e r s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareImageLayers() compares each image with the next in a sequence and
+%  returns the minimum bounding region of all the pixel differences (of the
+%  ImageLayerMethod specified) it discovers.
+%
+%  Images do NOT have to be the same size, though it is best that all the
+%  images are 'coalesced' (images are all the same size, on a flattened
+%  canvas, so as to represent exactly how an specific frame should look).
+%
+%  No GIF dispose methods are applied, so GIF animations must be coalesced
+%  before applying this image operator to find differences to them.
+%
+%  The format of the CompareImageLayers method is:
+%
+%      Image *CompareImageLayers(const Image *images,
+%        const ImageLayerMethod method,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o method: the layers type to compare images with. Must be one of...
+%              CompareAnyLayer, CompareClearLayer, CompareOverlayLayer.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *CompareImageLayers(const Image *image,
+  const ImageLayerMethod method, ExceptionInfo *exception)
+{
+  Image
+    *image_a,
+    *image_b,
+    *layers;
+
+  RectangleInfo
+    *bounds;
+
+  register const Image
+    *next;
+
+  register ssize_t
+    i;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert((method == CompareAnyLayer) ||
+         (method == CompareClearLayer) ||
+         (method == CompareOverlayLayer));
+  /*
+    Allocate bounds memory.
+  */
+  next=GetFirstImageInList(image);
+  bounds=(RectangleInfo *) AcquireQuantumMemory((size_t)
+    GetImageListLength(next),sizeof(*bounds));
+  if (bounds == (RectangleInfo *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  /*
+    Set up first comparision images.
+  */
+  image_a=CloneImage(next,next->page.width,next->page.height,
+    MagickTrue,exception);
+  if (image_a == (Image *) NULL)
+    {
+      bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+      return((Image *) NULL);
+    }
+  image_a->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(image_a);
+  image_a->page=next->page;
+  image_a->page.x=0;
+  image_a->page.y=0;
+  (void) CompositeImage(image_a,CopyCompositeOp,next,next->page.x,next->page.y);
+  /*
+    Compute the bounding box of changes for the later images
+  */
+  i=0;
+  next=GetNextImageInList(next);
+  for ( ; next != (const Image *) NULL; next=GetNextImageInList(next))
+  {
+    image_b=CloneImage(image_a,0,0,MagickTrue,exception);
+    if (image_b == (Image *) NULL)
+      {
+        image_a=DestroyImage(image_a);
+        bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+        return((Image *) NULL);
+      }
+    (void) CompositeImage(image_a,CopyCompositeOp,next,next->page.x,
+                           next->page.y);
+    bounds[i]=CompareImageBounds(image_b,image_a,method,exception);
+
+    image_b=DestroyImage(image_b);
+    i++;
+  }
+  image_a=DestroyImage(image_a);
+  /*
+    Clone first image in sequence.
+  */
+  next=GetFirstImageInList(image);
+  layers=CloneImage(next,0,0,MagickTrue,exception);
+  if (layers == (Image *) NULL)
+    {
+      bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+      return((Image *) NULL);
+    }
+  /*
+    Deconstruct the image sequence.
+  */
+  i=0;
+  next=GetNextImageInList(next);
+  for ( ; next != (const Image *) NULL; next=GetNextImageInList(next))
+  {
+    image_a=CloneImage(next,0,0,MagickTrue,exception);
+    if (image_a == (Image *) NULL)
+      break;
+    image_b=CropImage(image_a,&bounds[i],exception);
+    image_a=DestroyImage(image_a);
+    if (image_b == (Image *) NULL)
+      break;
+    AppendImageToList(&layers,image_b);
+    i++;
+  }
+  bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+  if (next != (Image *) NULL)
+    {
+      layers=DestroyImageList(layers);
+      return((Image *) NULL);
+    }
+  return(GetFirstImageInList(layers));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     O p t i m i z e L a y e r F r a m e s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OptimizeLayerFrames() takes a coalesced GIF animation, and compares each
+%  frame against the three different 'disposal' forms of the previous frame.
+%  From this it then attempts to select the smallest cropped image and
+%  disposal method needed to reproduce the resulting image.
+%
+%  Note that this not easy, and may require the expansion of the bounds
+%  of previous frame, simply clear pixels for the next animation frame to
+%  transparency according to the selected dispose method.
+%
+%  The format of the OptimizeLayerFrames method is:
+%
+%      Image *OptimizeLayerFrames(const Image *image,
+%        const ImageLayerMethod method, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o method: the layers technique to optimize with. Must be one of...
+%      OptimizeImageLayer, or  OptimizePlusLayer.  The Plus form allows
+%      the addition of extra 'zero delay' frames to clear pixels from
+%      the previous frame, and the removal of frames that done change,
+%      merging the delay times together.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+/*
+  Define a 'fake' dispose method where the frame is duplicated, (for
+  OptimizePlusLayer) with a extra zero time delay frame which does a
+  BackgroundDisposal to clear the pixels that need to be cleared.
+*/
+#define DupDispose  ((DisposeType)9)
+/*
+  Another 'fake' dispose method used to removed frames that don't change.
+*/
+#define DelDispose  ((DisposeType)8)
+
+#define DEBUG_OPT_FRAME 0
+
+static Image *OptimizeLayerFrames(const Image *image,
+  const ImageLayerMethod method, ExceptionInfo *exception)
+{
+  ExceptionInfo
+    *sans_exception;
+
+  Image
+    *prev_image,
+    *dup_image,
+    *bgnd_image,
+    *optimized_image;
+
+  RectangleInfo
+    try_bounds,
+    bgnd_bounds,
+    dup_bounds,
+    *bounds;
+
+  MagickBooleanType
+    add_frames,
+    try_cleared,
+    cleared;
+
+  DisposeType
+    *disposals;
+
+  register const Image
+    *curr;
+
+  register ssize_t
+    i;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert(method == OptimizeLayer ||
+         method == OptimizeImageLayer ||
+         method == OptimizePlusLayer);
+
+  /*
+    Are we allowed to add/remove frames from animation
+  */
+  add_frames=method == OptimizePlusLayer ? MagickTrue : MagickFalse;
+  /*
+    Ensure  all the images are the same size
+  */
+  curr=GetFirstImageInList(image);
+  for (; curr != (Image *) NULL; curr=GetNextImageInList(curr))
+  {
+    if ((curr->columns != image->columns) || (curr->rows != image->rows))
+      ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
+    /*
+      FUTURE: also check that image is also fully coalesced (full page)
+      Though as long as they are the same size it should not matter.
+    */
+  }
+  /*
+    Allocate memory (times 2 if we allow the use of frame duplications)
+  */
+  curr=GetFirstImageInList(image);
+  bounds=(RectangleInfo *) AcquireQuantumMemory((size_t)
+    GetImageListLength(curr),(add_frames != MagickFalse ? 2UL : 1UL)*
+    sizeof(*bounds));
+  if (bounds == (RectangleInfo *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  disposals=(DisposeType *) AcquireQuantumMemory((size_t)
+    GetImageListLength(image),(add_frames != MagickFalse ? 2UL : 1UL)*
+    sizeof(*disposals));
+  if (disposals == (DisposeType *) NULL)
+    {
+      bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Initialise Previous Image as fully transparent
+  */
+  prev_image=CloneImage(curr,curr->page.width,curr->page.height,
+    MagickTrue,exception);
+  if (prev_image == (Image *) NULL)
+    {
+      bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+      disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+      return((Image *) NULL);
+    }
+  prev_image->page=curr->page;  /* ERROR: <-- should not be need, but is! */
+  prev_image->page.x=0;
+  prev_image->page.y=0;
+  prev_image->dispose=NoneDispose;
+
+  prev_image->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(prev_image);
+  /*
+    Figure out the area of overlay of the first frame
+    No pixel could be cleared as all pixels are already cleared.
+  */
+#if DEBUG_OPT_FRAME
+  i=0;
+  (void) FormatLocaleFile(stderr, "frame %.20g :-\n", (double) i);
+#endif
+  disposals[0]=NoneDispose;
+  bounds[0]=CompareImageBounds(prev_image,curr,CompareAnyLayer,exception);
+#if DEBUG_OPT_FRAME
+  (void) FormatLocaleFile(stderr, "overlay: %.20gx%.20g%+.20g%+.20g\n\n",
+    (double) bounds[i].width,(double) bounds[i].height,
+    (double) bounds[i].x,(double) bounds[i].y );
+#endif
+  /*
+    Compute the bounding box of changes for each pair of images.
+  */
+  i=1;
+  bgnd_image=(Image *)NULL;
+  dup_image=(Image *)NULL;
+  dup_bounds.width=0;
+  dup_bounds.height=0;
+  dup_bounds.x=0;
+  dup_bounds.y=0;
+  curr=GetNextImageInList(curr);
+  for ( ; curr != (const Image *) NULL; curr=GetNextImageInList(curr))
+  {
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "frame %.20g :-\n", (double) i);
+#endif
+    /*
+      Assume none disposal is the best
+    */
+    bounds[i]=CompareImageBounds(curr->previous,curr,CompareAnyLayer,exception);
+    cleared=IsBoundsCleared(curr->previous,curr,&bounds[i],exception);
+    disposals[i-1]=NoneDispose;
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "overlay: %.20gx%.20g%+.20g%+.20g%s%s\n",
+         (double) bounds[i].width,(double) bounds[i].height,
+         (double) bounds[i].x,(double) bounds[i].y,
+         bounds[i].x < 0?"  (unchanged)":"",
+         cleared?"  (pixels cleared)":"");
+#endif
+    if ( bounds[i].x < 0 ) {
+      /*
+        Image frame is exactly the same as the previous frame!
+        If not adding frames leave it to be cropped down to a null image.
+        Otherwise mark previous image for deleted, transfering its crop bounds
+        to the current image.
+      */
+      if ( add_frames && i>=2 ) {
+        disposals[i-1]=DelDispose;
+        disposals[i]=NoneDispose;
+        bounds[i]=bounds[i-1];
+        i++;
+        continue;
+      }
+    }
+    else
+      {
+        /*
+          Compare a none disposal against a previous disposal
+        */
+        try_bounds=CompareImageBounds(prev_image,curr,CompareAnyLayer,exception);
+        try_cleared=IsBoundsCleared(prev_image,curr,&try_bounds,exception);
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "test_prev: %.20gx%.20g%+.20g%+.20g%s\n",
+         (double) try_bounds.width,(double) try_bounds.height,
+         (double) try_bounds.x,(double) try_bounds.y,
+         try_cleared?"  (pixels were cleared)":"");
+#endif
+        if ( (!try_cleared && cleared ) ||
+                try_bounds.width * try_bounds.height
+                    <  bounds[i].width * bounds[i].height )
+          {
+            cleared=try_cleared;
+            bounds[i]=try_bounds;
+            disposals[i-1]=PreviousDispose;
+#if DEBUG_OPT_FRAME
+            (void) FormatLocaleFile(stderr, "previous: accepted\n");
+          } else {
+            (void) FormatLocaleFile(stderr, "previous: rejected\n");
+#endif
+          }
+
+        /*
+          If we are allowed lets try a complex frame duplication.
+          It is useless if the previous image already clears pixels correctly.
+          This method will always clear all the pixels that need to be cleared.
+        */
+        dup_bounds.width=dup_bounds.height=0; /* no dup, no pixel added */
+        if ( add_frames )
+          {
+            dup_image=CloneImage(curr->previous,curr->previous->page.width,
+                curr->previous->page.height,MagickTrue,exception);
+            if (dup_image == (Image *) NULL)
+              {
+                bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+                disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+                prev_image=DestroyImage(prev_image);
+                return((Image *) NULL);
+              }
+            dup_bounds=CompareImageBounds(dup_image,curr,CompareClearLayer,exception);
+            ClearBounds(dup_image,&dup_bounds);
+            try_bounds=CompareImageBounds(dup_image,curr,CompareAnyLayer,exception);
+            if ( cleared ||
+                   dup_bounds.width*dup_bounds.height
+                      +try_bounds.width*try_bounds.height
+                   < bounds[i].width * bounds[i].height )
+              {
+                cleared=MagickFalse;
+                bounds[i]=try_bounds;
+                disposals[i-1]=DupDispose;
+                /* to be finalised later, if found to be optimial */
+              }
+            else
+              dup_bounds.width=dup_bounds.height=0;
+          }
+        /*
+          Now compare against a simple background disposal
+        */
+        bgnd_image=CloneImage(curr->previous,curr->previous->page.width,
+          curr->previous->page.height,MagickTrue,exception);
+        if (bgnd_image == (Image *) NULL)
+          {
+            bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+            disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+            prev_image=DestroyImage(prev_image);
+            if ( dup_image != (Image *) NULL)
+              dup_image=DestroyImage(dup_image);
+            return((Image *) NULL);
+          }
+        bgnd_bounds=bounds[i-1]; /* interum bounds of the previous image */
+        ClearBounds(bgnd_image,&bgnd_bounds);
+        try_bounds=CompareImageBounds(bgnd_image,curr,CompareAnyLayer,exception);
+        try_cleared=IsBoundsCleared(bgnd_image,curr,&try_bounds,exception);
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "background: %s\n",
+         try_cleared?"(pixels cleared)":"");
+#endif
+        if ( try_cleared )
+          {
+            /*
+              Straight background disposal failed to clear pixels needed!
+              Lets try expanding the disposal area of the previous frame, to
+              include the pixels that are cleared.  This guaranteed
+              to work, though may not be the most optimized solution.
+            */
+            try_bounds=CompareImageBounds(curr->previous,curr,CompareClearLayer,exception);
+#if DEBUG_OPT_FRAME
+            (void) FormatLocaleFile(stderr, "expand_clear: %.20gx%.20g%+.20g%+.20g%s\n",
+                (double) try_bounds.width,(double) try_bounds.height,
+                (double) try_bounds.x,(double) try_bounds.y,
+                try_bounds.x<0?"  (no expand nessary)":"");
+#endif
+            if ( bgnd_bounds.x < 0 )
+              bgnd_bounds = try_bounds;
+            else
+              {
+#if DEBUG_OPT_FRAME
+                (void) FormatLocaleFile(stderr, "expand_bgnd: %.20gx%.20g%+.20g%+.20g\n",
+                    (double) bgnd_bounds.width,(double) bgnd_bounds.height,
+                    (double) bgnd_bounds.x,(double) bgnd_bounds.y );
+#endif
+                if ( try_bounds.x < bgnd_bounds.x )
+                  {
+                     bgnd_bounds.width+= bgnd_bounds.x-try_bounds.x;
+                     if ( bgnd_bounds.width < try_bounds.width )
+                       bgnd_bounds.width = try_bounds.width;
+                     bgnd_bounds.x = try_bounds.x;
+                  }
+                else
+                  {
+                     try_bounds.width += try_bounds.x - bgnd_bounds.x;
+                     if ( bgnd_bounds.width < try_bounds.width )
+                       bgnd_bounds.width = try_bounds.width;
+                  }
+                if ( try_bounds.y < bgnd_bounds.y )
+                  {
+                     bgnd_bounds.height += bgnd_bounds.y - try_bounds.y;
+                     if ( bgnd_bounds.height < try_bounds.height )
+                       bgnd_bounds.height = try_bounds.height;
+                     bgnd_bounds.y = try_bounds.y;
+                  }
+                else
+                  {
+                    try_bounds.height += try_bounds.y - bgnd_bounds.y;
+                     if ( bgnd_bounds.height < try_bounds.height )
+                       bgnd_bounds.height = try_bounds.height;
+                  }
+#if DEBUG_OPT_FRAME
+                (void) FormatLocaleFile(stderr, "        to : %.20gx%.20g%+.20g%+.20g\n",
+                    (double) bgnd_bounds.width,(double) bgnd_bounds.height,
+                    (double) bgnd_bounds.x,(double) bgnd_bounds.y );
+#endif
+              }
+            ClearBounds(bgnd_image,&bgnd_bounds);
+#if DEBUG_OPT_FRAME
+/* Something strange is happening with a specific animation
+ * CompareAnyLayers (normal method) and CompareClearLayers returns the whole
+ * image, which is not posibly correct!  As verified by previous tests.
+ * Something changed beyond the bgnd_bounds clearing.  But without being able
+ * to see, or writet he image at this point it is hard to tell what is wrong!
+ * Only CompareOverlay seemed to return something sensible.
+ */
+            try_bounds=CompareImageBounds(bgnd_image,curr,CompareClearLayer,exception);
+            (void) FormatLocaleFile(stderr, "expand_ctst: %.20gx%.20g%+.20g%+.20g\n",
+                (double) try_bounds.width,(double) try_bounds.height,
+                (double) try_bounds.x,(double) try_bounds.y );
+            try_bounds=CompareImageBounds(bgnd_image,curr,CompareAnyLayer,exception);
+            try_cleared=IsBoundsCleared(bgnd_image,curr,&try_bounds,exception);
+            (void) FormatLocaleFile(stderr, "expand_any : %.20gx%.20g%+.20g%+.20g%s\n",
+                (double) try_bounds.width,(double) try_bounds.height,
+                (double) try_bounds.x,(double) try_bounds.y,
+                try_cleared?"   (pixels cleared)":"");
+#endif
+            try_bounds=CompareImageBounds(bgnd_image,curr,CompareOverlayLayer,exception);
+#if DEBUG_OPT_FRAME
+            try_cleared=IsBoundsCleared(bgnd_image,curr,&try_bounds,exception);
+            (void) FormatLocaleFile(stderr, "expand_test: %.20gx%.20g%+.20g%+.20g%s\n",
+                (double) try_bounds.width,(double) try_bounds.height,
+                (double) try_bounds.x,(double) try_bounds.y,
+                try_cleared?"   (pixels cleared)":"");
+#endif
+          }
+        /*
+          Test if this background dispose is smaller than any of the
+          other methods we tryed before this (including duplicated frame)
+        */
+        if ( cleared ||
+              bgnd_bounds.width*bgnd_bounds.height
+                +try_bounds.width*try_bounds.height
+              < bounds[i-1].width*bounds[i-1].height
+                  +dup_bounds.width*dup_bounds.height
+                  +bounds[i].width*bounds[i].height )
+          {
+            cleared=MagickFalse;
+            bounds[i-1]=bgnd_bounds;
+            bounds[i]=try_bounds;
+            if ( disposals[i-1] == DupDispose )
+              dup_image=DestroyImage(dup_image);
+            disposals[i-1]=BackgroundDispose;
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "expand_bgnd: accepted\n");
+          } else {
+    (void) FormatLocaleFile(stderr, "expand_bgnd: reject\n");
+#endif
+          }
+      }
+    /*
+       Finalise choice of dispose, set new prev_image,
+       and junk any extra images as appropriate,
+    */
+    if ( disposals[i-1] == DupDispose )
+      {
+         if (bgnd_image != (Image *) NULL)
+           bgnd_image=DestroyImage(bgnd_image);
+         prev_image=DestroyImage(prev_image);
+         prev_image=dup_image, dup_image=(Image *) NULL;
+         bounds[i+1]=bounds[i];
+         bounds[i]=dup_bounds;
+         disposals[i-1]=DupDispose;
+         disposals[i]=BackgroundDispose;
+         i++;
+      }
+    else
+      {
+        if ( dup_image != (Image *) NULL)
+          dup_image=DestroyImage(dup_image);
+        if ( disposals[i-1] != PreviousDispose )
+          prev_image=DestroyImage(prev_image);
+        if ( disposals[i-1] == BackgroundDispose )
+          prev_image=bgnd_image,  bgnd_image=(Image *)NULL;
+        if (bgnd_image != (Image *) NULL)
+          bgnd_image=DestroyImage(bgnd_image);
+        if ( disposals[i-1] == NoneDispose )
+          {
+            prev_image=CloneImage(curr->previous,curr->previous->page.width,
+              curr->previous->page.height,MagickTrue,exception);
+            if (prev_image == (Image *) NULL)
+              {
+                bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+                disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+                return((Image *) NULL);
+              }
+          }
+
+      }
+    assert(prev_image != (Image *) NULL);
+    disposals[i]=disposals[i-1];
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "final   %.20g : %s  %.20gx%.20g%+.20g%+.20g\n",
+         (double) i-1,
+         CommandOptionToMnemonic(MagickDisposeOptions, disposals[i-1]),
+         (double) bounds[i-1].width, (double) bounds[i-1].height,
+         (double) bounds[i-1].x, (double) bounds[i-1].y );
+#endif
+#if DEBUG_OPT_FRAME
+    (void) FormatLocaleFile(stderr, "interum %.20g : %s  %.20gx%.20g%+.20g%+.20g\n",
+         (double) i,
+         CommandOptionToMnemonic(MagickDisposeOptions, disposals[i]),
+         (double) bounds[i].width, (double) bounds[i].height,
+         (double) bounds[i].x, (double) bounds[i].y );
+    (void) FormatLocaleFile(stderr, "\n");
+#endif
+    i++;
+  }
+  prev_image=DestroyImage(prev_image);
+  /*
+    Optimize all images in sequence.
+  */
+  sans_exception=AcquireExceptionInfo();
+  i=0;
+  curr=GetFirstImageInList(image);
+  optimized_image=NewImageList();
+  while ( curr != (const Image *) NULL )
+  {
+    prev_image=CloneImage(curr,0,0,MagickTrue,exception);
+    if (prev_image == (Image *) NULL)
+      break;
+    if ( disposals[i] == DelDispose ) {
+      size_t time = 0;
+      while ( disposals[i] == DelDispose ) {
+        time += curr->delay*1000/curr->ticks_per_second;
+        curr=GetNextImageInList(curr);
+        i++;
+      }
+      time += curr->delay*1000/curr->ticks_per_second;
+      prev_image->ticks_per_second = 100L;
+      prev_image->delay = time*prev_image->ticks_per_second/1000;
+    }
+    bgnd_image=CropImage(prev_image,&bounds[i],sans_exception);
+    prev_image=DestroyImage(prev_image);
+    if (bgnd_image == (Image *) NULL)
+      break;
+    bgnd_image->dispose=disposals[i];
+    if ( disposals[i] == DupDispose ) {
+      bgnd_image->delay=0;
+      bgnd_image->dispose=NoneDispose;
+    }
+    else
+      curr=GetNextImageInList(curr);
+    AppendImageToList(&optimized_image,bgnd_image);
+    i++;
+  }
+  sans_exception=DestroyExceptionInfo(sans_exception);
+  bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
+  disposals=(DisposeType *) RelinquishMagickMemory(disposals);
+  if (curr != (Image *) NULL)
+    {
+      optimized_image=DestroyImageList(optimized_image);
+      return((Image *) NULL);
+    }
+  return(GetFirstImageInList(optimized_image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O p t i m i z e I m a g e L a y e r s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OptimizeImageLayers() compares each image the GIF disposed forms of the
+%  previous image in the sequence.  From this it attempts to select the
+%  smallest cropped image to replace each frame, while preserving the results
+%  of the GIF animation.
+%
+%  The format of the OptimizeImageLayers method is:
+%
+%      Image *OptimizeImageLayers(const Image *image,
+%               ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *OptimizeImageLayers(const Image *image,
+  ExceptionInfo *exception)
+{
+  return(OptimizeLayerFrames(image,OptimizeImageLayer,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O p t i m i z e P l u s I m a g e L a y e r s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OptimizeImagePlusLayers() is exactly as OptimizeImageLayers(), but may
+%  also add or even remove extra frames in the animation, if it improves
+%  the total number of pixels in the resulting GIF animation.
+%
+%  The format of the OptimizePlusImageLayers method is:
+%
+%      Image *OptimizePlusImageLayers(const Image *image,
+%               ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *OptimizePlusImageLayers(const Image *image,
+  ExceptionInfo *exception)
+{
+  return OptimizeLayerFrames(image, OptimizePlusLayer, exception);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O p t i m i z e I m a g e T r a n s p a r e n c y                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OptimizeImageTransparency() takes a frame optimized GIF animation, and
+%  compares the overlayed pixels against the disposal image resulting from all
+%  the previous frames in the animation.  Any pixel that does not change the
+%  disposal image (and thus does not effect the outcome of an overlay) is made
+%  transparent.
+%
+%  WARNING: This modifies the current images directly, rather than generate
+%  a new image sequence.
+%
+%  The format of the OptimizeImageTransperency method is:
+%
+%      void OptimizeImageTransperency(Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image sequence
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void OptimizeImageTransparency(const Image *image,
+     ExceptionInfo *exception)
+{
+  Image
+    *dispose_image;
+
+  register Image
+    *next;
+
+  /*
+    Run the image through the animation sequence
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  next=GetFirstImageInList(image);
+  dispose_image=CloneImage(next,next->page.width,next->page.height,
+    MagickTrue,exception);
+  if (dispose_image == (Image *) NULL)
+    return;
+  dispose_image->page=next->page;
+  dispose_image->page.x=0;
+  dispose_image->page.y=0;
+  dispose_image->dispose=NoneDispose;
+  dispose_image->background_color.alpha=(Quantum) TransparentAlpha;
+  (void) SetImageBackgroundColor(dispose_image);
+
+  while ( next != (Image *) NULL )
+  {
+    Image
+      *current_image;
+
+    /*
+      Overlay this frame's image over the previous disposal image
+    */
+    current_image=CloneImage(dispose_image,0,0,MagickTrue,exception);
+    if (current_image == (Image *) NULL)
+      {
+        dispose_image=DestroyImage(dispose_image);
+        return;
+      }
+    (void) CompositeImage(current_image,next->matte != MagickFalse ?
+      OverCompositeOp : CopyCompositeOp, next,next->page.x,next->page.y);
+    /*
+      At this point the image would be displayed, for the delay period
+    **
+      Work out the disposal of the previous image
+    */
+    if (next->dispose == BackgroundDispose)
+      {
+        RectangleInfo
+          bounds=next->page;
+
+        bounds.width=next->columns;
+        bounds.height=next->rows;
+        if (bounds.x < 0)
+          {
+            bounds.width+=bounds.x;
+            bounds.x=0;
+          }
+        if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) current_image->columns)
+          bounds.width=current_image->columns-bounds.x;
+        if (bounds.y < 0)
+          {
+            bounds.height+=bounds.y;
+            bounds.y=0;
+          }
+        if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) current_image->rows)
+          bounds.height=current_image->rows-bounds.y;
+        ClearBounds(current_image, &bounds);
+      }
+    if (next->dispose != PreviousDispose)
+      {
+        dispose_image=DestroyImage(dispose_image);
+        dispose_image=current_image;
+      }
+    else
+      current_image=DestroyImage(current_image);
+
+    /*
+      Optimize Transparency of the next frame (if present)
+    */
+    next=GetNextImageInList(next);
+    if ( next != (Image *) NULL ) {
+      (void) CompositeImage(next, ChangeMaskCompositeOp,
+          dispose_image, -(next->page.x), -(next->page.y) );
+    }
+  }
+  dispose_image=DestroyImage(dispose_image);
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     R e m o v e D u p l i c a t e L a y e r s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveDuplicateLayers() removes any image that is exactly the same as the
+%  next image in the given image list.  Image size and virtual canvas offset
+%  must also match, though not the virtual canvas size itself.
+%
+%  No check is made with regards to image disposal setting, though it is the
+%  dispose setting of later image that is kept.  Also any time delays are also
+%  added together. As such coalesced image animations should still produce the
+%  same result, though with duplicte frames merged into a single frame.
+%
+%  The format of the RemoveDuplicateLayers method is:
+%
+%      void RemoveDuplicateLayers(Image **image, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void RemoveDuplicateLayers(Image **images,
+     ExceptionInfo *exception)
+{
+  register Image
+    *curr,
+    *next;
+
+  RectangleInfo
+    bounds;
+
+  assert((*images) != (const Image *) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*images)->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  curr=GetFirstImageInList(*images);
+  for (; (next=GetNextImageInList(curr)) != (Image *) NULL; curr=next)
+  {
+    if ( curr->columns != next->columns || curr->rows != next->rows
+         || curr->page.x != next->page.x || curr->page.y != next->page.y )
+      continue;
+    bounds=CompareImageBounds(curr,next,CompareAnyLayer,exception);
+    if ( bounds.x < 0 ) {
+      /*
+        the two images are the same, merge time delays and delete one.
+      */
+      size_t time;
+      time = curr->delay*1000/curr->ticks_per_second;
+      time += next->delay*1000/next->ticks_per_second;
+      next->ticks_per_second = 100L;
+      next->delay = time*curr->ticks_per_second/1000;
+      next->iterations = curr->iterations;
+      *images = curr;
+      (void) DeleteImageFromList(images);
+    }
+  }
+  *images = GetFirstImageInList(*images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     R e m o v e Z e r o D e l a y L a y e r s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveZeroDelayLayers() removes any image that as a zero delay time. Such
+%  images generally represent intermediate or partial updates in GIF
+%  animations used for file optimization.  They are not ment to be displayed
+%  to users of the animation.  Viewable images in an animation should have a
+%  time delay of 3 or more centi-seconds (hundredths of a second).
+%
+%  However if all the frames have a zero time delay, then either the animation
+%  is as yet incomplete, or it is not a GIF animation.  This a non-sensible
+%  situation, so no image will be removed and a 'Zero Time Animation' warning
+%  (exception) given.
+%
+%  No warning will be given if no image was removed because all images had an
+%  appropriate non-zero time delay set.
+%
+%  Due to the special requirements of GIF disposal handling, GIF animations
+%  should be coalesced first, before calling this function, though that is not
+%  a requirement.
+%
+%  The format of the RemoveZeroDelayLayers method is:
+%
+%      void RemoveZeroDelayLayers(Image **image, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void RemoveZeroDelayLayers(Image **images,
+     ExceptionInfo *exception)
+{
+  Image
+    *i;
+
+  assert((*images) != (const Image *) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*images)->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  i=GetFirstImageInList(*images);
+  for ( ; i != (Image *) NULL; i=GetNextImageInList(i))
+    if ( i->delay != 0L ) break;
+  if ( i == (Image *) NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+       "ZeroTimeAnimation","`%s'",GetFirstImageInList(*images)->filename);
+    return;
+  }
+  i=GetFirstImageInList(*images);
+  while ( i != (Image *) NULL )
+  {
+    if ( i->delay == 0L ) {
+      (void) DeleteImageFromList(&i);
+      *images=i;
+    }
+    else
+      i=GetNextImageInList(i);
+  }
+  *images=GetFirstImageInList(*images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C o m p o s i t e L a y e r s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompositeLayers() compose first image sequence (source) over the second
+%  image sequence (destination), using the given compose method and offsets.
+%
+%  The pointers to the image list does not have to be the start of that image
+%  list, but may start somewhere in the middle.  Each layer from the two image
+%  lists are composted together until the end of one of the image lists is
+%  reached.  The offset of each composition is also adjusted to match the
+%  virtual canvas offsets of each layer. As such the given offset is relative
+%  to the virtual canvas, and not the actual image.
+%
+%  No GIF disposal handling is performed, so GIF animations should be
+%  coalesced before use.  However this not a requirement, and individual
+%  layer images may have any size or offset, for special compositions.
+%
+%  Special case:- If one of the image sequences is just a single image that
+%  image is repeatally composed with all the images in the other image list.
+%  Either the source or destination lists may be the single image, for this
+%  situation.
+%
+%  The destination list will be expanded as needed to match number of source
+%  image overlaid (from current position to end of list).
+%
+%  The format of the CompositeLayers method is:
+%
+%      void CompositeLayers(Image *destination,
+%          const CompositeOperator compose, Image *source,
+%          const ssize_t x_offset, const ssize_t y_offset,
+%          ExceptionInfo *exception);
+%
+%  A description of each parameter follows:
+%
+%    o destination: the destination images and results
+%
+%    o source: source image(s) for the layer composition
+%
+%    o compose, x_offset, y_offset:  arguments passed on to CompositeImages()
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static inline void CompositeCanvas(Image *destination,
+  const CompositeOperator compose, Image *source,ssize_t x_offset,
+  ssize_t y_offset )
+{
+  x_offset+=source->page.x-destination->page.x;
+  y_offset+=source->page.y-destination->page.y;
+  (void) CompositeImage(destination,compose,source,x_offset,y_offset);
+}
+
+MagickExport void CompositeLayers(Image *destination,
+  const CompositeOperator compose, Image *source,const ssize_t x_offset,
+  const ssize_t y_offset,ExceptionInfo *exception)
+{
+  assert(destination != (Image *) NULL);
+  assert(destination->signature == MagickSignature);
+  assert(source != (Image *) NULL);
+  assert(source->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (source->debug != MagickFalse || destination->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s - %s",
+         source->filename, destination->filename);
+
+  /*
+    Overlay single source image over destation image/list
+  */
+  if ( source->previous == (Image *) NULL && source->next == (Image *) NULL )
+    while ( destination != (Image *) NULL )
+    {
+      CompositeCanvas(destination, compose, source, x_offset, y_offset);
+      destination=GetNextImageInList(destination);
+    }
+
+  /*
+    Overlay source image list over single destination
+    Generating multiple clones of destination image to match source list.
+    Original Destination image becomes first image of generated list.
+    As such the image list pointer does not require any change in caller.
+    Some animation attributes however also needs coping in this case.
+  */
+  else if ( destination->previous == (Image *) NULL &&
+            destination->next == (Image *) NULL )
+  {
+    Image *dest = CloneImage(destination,0,0,MagickTrue,exception);
+
+    CompositeCanvas(destination, compose, source, x_offset, y_offset);
+    /* copy source image attributes ? */
+    if ( source->next != (Image *) NULL )
+      {
+        destination->delay = source->delay;
+        destination->iterations = source->iterations;
+      }
+    source=GetNextImageInList(source);
+
+    while ( source != (Image *) NULL )
+    {
+      AppendImageToList(&destination,
+           CloneImage(dest,0,0,MagickTrue,exception));
+      destination=GetLastImageInList(destination);
+
+      CompositeCanvas(destination, compose, source, x_offset, y_offset);
+      destination->delay = source->delay;
+      destination->iterations = source->iterations;
+      source=GetNextImageInList(source);
+    }
+    dest=DestroyImage(dest);
+  }
+
+  /*
+    Overlay a source image list over a destination image list
+    until either list runs out of images. (Does not repeat)
+  */
+  else
+    while ( source != (Image *) NULL && destination != (Image *) NULL )
+    {
+      CompositeCanvas(destination, compose, source, x_offset, y_offset);
+      source=GetNextImageInList(source);
+      destination=GetNextImageInList(destination);
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M e r g e I m a g e L a y e r s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MergeImageLayers() composes all the image layers from the current given
+%  image onward to produce a single image of the merged layers.
+%
+%  The inital canvas's size depends on the given ImageLayerMethod, and is
+%  initialized using the first images background color.  The images
+%  are then compositied onto that image in sequence using the given
+%  composition that has been assigned to each individual image.
+%
+%  The format of the MergeImageLayers is:
+%
+%      Image *MergeImageLayers(const Image *image,
+%        const ImageLayerMethod method, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image list to be composited together
+%
+%    o method: the method of selecting the size of the initial canvas.
+%
+%        MergeLayer: Merge all layers onto a canvas just large enough
+%           to hold all the actual images. The virtual canvas of the
+%           first image is preserved but otherwise ignored.
+%
+%        FlattenLayer: Use the virtual canvas size of first image.
+%           Images which fall outside this canvas is clipped.
+%           This can be used to 'fill out' a given virtual canvas.
+%
+%        MosaicLayer: Start with the virtual canvas of the first image,
+%           enlarging left and right edges to contain all images.
+%           Images with negative offsets will be clipped.
+%
+%        TrimBoundsLayer: Determine the overall bounds of all the image
+%           layers just as in "MergeLayer", then adjust the the canvas
+%           and offsets to be relative to those bounds, without overlaying
+%           the images.
+%
+%           WARNING: a new image is not returned, the original image
+%           sequence page data is modified instead.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *MergeImageLayers(Image *image,
+  const ImageLayerMethod method,ExceptionInfo *exception)
+{
+#define MergeLayersTag  "Merge/Layers"
+
+  Image
+    *canvas;
+
+  MagickBooleanType
+    proceed;
+
+  RectangleInfo
+    page;
+
+  register const Image
+    *next;
+
+  size_t
+    number_images,
+    height,
+    width;
+
+  ssize_t
+    scene;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  /*
+    Determine canvas image size, and its virtual canvas size and offset
+  */
+  page=image->page;
+  width=image->columns;
+  height=image->rows;
+  switch (method)
+  {
+    case TrimBoundsLayer:
+    case MergeLayer:
+    default:
+    {
+      next = GetNextImageInList(image);
+      for ( ; next != (Image *) NULL;  next=GetNextImageInList(next)) {
+        if ( page.x > next->page.x ) {
+             width += page.x-next->page.x;
+             page.x = next->page.x;
+        }
+        if ( page.y > next->page.y ) {
+             height += page.y-next->page.y;
+             page.y = next->page.y;
+        }
+        if ( (ssize_t) width < (next->page.x + (ssize_t)next->columns - page.x) )
+           width = (size_t) next->page.x + (ssize_t)next->columns - page.x;
+        if ( (ssize_t) height < (next->page.y + (ssize_t)next->rows - page.y) )
+           height = (size_t) next->page.y + (ssize_t)next->rows - page.y;
+      }
+      break;
+    }
+    case FlattenLayer:
+    {
+      if ( page.width > 0 )
+        width=page.width;
+      if ( page.height > 0 )
+        height=page.height;
+      page.x=0;
+      page.y=0;
+      break;
+    }
+    case MosaicLayer:
+    {
+      if ( page.width > 0 )
+        width=page.width;
+      if ( page.height > 0 )
+        height=page.height;
+      for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) {
+        if (method == MosaicLayer) {
+          page.x=next->page.x;
+          page.y=next->page.y;
+          if ( (ssize_t) width < (next->page.x + (ssize_t)next->columns) )
+             width = (size_t) next->page.x + next->columns;
+          if ( (ssize_t) height < (next->page.y + (ssize_t)next->rows) )
+             height = (size_t) next->page.y + next->rows;
+        }
+      }
+      page.width=width;
+      page.height=height;
+      page.x=0;
+      page.y=0;
+    }
+    break;
+  }
+  /* set virtual canvas size if not defined */
+  if ( page.width == 0 )
+    page.width = (page.x < 0) ? width : width+page.x;
+  if ( page.height == 0 )
+    page.height = (page.y < 0) ? height : height+page.y;
+
+  /*
+    Handle "TrimBoundsLayer" method separately to normal 'layer merge'
+  */
+  if ( method == TrimBoundsLayer ) {
+    number_images=GetImageListLength(image);
+    for (scene=0; scene < (ssize_t) number_images; scene++)
+    {
+      image->page.x -= page.x;
+      image->page.y -= page.y;
+      image->page.width = width;
+      image->page.height = height;
+      proceed=SetImageProgress(image,MergeLayersTag,(MagickOffsetType) scene,
+        number_images);
+      if (proceed == MagickFalse)
+        break;
+      image=GetNextImageInList(image);
+    }
+    return((Image *) NULL);
+  }
+
+  /*
+    Create canvas size of width and height, and background color.
+  */
+  canvas=CloneImage(image,width,height,MagickTrue,exception);
+  if (canvas == (Image *) NULL)
+    return((Image *) NULL);
+  (void) SetImageBackgroundColor(canvas);
+  canvas->page=page;
+  canvas->dispose=UndefinedDispose;
+
+  /*
+    Compose images onto canvas, with progress monitor
+  */
+  number_images=GetImageListLength(image);
+  for (scene=0; scene < (ssize_t) number_images; scene++)
+  {
+    (void) CompositeImage(canvas,image->compose,image,image->page.x-
+      canvas->page.x,image->page.y-canvas->page.y);
+    proceed=SetImageProgress(image,MergeLayersTag,(MagickOffsetType) scene,
+      number_images);
+    if (proceed == MagickFalse)
+      break;
+    image=GetNextImageInList(image);
+  }
+  return(canvas);
+}
+
diff --git a/MagickCore/layer.h b/MagickCore/layer.h
new file mode 100644
index 0000000..9da131c
--- /dev/null
+++ b/MagickCore/layer.h
@@ -0,0 +1,76 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image layer methods.
+*/
+#ifndef _MAGICKCORE_LAYER_H
+#define _MAGICKCORE_LAYER_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/composite.h>
+
+typedef enum
+{
+  UnrecognizedDispose,
+  UndefinedDispose = 0,
+  NoneDispose = 1,
+  BackgroundDispose = 2,
+  PreviousDispose = 3
+} DisposeType;
+
+typedef enum
+{
+  UndefinedLayer,
+  CoalesceLayer,
+  CompareAnyLayer,
+  CompareClearLayer,
+  CompareOverlayLayer,
+  DisposeLayer,
+  OptimizeLayer,
+  OptimizeImageLayer,
+  OptimizePlusLayer,
+  OptimizeTransLayer,
+  RemoveDupsLayer,
+  RemoveZeroLayer,
+  CompositeLayer,
+  MergeLayer,
+  FlattenLayer,
+  MosaicLayer,
+  TrimBoundsLayer
+} ImageLayerMethod;
+
+extern MagickExport Image
+  *CoalesceImages(const Image *,ExceptionInfo *),
+  *DisposeImages(const Image *,ExceptionInfo *),
+  *CompareImageLayers(const Image *,const ImageLayerMethod,ExceptionInfo *),
+  *MergeImageLayers(Image *,const ImageLayerMethod,ExceptionInfo *),
+  *OptimizeImageLayers(const Image *,ExceptionInfo *),
+  *OptimizePlusImageLayers(const Image *,ExceptionInfo *);
+
+extern MagickExport void
+  CompositeLayers(Image *,const CompositeOperator,Image *,const ssize_t,
+    const ssize_t,ExceptionInfo *),
+  OptimizeImageTransparency(const Image *,ExceptionInfo *),
+  RemoveDuplicateLayers(Image **,ExceptionInfo *),
+  RemoveZeroDelayLayers(Image **,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/list.c b/MagickCore/list.c
new file mode 100644
index 0000000..65e2451
--- /dev/null
+++ b/MagickCore/list.c
@@ -0,0 +1,1425 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                         L      IIIII  SSSSS  TTTTT                          %
+%                         L        I    SS       T                            %
+%                         L        I     SSS     T                            %
+%                         L        I       SS    T                            %
+%                         LLLLL  IIIII  SSSSS    T                            %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Image List Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               December 2002                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/string_.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A p p e n d I m a g e T o L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AppendImageToList() appends the second image list to the end of the first
+%  list.  The given image list pointer is left unchanged, unless it was empty.
+%
+%  The format of the AppendImageToList method is:
+%
+%      AppendImageToList(Image *images,const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list to be appended to.
+%
+%    o image: the appended image or image list.
+%
+*/
+MagickExport void AppendImageToList(Image **images,const Image *image)
+{
+  register Image
+    *p,
+    *q;
+
+  assert(images != (Image **) NULL);
+  if (image == (Image *) NULL)
+    return;
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((*images) == (Image *) NULL)
+    {
+      *images=(Image *) image;
+      return;
+    }
+  assert((*images)->signature == MagickSignature);
+  p=GetLastImageInList(*images);
+  q=GetFirstImageInList(image);
+  p->next=q;
+  q->previous=p;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageList() returns a duplicate of the image list.
+%
+%  The format of the CloneImageList method is:
+%
+%      Image *CloneImageList(const Image *images,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CloneImageList(const Image *images,ExceptionInfo *exception)
+{
+  Image
+    *clone,
+    *image;
+
+  register Image
+    *p;
+
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  while (images->previous != (Image *) NULL)
+    images=images->previous;
+  image=(Image *) NULL;
+  for (p=(Image *) NULL; images != (Image *) NULL; images=images->next)
+  {
+    clone=CloneImage(images,0,0,MagickTrue,exception);
+    if (clone == (Image *) NULL)
+      {
+        if (image != (Image *) NULL)
+          image=DestroyImageList(image);
+        return((Image *) NULL);
+      }
+    if (image == (Image *) NULL)
+      {
+        image=clone;
+        p=image;
+        continue;
+      }
+    p->next=clone;
+    clone->previous=p;
+    p=p->next;
+  }
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e s                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImages() clones one or more images from an image sequence, using a
+%  comma separated list of image numbers or ranges.
+%
+%  The numbers start at 0 for the first image in the list, while negative
+%  numbers refer to images starting counting from the end of the range. Images
+%  may be refered to multiple times to clone them multiple times. Images
+%  refered beyond the available number of images in list are ignored.
+%
+%  Images referenced may be reversed, and results in a clone of those images
+%  also being made with a reversed order.
+%
+%  The format of the CloneImages method is:
+%
+%      Image *CloneImages(const Image *images,const char *scenes,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image sequence.
+%
+%    o scenes: This character string specifies which scenes to clone
+%      (e.g. 1,3-5,7-3,2).
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CloneImages(const Image *images,const char *scenes,
+  ExceptionInfo *exception)
+{
+  char
+    *p;
+
+  const Image
+    *next;
+
+  Image
+    *clone_images,
+    *image;
+
+  long
+    first,
+    last,
+    step;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  assert(images != (const Image *) NULL);
+  assert(images->signature == MagickSignature);
+  assert(scenes != (char *) NULL);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  clone_images=NewImageList();
+  images=GetFirstImageInList(images);
+  length=GetImageListLength(images);
+  for (p=(char *) scenes; *p != '\0';)
+  {
+    while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
+      p++;
+    first=strtol(p,&p,10);
+    if (first < 0)
+      first+=(long) length;
+    last=first;
+    while (isspace((int) ((unsigned char) *p)) != 0)
+      p++;
+    if (*p == '-')
+      {
+        last=strtol(p+1,&p,10);
+        if (last < 0)
+          last+=(long) length;
+      }
+    for (step=first > last ? -1 : 1; first != (last+step); first+=step)
+    {
+      i=0;
+      for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
+      {
+        if (i == (ssize_t) first)
+          {
+            image=CloneImage(next,0,0,MagickTrue,exception);
+            if (image == (Image *) NULL)
+              break;
+            AppendImageToList(&clone_images,image);
+          }
+        i++;
+      }
+    }
+  }
+  return(GetFirstImageInList(clone_images));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e F r o m L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageFromList() deletes an image from the list. List pointer
+%  is moved to the next image, if one is present. See RemoveImageFromList().
+%
+%  The format of the DeleteImageFromList method is:
+%
+%      DeleteImageFromList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport void DeleteImageFromList(Image **images)
+{
+  Image
+    *image;
+
+  image=RemoveImageFromList(images);
+  if (image != (Image *) NULL)
+    (void) DestroyImage(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e s                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImages() deletes one or more images from an image sequence, using a
+%  comma separated list of image numbers or ranges.
+%
+%  The numbers start at 0 for the first image, while negative numbers refer to
+%  images starting counting from the end of the range. Images may be refered to
+%  multiple times without problems. Image refered beyond the available number
+%  of images in list are ignored.
+%
+%  If the referenced images are in the reverse order, that range will be
+%  completely ignored, unlike CloneImages().
+%
+%  The format of the DeleteImages method is:
+%
+%      DeleteImages(Image **images,const char *scenes,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image sequence.
+%
+%    o scenes: This character string specifies which scenes to delete
+%      (e.g. 1,3-5,-2-6,2).
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void DeleteImages(Image **images,const char *scenes,
+  ExceptionInfo *exception)
+{
+  char
+    *p;
+
+  Image
+    *image;
+
+  long
+    first,
+    last;
+
+  MagickBooleanType
+    *delete_list;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  assert(images != (Image **) NULL);
+  assert((*images)->signature == MagickSignature);
+  assert(scenes != (char *) NULL);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  *images=GetFirstImageInList(*images);
+  length=GetImageListLength(*images);
+  delete_list=(MagickBooleanType *) AcquireQuantumMemory(length,
+    sizeof(*delete_list));
+  if (delete_list == (MagickBooleanType *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",(*images)->filename);
+      return;
+    }
+  image=(*images);
+  for (i=0; i < (ssize_t) length; i++)
+    delete_list[i]=MagickFalse;
+  /*
+    Note which images will be deleted, avoid duplicate deleted
+  */
+  for (p=(char *) scenes; *p != '\0';)
+  {
+    while ((isspace((int) *p) != 0) || (*p == ','))
+      p++;
+    first=strtol(p,&p,10);
+    if (first < 0)
+      first+=(long) length;
+    last=first;
+    while (isspace((int) ((unsigned char) *p)) != 0)
+      p++;
+    if (*p == '-')
+      {
+        last=strtol(p+1,&p,10);
+        if (last < 0)
+          last+=(long) length;
+      }
+    if (first > last)
+      continue;
+    for (i=(ssize_t) first; i <= (ssize_t) last; i++)
+      if ((i >= 0) && (i < (ssize_t) length))
+        delete_list[i]=MagickTrue;
+  }
+  /*
+    Delete images marked for deletion, once only
+  */
+  image=(*images);
+  for (i=0; i < (ssize_t) length; i++)
+  {
+    *images=image;
+    image=GetNextImageInList(image);
+    if (delete_list[i] != MagickFalse)
+      DeleteImageFromList(images);
+
+  }
+  (void) RelinquishMagickMemory(delete_list);
+  *images=GetFirstImageInList(*images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageList() destroys an image list.
+%
+%  The format of the DestroyImageList method is:
+%
+%      Image *DestroyImageList(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image sequence.
+%
+*/
+MagickExport Image *DestroyImageList(Image *images)
+{
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  while (images != (Image *) NULL)
+    DeleteImageFromList(&images);
+  return((Image *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D u p l i c a t e I m a g e s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DuplicateImages() duplicates one or more images from an image sequence,
+%  using a count and a comma separated list of image numbers or ranges.
+%
+%  The numbers start at 0 for the first image, while negative numbers refer to
+%  images starting counting from the end of the range. Images may be refered to
+%  multiple times without problems. Image refered beyond the available number
+%  of images in list are ignored.
+%
+%  The format of the DuplicateImages method is:
+%
+%      Image *DuplicateImages(Image *images,const size_t number_duplicates,
+%        const char *scenes,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image sequence.
+%
+%    o number_duplicates: duplicate the image sequence this number of times.
+%
+%    o scenes: This character string specifies which scenes to duplicate (e.g.
+%      1,3-5,-2-6,2).
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *DuplicateImages(Image *images,
+  const size_t number_duplicates,const char *scenes,ExceptionInfo *exception)
+{
+  Image
+    *clone_images,
+    *duplicate_images;
+
+  register ssize_t
+    i;
+
+  /*
+    Duplicate images.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  assert(scenes != (char *) NULL);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  duplicate_images=NewImageList();
+  for (i=0; i < (ssize_t) number_duplicates; i++)
+  {
+    clone_images=CloneImages(images,scenes,exception);
+    AppendImageToList(&duplicate_images,clone_images);
+  }
+  return(duplicate_images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t F i r s t I m a g e I n L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetFirstImageInList() returns a pointer to the first image in the list.
+%
+%  The format of the GetFirstImageInList method is:
+%
+%      Image *GetFirstImageInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *GetFirstImageInList(const Image *images)
+{
+  register const Image
+    *p;
+
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  for (p=images; p->previous != (Image *) NULL; p=p->previous) ;
+  return((Image *) p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e F r o m L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageFromList() returns an image at the specified offset from the list.
+%
+%  The format of the GetImageFromList method is:
+%
+%      Image *GetImageFromList(const Image *images,const ssize_t index)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o index: the position within the list.
+%
+*/
+MagickExport Image *GetImageFromList(const Image *images,const ssize_t index)
+{
+  register const Image
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  ssize_t
+    offset;
+
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  for (p=images; p->previous != (Image *) NULL; p=p->previous) ;
+  length=GetImageListLength(images);
+  for (offset=index; offset < 0; offset+=(ssize_t) length) ;
+  for (i=0; p != (Image *) NULL; p=p->next)
+    if (i++ == (ssize_t) (offset % length))
+      break;
+  if (p == (Image *) NULL)
+    return((Image *) NULL);
+  return((Image *) p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e I n d e x I n L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageIndexInList() returns the offset in the list of the specified image.
+%
+%  The format of the GetImageIndexInList method is:
+%
+%      ssize_t GetImageIndexInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport ssize_t GetImageIndexInList(const Image *images)
+{
+  register ssize_t
+    i;
+
+  if (images == (const Image *) NULL)
+    return(-1);
+  assert(images->signature == MagickSignature);
+  for (i=0; images->previous != (Image *) NULL; i++)
+    images=images->previous;
+  return(i);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e L i s t L e n g t h                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageListLength() returns the length of the list (the number of images in
+%  the list).
+%
+%  The format of the GetImageListLength method is:
+%
+%      size_t GetImageListLength(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport size_t GetImageListLength(const Image *images)
+{
+  register ssize_t
+    i;
+
+  if (images == (Image *) NULL)
+    return(0);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  while (images->previous != (Image *) NULL)
+    images=images->previous;
+  for (i=0; images != (Image *) NULL; images=images->next)
+    i++;
+  return((size_t) i);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L a s t I m a g e I n L i s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLastImageInList() returns a pointer to the last image in the list.
+%
+%  The format of the GetLastImageInList method is:
+%
+%      Image *GetLastImageInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *GetLastImageInList(const Image *images)
+{
+  register const Image
+    *p;
+
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  for (p=images; p->next != (Image *) NULL; p=p->next) ;
+  return((Image *) p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e I n L i s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageInList() returns the next image in the list.
+%
+%  The format of the GetNextImageInList method is:
+%
+%      Image *GetNextImageInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *GetNextImageInList(const Image *images)
+{
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  return(images->next);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P r e v i o u s I m a g e I n L i s t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPreviousImageInList() returns the previous image in the list.
+%
+%  The format of the GetPreviousImageInList method is:
+%
+%      Image *GetPreviousImageInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *GetPreviousImageInList(const Image *images)
+{
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  return(images->previous);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%     I m a g e L i s t T o A r r a y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImageListToArray() is a convenience method that converts an image list to
+%  a sequential array.  For example,
+%
+%    group = ImageListToArray(images, exception);
+%    while (i = 0; group[i] != (Image *) NULL; i++)
+%      printf("%s\n", group[i]->filename);
+%    printf("%d images\n", i);
+%    group = RelinquishMagickMemory(group);
+%
+%  The format of the ImageListToArray method is:
+%
+%      Image **ImageListToArray(const Image *images,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image **ImageListToArray(const Image *images,
+  ExceptionInfo *exception)
+{
+  Image
+    **group;
+
+  register ssize_t
+    i;
+
+  if (images == (Image *) NULL)
+    return((Image **) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  group=(Image **) AcquireQuantumMemory((size_t) GetImageListLength(images)+1UL,
+    sizeof(*group));
+  if (group == (Image **) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      return((Image **) NULL);
+    }
+  images=GetFirstImageInList(images);
+  for (i=0; images != (Image *) NULL; images=images->next)
+    group[i++]=(Image *) images;
+  group[i]=(Image *) NULL;
+  return(group);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n s e r t I m a g e I n L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InsertImageInList() inserts the second image or image list into the first
+%  image list immediately after the image pointed to.  The given image list
+%  pointer is unchanged unless previously empty.
+%
+%  The format of the InsertImageInList method is:
+%
+%      InsertImageInList(Image **images,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list to insert into.
+%
+%    o image: the image list to insert.
+%
+*/
+MagickExport void InsertImageInList(Image **images,Image *image)
+{
+  Image
+    *split;
+
+  assert(images != (Image **) NULL);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((*images) == (Image *) NULL)
+    return;
+  assert((*images)->signature == MagickSignature);
+  split=SplitImageList(*images);
+  AppendImageToList(images,image);
+  AppendImageToList(images,split);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w I m a g e L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewImageList() creates an empty image list.
+%
+%  The format of the NewImageList method is:
+%
+%      Image *NewImageList(void)
+%
+*/
+MagickExport Image *NewImageList(void)
+{
+  return((Image *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P r e p e n d I m a g e T o L i s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PrependImageToList() prepends the image to the beginning of the list.
+%
+%  The format of the PrependImageToList method is:
+%
+%      PrependImageToList(Image *images,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o image: the image.
+%
+*/
+MagickExport void PrependImageToList(Image **images,Image *image)
+{
+  AppendImageToList(&image,*images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e I m a g e F r o m L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveImageFromList() removes and returns the image pointed to.
+%
+%  The given image list pointer is set to point to the next image in list
+%  if it exists, otherwise it is set to the previous image, or NULL if list
+%  was emptied.
+%
+%  The format of the RemoveImageFromList method is:
+%
+%      Image *RemoveImageFromList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *RemoveImageFromList(Image **images)
+{
+  register Image
+    *p;
+
+  assert(images != (Image **) NULL);
+  if ((*images) == (Image *) NULL)
+    return((Image *) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  p=(*images);
+  if ((p->previous == (Image *) NULL) && (p->next == (Image *) NULL))
+    *images=(Image *) NULL;
+  else
+    {
+      if (p->previous != (Image *) NULL)
+        {
+          p->previous->next=p->next;
+          *images=p->previous;
+        }
+      if (p->next != (Image *) NULL)
+        {
+          p->next->previous=p->previous;
+          *images=p->next;
+        }
+      p->previous=(Image *) NULL;
+      p->next=(Image *) NULL;
+    }
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e F i r s t I m a g e F r o m L i s t                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveFirstImageFromList() removes and returns the first image in the list.
+%
+%  If the given image list pointer pointed to the removed first image, it is
+%  set to the new first image of list, or NULL if list was emptied, otherwise
+%  it is left as is.
+%
+%  The format of the RemoveFirstImageFromList method is:
+%
+%      Image *RemoveFirstImageFromList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *RemoveFirstImageFromList(Image **images)
+{
+  Image
+    *image;
+
+  assert(images != (Image **) NULL);
+  if ((*images) == (Image *) NULL)
+    return((Image *) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  image=(*images);
+  while (image->previous != (Image *) NULL)
+    image=image->previous;
+  if (image == *images)
+    *images=(*images)->next;
+  if (image->next != (Image *) NULL)
+    {
+      image->next->previous=(Image *) NULL;
+      image->next=(Image *) NULL;
+    }
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e L a s t I m a g e F r o m L i s t                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveLastImageFromList() removes and returns the last image from the list.
+%
+%  If the given image list pointer pointed to the removed last image, it is
+%  set to the new last image of list, or NULL if list was emptied, otherwise
+%  it is left as is.
+%
+%  The format of the RemoveLastImageFromList method is:
+%
+%      Image *RemoveLastImageFromList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *RemoveLastImageFromList(Image **images)
+{
+  Image
+    *image;
+
+  assert(images != (Image **) NULL);
+  if ((*images) == (Image *) NULL)
+    return((Image *) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  image=(*images);
+  while (image->next != (Image *) NULL)
+    image=image->next;
+  if (image == *images)
+    *images=(*images)->previous;
+  if (image->previous != (Image *) NULL)
+    {
+      image->previous->next=(Image *) NULL;
+      image->previous=(Image *) NULL;
+    }
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e p l a c e I m a g e I n L i s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReplaceImageInList() replaces an image in the list with the given image, or
+%  list of images.  Old image is destroyed.  The image list pointer is set to
+%  point to the first image of the inserted list of images.
+%
+%  The format of the ReplaceImageInList method is:
+%
+%      ReplaceImageInList(Image **images,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o images: the list and pointer to image to replace
+%
+%    o image: the image or image list replacing the original
+%
+*/
+MagickExport void ReplaceImageInList(Image **images,Image *image)
+{
+  assert(images != (Image **) NULL);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((*images) == (Image *) NULL)
+    return;
+  assert((*images)->signature == MagickSignature);
+
+  /* link next pointer */
+  image=GetLastImageInList(image);
+  image->next=(*images)->next;
+  if (image->next != (Image *) NULL)
+    image->next->previous=image;
+
+  /* link previous pointer - set image position to first replacement image */
+  image=GetFirstImageInList(image);
+  image->previous=(*images)->previous;
+  if (image->previous != (Image *) NULL)
+    image->previous->next=image;
+
+  /* destroy replaced image */
+  (void) DestroyImage(*images);
+  (*images)=image;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e p l a c e I m a g e I n L i s t R e t u r n L a s t                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReplaceImageInListReturnLast() is exactly as ReplaceImageInList() except
+%  the image pointer is set to the last image in the list.
+%
+%  This allows you to simply use 'next' to go to the image that follows the
+%  just replaced image.
+%
+%  The format of the ReplaceImageInList method is:
+%
+%      ReplaceImageInListReturnLast(Image **images,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o images: the list and pointer to image to replace
+%
+%    o image: the image or image list replacing the original
+%
+*/
+MagickExport void ReplaceImageInListReturnLast(Image **images,Image *image)
+{
+  assert(images != (Image **) NULL);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((*images) == (Image *) NULL)
+    return;
+  assert((*images)->signature == MagickSignature);
+
+  /* link previous pointer */
+  image=GetFirstImageInList(image);
+  image->previous=(*images)->previous;
+  if (image->previous != (Image *) NULL)
+    image->previous->next=image;
+
+  /* link next pointer - set image position to last replacement image */
+  image=GetLastImageInList(image);
+  image->next=(*images)->next;
+  if (image->next != (Image *) NULL)
+    image->next->previous=image;
+
+  /* destroy replaced image */
+  (void) DestroyImage(*images);
+  (*images)=image;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e v e r s e I m a g e L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReverseImageList() reverses the order of an image list.
+%  The list pointer is reset to that start of the re-ordered list.
+%
+%  The format of the ReverseImageList method is:
+%
+%      void ReverseImageList(Image **images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport void ReverseImageList(Image **images)
+{
+  Image
+    *next;
+
+  register Image
+    *p;
+
+  assert(images != (Image **) NULL);
+  if ((*images) == (Image *) NULL)
+    return;
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  for (p=(*images); p->next != (Image *) NULL; p=p->next) ;
+  *images=p;
+  for ( ; p != (Image *) NULL; p=p->next)
+  {
+    next=p->next;
+    p->next=p->previous;
+    p->previous=next;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p l i c e I m a g e I n t o L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SpliceImageIntoList() removes 'length' images from the list and replaces
+%  them with the specified splice. Removed images are returned.
+%
+%  The format of the SpliceImageIntoList method is:
+%
+%      SpliceImageIntoList(Image **images,const size_t,
+%        const Image *splice)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+%    o length: the length of the image list to remove.
+%
+%    o splice: Replace the removed image list with this list.
+%
+*/
+MagickExport Image *SpliceImageIntoList(Image **images,
+  const size_t length,const Image *splice)
+{
+  Image
+    *image,
+    *split;
+
+  register size_t
+    i;
+
+  assert(images != (Image **) NULL);
+  assert(splice != (Image *) NULL);
+  assert(splice->signature == MagickSignature);
+  if ((*images) == (Image *) NULL)
+    return((Image *) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  split=SplitImageList(*images);
+  AppendImageToList(images,splice);
+  image=(Image *) NULL;
+  for (i=0; (i < length) && (split != (Image *) NULL); i++)
+    AppendImageToList(&image,RemoveImageFromList(&split));
+  AppendImageToList(images,split);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p l i t I m a g e L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SplitImageList() splits an image into two lists, after given image
+%  The list that was split off is returned, which may be empty.
+%
+%  The format of the SplitImageList method is:
+%
+%      Image *SplitImageList(Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *SplitImageList(Image *images)
+{
+  if ((images == (Image *) NULL) || (images->next == (Image *) NULL))
+    return((Image *) NULL);
+  images=images->next;
+  images->previous->next=(Image *) NULL;
+  images->previous=(Image *) NULL;
+  return(images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S y n c I m a g e L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncImageList() synchronizes the scene numbers in an image list.
+%
+%  The format of the SyncImageList method is:
+%
+%      void SyncImageList(Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport void SyncImageList(Image *images)
+{
+  register Image
+    *p,
+    *q;
+
+  if (images == (Image *) NULL)
+    return;
+  assert(images->signature == MagickSignature);
+  for (p=images; p != (Image *) NULL; p=p->next)
+  {
+    for (q=p->next; q != (Image *) NULL; q=q->next)
+      if (p->scene == q->scene)
+        break;
+    if (q != (Image *) NULL)
+      break;
+  }
+  if (p == (Image *) NULL)
+    return;
+  for (p=images->next; p != (Image *) NULL; p=p->next)
+    p->scene=p->previous->scene+1;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S y n c N e x t I m a g e I n L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncNextImageInList() returns the next image in the list after the blob
+%  referenced is synchronized with the current image.
+%
+%  The format of the SyncNextImageInList method is:
+%
+%      Image *SyncNextImageInList(const Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o images: the image list.
+%
+*/
+MagickExport Image *SyncNextImageInList(const Image *images)
+{
+  if (images == (Image *) NULL)
+    return((Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->next == (Image *) NULL)
+    return((Image *) NULL);
+  if (images->blob != images->next->blob)
+    {
+      DestroyBlob(images->next);
+      images->next->blob=ReferenceBlob(images->blob);
+    }
+  images->next->compression=images->compression;
+  images->next->endian=images->endian;
+  return(images->next);
+}
diff --git a/MagickCore/list.h b/MagickCore/list.h
new file mode 100644
index 0000000..c77f4f9
--- /dev/null
+++ b/MagickCore/list.h
@@ -0,0 +1,65 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image list methods.
+*/
+#ifndef _MAGICKCORE_LIST_H
+#define _MAGICKCORE_LIST_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport Image
+  *CloneImageList(const Image *,ExceptionInfo *),
+  *CloneImages(const Image *,const char *,ExceptionInfo *),
+  *DestroyImageList(Image *),
+  *DuplicateImages(Image *,const size_t,const char *,ExceptionInfo *),
+  *GetFirstImageInList(const Image *),
+  *GetImageFromList(const Image *,const ssize_t),
+  *GetLastImageInList(const Image *),
+  *GetNextImageInList(const Image *),
+  *GetPreviousImageInList(const Image *),
+  **ImageListToArray(const Image *,ExceptionInfo *),
+  *NewImageList(void),
+  *RemoveImageFromList(Image **),
+  *RemoveLastImageFromList(Image **),
+  *RemoveFirstImageFromList(Image **),
+  *SpliceImageIntoList(Image **,const size_t,const Image *),
+  *SplitImageList(Image *),
+  *SyncNextImageInList(const Image *);
+
+extern MagickExport size_t
+  GetImageListLength(const Image *);
+
+extern MagickExport ssize_t
+  GetImageIndexInList(const Image *);
+
+extern MagickExport void
+  AppendImageToList(Image **,const Image *),
+  DeleteImageFromList(Image **),
+  DeleteImages(Image **,const char *,ExceptionInfo *),
+  InsertImageInList(Image **,Image *),
+  PrependImageToList(Image **,Image *),
+  ReplaceImageInList(Image **,Image *),
+  ReplaceImageInListReturnLast(Image **,Image *),
+  ReverseImageList(Image **),
+  SyncImageList(Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/locale.c b/MagickCore/locale.c
new file mode 100644
index 0000000..3e87b1e
--- /dev/null
+++ b/MagickCore/locale.c
@@ -0,0 +1,1413 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  L       OOO    CCCC   AAA   L      EEEEE                   %
+%                  L      O   O  C      A   A  L      E                       %
+%                  L      O   O  C      AAAAA  L      EEE                     %
+%                  L      O   O  C      A   A  L      E                       %
+%                  LLLLL   OOO    CCCC  A   A  LLLLL  EEEEE                   %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Locale Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define LocaleFilename  "locale.xml"
+#define MaxRecursionDepth  200
+
+/*
+  Typedef declarations.
+*/
+#if defined(__CYGWIN__)
+typedef struct _locale_t *locale_t;
+#endif
+
+/*
+  Static declarations.
+*/
+static const char
+  *LocaleMap =
+    "<?xml version=\"1.0\"?>"
+    "<localemap>"
+    "  <locale name=\"C\">"
+    "    <Exception>"
+    "     <Message name=\"\">"
+    "     </Message>"
+    "    </Exception>"
+    "  </locale>"
+    "</localemap>";
+
+static SemaphoreInfo
+  *locale_semaphore = (SemaphoreInfo *) NULL;
+
+static SplayTreeInfo
+  *locale_list = (SplayTreeInfo *) NULL;
+
+#if defined(MAGICKCORE_HAVE_STRTOD_L)
+static volatile locale_t
+  c_locale = (locale_t) NULL;
+#endif
+
+static volatile MagickBooleanType
+  instantiate_locale = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeLocaleList(ExceptionInfo *),
+  LoadLocaleLists(const char *,const char *,ExceptionInfo *);
+
+#if defined(MAGICKCORE_HAVE_STRTOD_L)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e C L o c a l e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
+%  errno set if it cannot be acquired.
+%
+%  The format of the AcquireCLocale method is:
+%
+%      locale_t AcquireCLocale(void)
+%
+*/
+static locale_t AcquireCLocale(void)
+{
+#if defined(MAGICKCORE_HAVE_NEWLOCALE)
+  if (c_locale == (locale_t) NULL)
+    c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  if (c_locale == (locale_t) NULL)
+    c_locale=_create_locale(LC_ALL,"C");
+#endif
+  return(c_locale);
+}
+#endif
+
+#if defined(MAGICKCORE_HAVE_STRTOD_L)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C L o c a l e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyCLocale() releases the resources allocated for a locale object
+%  returned by a call to the AcquireCLocale() method.
+%
+%  The format of the DestroyCLocale method is:
+%
+%      void DestroyCLocale(void)
+%
+*/
+static void DestroyCLocale(void)
+{
+#if defined(MAGICKCORE_HAVE_NEWLOCALE)
+  if (c_locale != (locale_t) NULL)
+    freelocale(c_locale);
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  if (c_locale != (locale_t) NULL)
+    _free_locale(c_locale);
+#endif
+  c_locale=(locale_t) NULL;
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y L o c a l e O p t i o n s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyLocaleOptions() releases memory associated with an locale
+%  messages.
+%
+%  The format of the DestroyProfiles method is:
+%
+%      LinkedListInfo *DestroyLocaleOptions(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+
+static void *DestroyOptions(void *message)
+{
+  return(DestroyStringInfo((StringInfo *) message));
+}
+
+MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
+{
+  assert(messages != (LinkedListInfo *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(DestroyLinkedList(messages,DestroyOptions));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  F o r m a t L o c a l e F i l e                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatLocaleFile() prints formatted output of a variable argument list to a
+%  file in the "C" locale.
+%
+%  The format of the FormatLocaleFile method is:
+%
+%      ssize_t FormatLocaleFile(FILE *file,const char *format,...)
+%
+%  A description of each parameter follows.
+%
+%   o file:  the file.
+%
+%   o format:  A file describing the format to use to write the remaining
+%     arguments.
+%
+*/
+
+MagickExport ssize_t FormatLocaleFileList(FILE *file,
+  const char *restrict format,va_list operands)
+{
+  ssize_t
+    n;
+
+#if defined(MAGICKCORE_HAVE_VFPRINTF_L)
+  {
+    locale_t
+      locale;
+
+    locale=AcquireCLocale();
+    if (locale == (locale_t) NULL)
+      n=(ssize_t) vfprintf(file,format,operands);
+    else
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+      n=(ssize_t) vfprintf_l(file,format,locale,operands);
+#else
+      n=(ssize_t) vfprintf_l(file,locale,format,operands);
+#endif
+  }
+#else
+#if defined(MAGICKCORE_HAVE_USELOCALE)
+  {
+    locale_t
+      locale,
+      previous_locale;
+
+    locale=AcquireCLocale();
+    if (locale == (locale_t) NULL)
+      n=(ssize_t) vfprintf(file,format,operands);
+    else
+      {
+        previous_locale=uselocale(locale);
+        n=(ssize_t) vfprintf(file,format,operands);
+        uselocale(previous_locale);
+      }
+  }
+#else
+  n=(ssize_t) vfprintf(file,format,operands);
+#endif
+#endif
+  return(n);
+}
+
+MagickExport ssize_t FormatLocaleFile(FILE *file,const char *restrict format,
+  ...)
+{
+  ssize_t
+    n;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  n=FormatLocaleFileList(file,format,operands);
+  va_end(operands);
+  return(n);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  F o r m a t L o c a l e S t r i n g                                        %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatLocaleString() prints formatted output of a variable argument list to
+%  a string buffer in the "C" locale.
+%
+%  The format of the FormatLocaleString method is:
+%
+%      ssize_t FormatLocaleString(char *string,const size_t length,
+%        const char *format,...)
+%
+%  A description of each parameter follows.
+%
+%   o string:  FormatLocaleString() returns the formatted string in this
+%     character buffer.
+%
+%   o length: the maximum length of the string.
+%
+%   o format:  A string describing the format to use to write the remaining
+%     arguments.
+%
+*/
+
+MagickExport ssize_t FormatLocaleStringList(char *restrict string,
+  const size_t length,const char *restrict format,va_list operands)
+{
+  ssize_t
+    n;
+
+#if defined(MAGICKCORE_HAVE_VSNPRINTF_L)
+  {
+    locale_t
+      locale;
+
+    locale=AcquireCLocale();
+    if (locale == (locale_t) NULL)
+      n=(ssize_t) vsnprintf(string,length,format,operands);
+    else
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+      n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
+#else
+      n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
+#endif
+  }
+#elif defined(MAGICKCORE_HAVE_VSNPRINTF)
+#if defined(MAGICKCORE_HAVE_USELOCALE)
+  {
+    locale_t
+      locale,
+      previous_locale;
+
+    locale=AcquireCLocale();
+    if (locale == (locale_t) NULL)
+      n=(ssize_t) vsnprintf(string,length,format,operands);
+    else
+      {
+        previous_locale=uselocale(locale);
+        n=(ssize_t) vsnprintf(string,length,format,operands);
+        uselocale(previous_locale);
+      }
+  }
+#else
+  n=(ssize_t) vsnprintf(string,length,format,operands);
+#endif
+#else
+  n=(ssize_t) vsprintf(string,format,operands);
+#endif
+  if (n < 0)
+    string[length-1]='\0';
+  return(n);
+}
+
+MagickExport ssize_t FormatLocaleString(char *restrict string,
+  const size_t length,const char *restrict format,...)
+{
+  ssize_t
+    n;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  n=FormatLocaleStringList(string,length,format,operands);
+  va_end(operands);
+  return(n);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t L o c a l e I n f o _                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleInfo_() searches the locale list for the specified tag and if
+%  found returns attributes for that element.
+%
+%  The format of the GetLocaleInfo method is:
+%
+%      const LocaleInfo *GetLocaleInfo_(const char *tag,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o tag: the locale tag.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
+  ExceptionInfo *exception)
+{
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((locale_list == (SplayTreeInfo *) NULL) ||
+      (instantiate_locale == MagickFalse))
+    if (InitializeLocaleList(exception) == MagickFalse)
+      return((const LocaleInfo *) NULL);
+  if ((locale_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(locale_list) == 0))
+    return((const LocaleInfo *) NULL);
+  if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
+    {
+      ResetSplayTreeIterator(locale_list);
+      return((const LocaleInfo *) GetNextValueInSplayTree(locale_list));
+    }
+  return((const LocaleInfo *) GetValueFromSplayTree(locale_list,tag));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o c a l e I n f o L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleInfoList() returns any locale messages that match the
+%  specified pattern.
+%
+%  The format of the GetLocaleInfoList function is:
+%
+%      const LocaleInfo **GetLocaleInfoList(const char *pattern,
+%        size_t *number_messages,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_messages:  This integer returns the number of locale messages in
+%    the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int LocaleInfoCompare(const void *x,const void *y)
+{
+  const LocaleInfo
+    **p,
+    **q;
+
+  p=(const LocaleInfo **) x,
+  q=(const LocaleInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->tag,(*q)->tag));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
+  size_t *number_messages,ExceptionInfo *exception)
+{
+  const LocaleInfo
+    **messages;
+
+  register const LocaleInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate locale list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_messages != (size_t *) NULL);
+  *number_messages=0;
+  p=GetLocaleInfo_("*",exception);
+  if (p == (const LocaleInfo *) NULL)
+    return((const LocaleInfo **) NULL);
+  messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
+  if (messages == (const LocaleInfo **) NULL)
+    return((const LocaleInfo **) NULL);
+  /*
+    Generate locale list.
+  */
+  LockSemaphoreInfo(locale_semaphore);
+  ResetSplayTreeIterator(locale_list);
+  p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
+  for (i=0; p != (const LocaleInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
+      messages[i++]=p;
+    p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
+  }
+  UnlockSemaphoreInfo(locale_semaphore);
+  qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
+  messages[i]=(LocaleInfo *) NULL;
+  *number_messages=(size_t) i;
+  return(messages);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o c a l e L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleList() returns any locale messages that match the specified
+%  pattern.
+%
+%  The format of the GetLocaleList function is:
+%
+%      char **GetLocaleList(const char *pattern,size_t *number_messages,
+%        Exceptioninfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_messages:  This integer returns the number of messages in the
+%      list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int LocaleTagCompare(const void *x,const void *y)
+{
+  register char
+    **p,
+    **q;
+
+  p=(char **) x;
+  q=(char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetLocaleList(const char *pattern,
+  size_t *number_messages,ExceptionInfo *exception)
+{
+  char
+    **messages;
+
+  register const LocaleInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate locale list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_messages != (size_t *) NULL);
+  *number_messages=0;
+  p=GetLocaleInfo_("*",exception);
+  if (p == (const LocaleInfo *) NULL)
+    return((char **) NULL);
+  messages=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(locale_list)+1UL,sizeof(*messages));
+  if (messages == (char **) NULL)
+    return((char **) NULL);
+  LockSemaphoreInfo(locale_semaphore);
+  p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
+  for (i=0; p != (const LocaleInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
+      messages[i++]=ConstantString(p->tag);
+    p=(const LocaleInfo *) GetNextValueInSplayTree(locale_list);
+  }
+  UnlockSemaphoreInfo(locale_semaphore);
+  qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
+  messages[i]=(char *) NULL;
+  *number_messages=(size_t) i;
+  return(messages);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o c a l e M e s s a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleMessage() returns a message in the current locale that matches the
+%  supplied tag.
+%
+%  The format of the GetLocaleMessage method is:
+%
+%      const char *GetLocaleMessage(const char *tag)
+%
+%  A description of each parameter follows:
+%
+%    o tag: Return a message that matches this tag in the current locale.
+%
+*/
+MagickExport const char *GetLocaleMessage(const char *tag)
+{
+  char
+    name[MaxTextExtent];
+
+  const LocaleInfo
+    *locale_info;
+
+  ExceptionInfo
+    *exception;
+
+  if ((tag == (const char *) NULL) || (*tag == '\0'))
+    return(tag);
+  exception=AcquireExceptionInfo();
+  (void) FormatLocaleString(name,MaxTextExtent,"%s/",tag);
+  locale_info=GetLocaleInfo_(name,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (locale_info != (const LocaleInfo *) NULL)
+    return(locale_info->message);
+  return(tag);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t L o c a l e O p t i o n s                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleOptions() returns any Magick configuration messages associated
+%  with the specified filename.
+%
+%  The format of the GetLocaleOptions method is:
+%
+%      LinkedListInfo *GetLocaleOptions(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the locale file tag.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
+  ExceptionInfo *exception)
+{
+  char
+    path[MaxTextExtent];
+
+  const char
+    *element;
+
+  LinkedListInfo
+    *messages,
+    *paths;
+
+  StringInfo
+    *xml;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) CopyMagickString(path,filename,MaxTextExtent);
+  /*
+    Load XML from configuration files to linked-list.
+  */
+  messages=NewLinkedList(0);
+  paths=GetConfigurePaths(filename,exception);
+  if (paths != (LinkedListInfo *) NULL)
+    {
+      ResetLinkedListIterator(paths);
+      element=(const char *) GetNextValueInLinkedList(paths);
+      while (element != (const char *) NULL)
+      {
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
+        (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
+          "Searching for locale file: \"%s\"",path);
+        xml=ConfigureFileToStringInfo(path);
+        if (xml != (StringInfo *) NULL)
+          (void) AppendValueToLinkedList(messages,xml);
+        element=(const char *) GetNextValueInLinkedList(paths);
+      }
+      paths=DestroyLinkedList(paths,RelinquishMagickMemory);
+    }
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    char
+      *blob;
+
+    blob=(char *) NTResourceToBlob(filename);
+    if (blob != (char *) NULL)
+      {
+        xml=StringToStringInfo(blob);
+        (void) AppendValueToLinkedList(messages,xml);
+        blob=DestroyString(blob);
+      }
+  }
+#endif
+  ResetLinkedListIterator(messages);
+  return(messages);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o c a l e V a l u e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLocaleValue() returns the message associated with the locale info.
+%
+%  The format of the GetLocaleValue method is:
+%
+%      const char *GetLocaleValue(const LocaleInfo *locale_info)
+%
+%  A description of each parameter follows:
+%
+%    o locale_info:  The locale info.
+%
+*/
+MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(locale_info != (LocaleInfo *) NULL);
+  assert(locale_info->signature == MagickSignature);
+  return(locale_info->message);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e L o c a l e L i s t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeLocaleList() initializes the locale list.
+%
+%  The format of the InitializeLocaleList method is:
+%
+%      MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeLocaleList(ExceptionInfo *exception)
+{
+  if ((locale_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_locale == MagickFalse))
+    {
+      if (locale_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&locale_semaphore);
+      LockSemaphoreInfo(locale_semaphore);
+      if ((locale_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_locale == MagickFalse))
+        {
+          char
+            *locale;
+
+          register const char
+            *p;
+
+          locale=(char *) NULL;
+          p=setlocale(LC_CTYPE,(const char *) NULL);
+          if (p != (const char *) NULL)
+            locale=ConstantString(p);
+          if (locale == (char *) NULL)
+            locale=GetEnvironmentValue("LC_ALL");
+          if (locale == (char *) NULL)
+            locale=GetEnvironmentValue("LC_MESSAGES");
+          if (locale == (char *) NULL)
+            locale=GetEnvironmentValue("LC_CTYPE");
+          if (locale == (char *) NULL)
+            locale=GetEnvironmentValue("LANG");
+          if (locale == (char *) NULL)
+            locale=ConstantString("C");
+          (void) LoadLocaleLists(LocaleFilename,locale,exception);
+          locale=DestroyString(locale);
+          instantiate_locale=MagickTrue;
+        }
+      UnlockSemaphoreInfo(locale_semaphore);
+    }
+  return(locale_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n t e r p r e t L o c a l e V a l u e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpretLocaleValue() interprets the string as a floating point number in
+%  the "C" locale and returns its value as a double. If sentinal is not a null
+%  pointer, the method also sets the value pointed by sentinal to point to the
+%  first character after the number.
+%
+%  The format of the InterpretLocaleValue method is:
+%
+%      double InterpretLocaleValue(const char *value,char **sentinal)
+%
+%  A description of each parameter follows:
+%
+%    o value: the string value.
+%
+%    o sentinal:  if sentinal is not NULL, a pointer to the character after the
+%      last character used in the conversion is stored in the location
+%      referenced by sentinal.
+%
+*/
+MagickExport double InterpretLocaleValue(const char *restrict string,
+  char **restrict sentinal)
+{
+  double
+    value;
+
+#if defined(MAGICKCORE_HAVE_STRTOD_L)
+  {
+    locale_t
+      locale;
+
+    locale=AcquireCLocale();
+    if (locale == (locale_t) NULL)
+      value=strtod(string,sentinal);
+    else
+      value=strtod_l(string,sentinal,locale);
+  }
+#else
+  value=strtod(string,sentinal);
+#endif
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t L o c a l e I n f o                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListLocaleInfo() lists the locale info to a file.
+%
+%  The format of the ListLocaleInfo method is:
+%
+%      MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const char
+    *path;
+
+  const LocaleInfo
+    **locale_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_messages;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  number_messages=0;
+  locale_info=GetLocaleInfoList("*",&number_messages,exception);
+  if (locale_info == (const LocaleInfo **) NULL)
+    return(MagickFalse);
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_messages; i++)
+  {
+    if (locale_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,locale_info[i]->path) != 0))
+      {
+        if (locale_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
+        (void) FormatLocaleFile(file,"Tag/Message\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=locale_info[i]->path;
+    (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
+    if (locale_info[i]->message != (char *) NULL)
+      (void) FormatLocaleFile(file,"  %s",locale_info[i]->message);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  locale_info=(const LocaleInfo **)
+    RelinquishMagickMemory((void *) locale_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d L o c a l e L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadLocaleList() loads the locale configuration file which provides a mapping
+%  between locale attributes and a locale name.
+%
+%  The format of the LoadLocaleList method is:
+%
+%      MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The locale list in XML format.
+%
+%    o filename:  The locale list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void ChopLocaleComponents(char *path,const size_t components)
+{
+  register char
+    *p;
+
+  ssize_t
+    count;
+
+  if (*path == '\0')
+    return;
+  p=path+strlen(path)-1;
+  if (*p == '/')
+    *p='\0';
+  for (count=0; (count < (ssize_t) components) && (p > path); p--)
+    if (*p == '/')
+      {
+        *p='\0';
+        count++;
+      }
+  if (count < (ssize_t) components)
+    *path='\0';
+}
+
+static void *DestroyLocaleNode(void *locale_info)
+{
+  register LocaleInfo
+    *p;
+
+  p=(LocaleInfo *) locale_info;
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  if (p->tag != (char *) NULL)
+    p->tag=DestroyString(p->tag);
+  if (p->message != (char *) NULL)
+    p->message=DestroyString(p->message);
+  return(RelinquishMagickMemory(p));
+}
+
+static void LocaleFatalErrorHandler(
+  const ExceptionType magick_unused(severity),
+  const char *reason,const char *description)
+{
+  if (reason == (char *) NULL)
+    return;
+  (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
+  if (description != (char *) NULL)
+    (void) FormatLocaleFile(stderr," (%s)",description);
+  (void) FormatLocaleFile(stderr,".\n");
+  (void) fflush(stderr);
+  exit(1);
+}
+
+
+static MagickBooleanType LoadLocaleList(const char *xml,const char *filename,
+  const char *locale,const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    message[MaxTextExtent],
+    tag[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  FatalErrorHandler
+    fatal_handler;
+
+  LocaleInfo
+    *locale_info;
+
+  MagickBooleanType
+    status;
+
+  register char
+    *p;
+
+  /*
+    Read the locale configure file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading locale configure file \"%s\" ...",filename);
+  if (xml == (const char *) NULL)
+    return(MagickFalse);
+  if (locale_list == (SplayTreeInfo *) NULL)
+    {
+      locale_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
+        DestroyLocaleNode);
+      if (locale_list == (SplayTreeInfo *) NULL)
+        return(MagickFalse);
+    }
+  status=MagickTrue;
+  locale_info=(LocaleInfo *) NULL;
+  *tag='\0';
+  *message='\0';
+  *keyword='\0';
+  fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
+  token=AcquireString(xml);
+  for (q=(char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+        {
+          GetMagickToken(q,&q,token);
+          while (isspace((int) ((unsigned char) *q)) != 0)
+            q++;
+        }
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+        {
+          GetMagickToken(q,&q,token);
+          while (isspace((int) ((unsigned char) *q)) != 0)
+            q++;
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"locale") == 0)
+            {
+              if (LocaleCompare(locale,token) != 0)
+                break;
+              continue;
+            }
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  *path='\0';
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadLocaleList(xml,path,locale,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<locale") == 0)
+      {
+        /*
+          Locale element.
+        */
+        while ((*token != '>') && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"</locale>") == 0)
+      {
+        ChopLocaleComponents(tag,1);
+        (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<localemap>") == 0)
+      continue;
+    if (LocaleCompare(keyword,"</localemap>") == 0)
+      continue;
+    if (LocaleCompare(keyword,"<message") == 0)
+      {
+        /*
+          Message element.
+        */
+        while ((*token != '>') && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"name") == 0)
+            {
+              (void) ConcatenateMagickString(tag,token,MaxTextExtent);
+              (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
+            }
+        }
+        for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
+        while (isspace((int) ((unsigned char) *p)) != 0)
+          p++;
+        q--;
+        while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
+          q--;
+        (void) CopyMagickString(message,p,(size_t) (q-p+2));
+        locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
+        if (locale_info == (LocaleInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(locale_info,0,sizeof(*locale_info));
+        locale_info->path=ConstantString(filename);
+        locale_info->tag=ConstantString(tag);
+        locale_info->message=ConstantString(message);
+        locale_info->signature=MagickSignature;
+        status=AddValueToSplayTree(locale_list,locale_info->tag,locale_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            locale_info->tag);
+        (void) ConcatenateMagickString(tag,message,MaxTextExtent);
+        (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
+        q++;
+        continue;
+      }
+    if (LocaleCompare(keyword,"</message>") == 0)
+      {
+        ChopLocaleComponents(tag,2);
+        (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
+        continue;
+      }
+    if (*keyword == '<')
+      {
+        /*
+          Subpath element.
+        */
+        if (*(keyword+1) == '?')
+          continue;
+        if (*(keyword+1) == '/')
+          {
+            ChopLocaleComponents(tag,1);
+            if (*tag != '\0')
+              (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
+            continue;
+          }
+        token[strlen(token)-1]='\0';
+        (void) CopyMagickString(token,token+1,MaxTextExtent);
+        (void) ConcatenateMagickString(tag,token,MaxTextExtent);
+        (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
+        continue;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  (void) SetFatalErrorHandler(fatal_handler);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d L o c a l e L i s t s                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadLocaleList() loads one or more locale configuration file which
+%  provides a mapping between locale attributes and a locale tag.
+%
+%  The format of the LoadLocaleLists method is:
+%
+%      MagickBooleanType LoadLocaleLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file tag.
+%
+%    o locale: the actual locale.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadLocaleLists(const char *filename,
+  const char *locale,ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadLocaleList(LocaleMap,"built-in",locale,0,exception));
+#else
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  status=MagickFalse;
+  options=GetLocaleOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),locale,0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyLocaleOptions(options);
+  if ((locale_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(locale_list) == 0))
+    {
+      options=GetLocaleOptions("english.xml",exception);
+      option=(const StringInfo *) GetNextValueInLinkedList(options);
+      while (option != (const StringInfo *) NULL)
+      {
+        status|=LoadLocaleList((const char *) GetStringInfoDatum(option),
+          GetStringInfoPath(option),locale,0,exception);
+        option=(const StringInfo *) GetNextValueInLinkedList(options);
+      }
+      options=DestroyLocaleOptions(options);
+    }
+  if ((locale_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(locale_list) == 0))
+    status|=LoadLocaleList(LocaleMap,"built-in",locale,0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o c a l e C o m p o n e n t G e n e s i s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LocaleComponentGenesis() instantiates the locale component.
+%
+%  The format of the LocaleComponentGenesis method is:
+%
+%      MagickBooleanType LocaleComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType LocaleComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&locale_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o c a l e C o m p o n e n t T e r m i n u s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LocaleComponentTerminus() destroys the locale component.
+%
+%  The format of the LocaleComponentTerminus method is:
+%
+%      LocaleComponentTerminus(void)
+%
+*/
+MagickExport void LocaleComponentTerminus(void)
+{
+  if (locale_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&locale_semaphore);
+  LockSemaphoreInfo(locale_semaphore);
+#if defined(MAGICKCORE_HAVE_STRTOD_L)
+  DestroyCLocale();
+#endif
+  instantiate_locale=MagickFalse;
+  UnlockSemaphoreInfo(locale_semaphore);
+  DestroySemaphoreInfo(&locale_semaphore);
+}
diff --git a/MagickCore/locale_.h b/MagickCore/locale_.h
new file mode 100644
index 0000000..98ee0fc
--- /dev/null
+++ b/MagickCore/locale_.h
@@ -0,0 +1,79 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore locale methods.
+*/
+#ifndef _MAGICKCORE_LOCALE_H
+#define _MAGICKCORE_LOCALE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/hashmap.h"
+
+typedef struct _LocaleInfo
+{
+  char
+    *path,
+    *tag,
+    *message;
+                                                                                
+  MagickBooleanType
+    stealth;
+                                                                                
+  size_t
+    signature;
+} LocaleInfo;
+
+extern MagickExport char
+  **GetLocaleList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetLocaleMessage(const char *);
+
+extern MagickExport const LocaleInfo
+  *GetLocaleInfo_(const char *,ExceptionInfo *),
+  **GetLocaleInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport double
+  InterpretLocaleValue(const char *restrict,char **restrict);
+
+extern MagickExport LinkedListInfo
+  *DestroyLocaleOptions(LinkedListInfo *),
+  *GetLocaleOptions(const char *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ListLocaleInfo(FILE *,ExceptionInfo *),
+  LocaleComponentGenesis(void);
+
+extern MagickExport ssize_t
+  FormatLocaleFile(FILE *,const char *restrict,...)
+    magick_attribute((format (printf,2,3))),
+  FormatLocaleFileList(FILE *,const char *restrict,va_list)
+    magick_attribute((format (printf,2,0))),
+  FormatLocaleString(char *restrict,const size_t,const char *restrict,...)
+    magick_attribute((format (printf,3,4))),
+  FormatLocaleStringList(char *restrict,const size_t,const char *restrict,
+    va_list) magick_attribute((format (printf,3,0)));
+
+extern MagickExport void
+  LocaleComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/log.c b/MagickCore/log.c
new file mode 100644
index 0000000..494a70c
--- /dev/null
+++ b/MagickCore/log.c
@@ -0,0 +1,1770 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                             L       OOO    GGGG                             %
+%                             L      O   O  G                                 %
+%                             L      O   O  G GG                              %
+%                             L      O   O  G   G                             %
+%                             LLLLL   OOO    GGG                              %
+%                                                                             %
+%                                                                             %
+%                             MagickCore Log Events                           %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                September 2002                               %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/thread_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define LogFilename  "log.xml"
+
+/*
+  Typedef declarations.
+*/
+typedef enum
+{
+  UndefinedHandler = 0x0000,
+  NoHandler = 0x0000,
+  ConsoleHandler = 0x0001,
+  StdoutHandler = 0x0002,
+  StderrHandler = 0x0004,
+  FileHandler = 0x0008,
+  DebugHandler = 0x0010,
+  EventHandler = 0x0020
+} LogHandlerType;
+
+typedef struct _EventInfo
+{
+  char
+    *name;
+
+  LogEventType
+    event;
+} EventInfo;
+
+typedef struct _HandlerInfo
+{
+  const char
+    *name;
+
+  LogHandlerType
+    handler;
+} HandlerInfo;
+
+struct _LogInfo
+{
+  LogEventType
+    event_mask;
+
+  LogHandlerType
+    handler_mask;
+
+  char
+    *path,
+    *name,
+    *filename,
+    *format;
+
+  size_t
+    generations,
+    limit;
+
+  FILE
+    *file;
+
+  size_t
+    generation;
+
+  MagickBooleanType
+    append,
+    exempt,
+    stealth;
+
+  TimerInfo
+    timer;
+
+  size_t
+    signature;
+};
+
+typedef struct _LogMapInfo
+{
+  const LogEventType
+    event_mask;
+
+  const LogHandlerType
+    handler_mask;
+
+  const char
+    *filename,
+    *format;
+} LogMapInfo;
+
+/*
+  Static declarations.
+*/
+static const HandlerInfo
+  LogHandlers[] =
+  {
+    { "console", ConsoleHandler },
+    { "debug", DebugHandler },
+    { "event", EventHandler },
+    { "file", FileHandler },
+    { "none", NoHandler },
+    { "stderr", StderrHandler },
+    { "stdout", StdoutHandler },
+    { (char *) NULL, UndefinedHandler }
+  };
+
+static const LogMapInfo
+  LogMap[] =
+  {
+    { NoEvents, ConsoleHandler, "Magick-%d.log",
+      "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n  %e" }
+  };
+
+static char
+  log_name[MaxTextExtent] = "Magick";
+
+static LinkedListInfo
+  *log_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *log_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_log = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static LogHandlerType
+  ParseLogHandlers(const char *);
+
+static LogInfo
+  *GetLogInfo(const char *,ExceptionInfo *);
+
+static MagickBooleanType
+  InitializeLogList(ExceptionInfo *),
+  LoadLogLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o s e M a g i c k L o g                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloseMagickLog() closes the Magick log.
+%
+%  The format of the CloseMagickLog method is:
+%
+%      CloseMagickLog(void)
+%
+*/
+MagickExport void CloseMagickLog(void)
+{
+  ExceptionInfo
+    *exception;
+
+  LogInfo
+    *log_info;
+
+  if (IsEventLogging() == MagickFalse)
+    return;
+  exception=AcquireExceptionInfo();
+  log_info=GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  LockSemaphoreInfo(log_semaphore);
+  if (log_info->file != (FILE *) NULL)
+    {
+      if (log_info->append == MagickFalse)
+        (void) FormatLocaleFile(log_info->file,"</log>\n");
+      (void) fclose(log_info->file);
+      log_info->file=(FILE *) NULL;
+    }
+  UnlockSemaphoreInfo(log_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t L o g I n f o                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLogInfo() searches the log list for the specified name and if found
+%  returns attributes for that log.
+%
+%  The format of the GetLogInfo method is:
+%
+%      LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the log name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
+{
+  register LogInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((log_list == (LinkedListInfo *) NULL) || (instantiate_log == MagickFalse))
+    if (InitializeLogList(exception) == MagickFalse)
+      return((LogInfo *) NULL);
+  if ((log_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(log_list) != MagickFalse))
+    return((LogInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    return((LogInfo *) GetValueFromLinkedList(log_list,0));
+  /*
+    Search for log tag.
+  */
+  LockSemaphoreInfo(log_semaphore);
+  ResetLinkedListIterator(log_list);
+  p=(LogInfo *) GetNextValueInLinkedList(log_list);
+  while (p != (LogInfo *) NULL)
+  {
+    if (LocaleCompare(name,p->name) == 0)
+      break;
+    p=(LogInfo *) GetNextValueInLinkedList(log_list);
+  }
+  if (p != (LogInfo *) NULL)
+    (void) InsertValueInLinkedList(log_list,0,
+      RemoveElementByValueFromLinkedList(log_list,p));
+  UnlockSemaphoreInfo(log_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o g I n f o L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLogInfoList() returns any logs that match the specified pattern.
+%
+%  The format of the GetLogInfoList function is:
+%
+%      const LogInfo **GetLogInfoList(const char *pattern,
+%        size_t *number_preferences,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_preferences:  This integer returns the number of logs in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int LogInfoCompare(const void *x,const void *y)
+{
+  const LogInfo
+    **p,
+    **q;
+
+  p=(const LogInfo **) x,
+  q=(const LogInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->name,(*q)->name));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const LogInfo **GetLogInfoList(const char *pattern,
+  size_t *number_preferences,ExceptionInfo *exception)
+{
+  const LogInfo
+    **preferences;
+
+  register const LogInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate log list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_preferences != (size_t *) NULL);
+  *number_preferences=0;
+  p=GetLogInfo("*",exception);
+  if (p == (const LogInfo *) NULL)
+    return((const LogInfo **) NULL);
+  preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
+  if (preferences == (const LogInfo **) NULL)
+    return((const LogInfo **) NULL);
+  /*
+    Generate log list.
+  */
+  LockSemaphoreInfo(log_semaphore);
+  ResetLinkedListIterator(log_list);
+  p=(const LogInfo *) GetNextValueInLinkedList(log_list);
+  for (i=0; p != (const LogInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      preferences[i++]=p;
+    p=(const LogInfo *) GetNextValueInLinkedList(log_list);
+  }
+  UnlockSemaphoreInfo(log_semaphore);
+  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
+  preferences[i]=(LogInfo *) NULL;
+  *number_preferences=(size_t) i;
+  return(preferences);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o g L i s t                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLogList() returns any logs that match the specified pattern.
+%
+%  The format of the GetLogList function is:
+%
+%      char **GetLogList(const char *pattern,size_t *number_preferences,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_preferences:  This integer returns the number of logs in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int LogCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetLogList(const char *pattern,
+  size_t *number_preferences,ExceptionInfo *exception)
+{
+  char
+    **preferences;
+
+  register const LogInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate log list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_preferences != (size_t *) NULL);
+  *number_preferences=0;
+  p=GetLogInfo("*",exception);
+  if (p == (const LogInfo *) NULL)
+    return((char **) NULL);
+  preferences=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
+  if (preferences == (char **) NULL)
+    return((char **) NULL);
+  /*
+    Generate log list.
+  */
+  LockSemaphoreInfo(log_semaphore);
+  ResetLinkedListIterator(log_list);
+  p=(const LogInfo *) GetNextValueInLinkedList(log_list);
+  for (i=0; p != (const LogInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      preferences[i++]=ConstantString(p->name);
+    p=(const LogInfo *) GetNextValueInLinkedList(log_list);
+  }
+  UnlockSemaphoreInfo(log_semaphore);
+  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
+  preferences[i]=(char *) NULL;
+  *number_preferences=(size_t) i;
+  return(preferences);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t L o g N a m e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetLogName() returns the current log name.
+%
+%  The format of the GetLogName method is:
+%
+%      const char *GetLogName(void)
+%
+*/
+MagickExport const char *GetLogName(void)
+{
+  return(log_name);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e L o g L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeLogList() initialize the log list.
+%
+%  The format of the InitializeLogList method is:
+%
+%      MagickBooleanType InitializeLogList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeLogList(ExceptionInfo *exception)
+{
+  if ((log_list == (LinkedListInfo *) NULL) && (instantiate_log == MagickFalse))
+    {
+      if (log_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&log_semaphore);
+      LockSemaphoreInfo(log_semaphore);
+      if ((log_list == (LinkedListInfo *) NULL) &&
+          (instantiate_log == MagickFalse))
+        {
+          (void) LoadLogLists(LogFilename,exception);
+          instantiate_log=MagickTrue;
+        }
+      UnlockSemaphoreInfo(log_semaphore);
+    }
+  return(log_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I s E v e n t L o g g i n g                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
+%  MagickFalse.
+%
+%  The format of the IsEventLogging method is:
+%
+%      MagickBooleanType IsEventLogging(void)
+%
+*/
+MagickExport MagickBooleanType IsEventLogging(void)
+{
+  const LogInfo
+    *log_info;
+
+  ExceptionInfo
+    *exception;
+
+  if ((log_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(log_list) != MagickFalse))
+    return(MagickFalse);
+  exception=AcquireExceptionInfo();
+  log_info=GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  return(log_info->event_mask != NoEvents ? MagickTrue : MagickFalse);
+}
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t L o g I n f o                                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListLogInfo() lists the log info to a file.
+%
+%  The format of the ListLogInfo method is:
+%
+%      MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
+{
+#define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
+
+  char
+    limit[MaxTextExtent];
+
+  const char
+    *path;
+
+  const LogInfo
+    **log_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_aliases;
+
+  ssize_t
+    j;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  log_info=GetLogInfoList("*",&number_aliases,exception);
+  if (log_info == (const LogInfo **) NULL)
+    return(MagickFalse);
+  j=0;
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_aliases; i++)
+  {
+    if (log_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,log_info[i]->path) != 0))
+      {
+        if (log_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path);
+        (void) FormatLocaleFile(file,
+          "Filename       Generations     Limit  Format\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=log_info[i]->path;
+    if (log_info[i]->filename != (char *) NULL)
+      {
+        (void) FormatLocaleFile(file,"%s",log_info[i]->filename);
+        for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
+          (void) FormatLocaleFile(file," ");
+      }
+    (void) FormatLocaleFile(file,"%9g  ",(double) log_info[i]->generations);
+    (void) FormatMagickSize(MegabytesToBytes(log_info[i]->limit),MagickFalse,
+      limit);
+    (void) FormatLocaleFile(file,"%8sB  ",limit);
+    if (log_info[i]->format != (char *) NULL)
+      (void) FormatLocaleFile(file,"%s",log_info[i]->format);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o g C o m p o n e n t G e n e s i s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LogComponentGenesis() instantiates the log component.
+%
+%  The format of the LogComponentGenesis method is:
+%
+%      MagickBooleanType LogComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType LogComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&log_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o g C o m p o n e n t T e r m i n u s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LogComponentTerminus() destroys the logging component.
+%
+%  The format of the LogComponentTerminus method is:
+%
+%      LogComponentTerminus(void)
+%
+*/
+
+static void *DestroyLogElement(void *log_info)
+{
+  register LogInfo
+    *p;
+
+  p=(LogInfo *) log_info;
+  if (p->file != (FILE *) NULL)
+    {
+      if (p->append == MagickFalse)
+        (void) FormatLocaleFile(p->file,"</log>\n");
+      (void) fclose(p->file);
+      p->file=(FILE *) NULL;
+    }
+  if (p->exempt == MagickFalse)
+    {
+      if (p->format != (char *) NULL)
+        p->format=DestroyString(p->format);
+      if (p->path != (char *) NULL)
+        p->path=DestroyString(p->path);
+      if (p->filename != (char *) NULL)
+        p->filename=DestroyString(p->filename);
+    }
+  p=(LogInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void LogComponentTerminus(void)
+{
+  if (log_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&log_semaphore);
+  LockSemaphoreInfo(log_semaphore);
+  if (log_list != (LinkedListInfo *) NULL)
+    log_list=DestroyLinkedList(log_list,DestroyLogElement);
+  instantiate_log=MagickFalse;
+  UnlockSemaphoreInfo(log_semaphore);
+  DestroySemaphoreInfo(&log_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L o g M a g i c k E v e n t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LogMagickEvent() logs an event as determined by the log configuration file.
+%  If an error occurs, MagickFalse is returned otherwise MagickTrue.
+%
+%  The format of the LogMagickEvent method is:
+%
+%      MagickBooleanType LogMagickEvent(const LogEventType type,
+%        const char *module,const char *function,const size_t line,
+%        const char *format,...)
+%
+%  A description of each parameter follows:
+%
+%    o type: the event type.
+%
+%    o filename: the source module filename.
+%
+%    o function: the function name.
+%
+%    o line: the line number of the source module.
+%
+%    o format: the output format.
+%
+*/
+static char *TranslateEvent(const LogEventType magick_unused(type),
+  const char *module,const char *function,const size_t line,
+  const char *domain,const char *event)
+{
+  char
+    *text;
+
+  double
+    elapsed_time,
+    user_time;
+
+  ExceptionInfo
+    *exception;
+
+  LogInfo
+    *log_info;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  size_t
+    extent;
+
+  time_t
+    seconds;
+
+  exception=AcquireExceptionInfo();
+  log_info=(LogInfo *) GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  seconds=time((time_t *) NULL);
+  elapsed_time=GetElapsedTime(&log_info->timer);
+  user_time=GetUserTime(&log_info->timer);
+  text=AcquireString(event);
+  if (log_info->format == (char *) NULL)
+    return(text);
+  extent=strlen(event)+MaxTextExtent;
+  if (LocaleCompare(log_info->format,"xml") == 0)
+    {
+      char
+        timestamp[MaxTextExtent];
+
+      /*
+        Translate event in "XML" format.
+      */
+      (void) FormatMagickTime(seconds,extent,timestamp);
+      (void) FormatLocaleString(text,extent,
+        "<entry>\n"
+        "  <timestamp>%s</timestamp>\n"
+        "  <elapsed-time>%lu:%02lu.%03lu</elapsed-time>\n"
+        "  <user-time>%0.3f</user-time>\n"
+        "  <process-id>%.20g</process-id>\n"
+        "  <thread-id>%.20g</thread-id>\n"
+        "  <module>%s</module>\n"
+        "  <function>%s</function>\n"
+        "  <line>%.20g</line>\n"
+        "  <domain>%s</domain>\n"
+        "  <event>%s</event>\n"
+        "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
+        (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
+        (1000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
+        (double) getpid(),(double) GetMagickThreadSignature(),module,function,
+        (double) line,domain,event);
+      return(text);
+    }
+  /*
+    Translate event in "human readable" format.
+  */
+  q=text;
+  for (p=log_info->format; *p != '\0'; p++)
+  {
+    *q='\0';
+    if ((size_t) (q-text+MaxTextExtent) >= extent)
+      {
+        extent+=MaxTextExtent;
+        text=(char *) ResizeQuantumMemory(text,extent+MaxTextExtent,
+          sizeof(*text));
+        if (text == (char *) NULL)
+          return((char *) NULL);
+        q=text+strlen(text);
+      }
+    /*
+      The format of the log is defined by embedding special format characters:
+
+        %c   client name
+        %d   domain
+        %e   event
+        %f   function
+        %g   generation
+        %l   line
+        %m   module
+        %n   log name
+        %p   process id
+        %r   real CPU time
+        %t   wall clock time
+        %u   user CPU time
+        %v   version
+        %%   percent sign
+        \n   newline
+        \r   carriage return
+    */
+    if ((*p == '\\') && (*(p+1) == 'r'))
+      {
+        *q++='\r';
+        p++;
+        continue;
+      }
+    if ((*p == '\\') && (*(p+1) == 'n'))
+      {
+        *q++='\n';
+        p++;
+        continue;
+      }
+    if (*p != '%')
+      {
+        *q++=(*p);
+        continue;
+      }
+    p++;
+    switch (*p)
+    {
+      case 'c':
+      {
+        q+=CopyMagickString(q,GetClientName(),extent);
+        break;
+      }
+      case 'd':
+      {
+        q+=CopyMagickString(q,domain,extent);
+        break;
+      }
+      case 'e':
+      {
+        q+=CopyMagickString(q,event,extent);
+        break;
+      }
+      case 'f':
+      {
+        q+=CopyMagickString(q,function,extent);
+        break;
+      }
+      case 'g':
+      {
+        if (log_info->generations == 0)
+          {
+            (void) CopyMagickString(q,"0",extent);
+            q++;
+            break;
+          }
+        q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
+          log_info->generations));
+        break;
+      }
+      case 'l':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) line);
+        break;
+      }
+      case 'm':
+      {
+        register const char
+          *p;
+
+        for (p=module+strlen(module)-1; p > module; p--)
+          if (*p == *DirectorySeparator)
+            {
+              p++;
+              break;
+            }
+        q+=CopyMagickString(q,p,extent);
+        break;
+      }
+      case 'n':
+      {
+        q+=CopyMagickString(q,GetLogName(),extent);
+        break;
+      }
+      case 'p':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
+        break;
+      }
+      case 'r':
+      {
+        q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
+          (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
+          (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
+        break;
+      }
+      case 't':
+      {
+        q+=FormatMagickTime(seconds,extent,q);
+        break;
+      }
+      case 'u':
+      {
+        q+=FormatLocaleString(q,extent,"%0.3fu",user_time);
+        break;
+      }
+      case 'v':
+      {
+        q+=CopyMagickString(q,MagickLibVersionText,extent);
+        break;
+      }
+      case '%':
+      {
+        *q++=(*p);
+        break;
+      }
+      default:
+      {
+        *q++='%';
+        *q++=(*p);
+        break;
+      }
+    }
+  }
+  *q='\0';
+  return(text);
+}
+
+static char *TranslateFilename(const LogInfo *log_info)
+{
+  char
+    *filename;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  size_t
+    extent;
+
+  /*
+    Translate event in "human readable" format.
+  */
+  assert(log_info != (LogInfo *) NULL);
+  assert(log_info->filename != (char *) NULL);
+  filename=AcquireString((char *) NULL);
+  extent=MaxTextExtent;
+  q=filename;
+  for (p=log_info->filename; *p != '\0'; p++)
+  {
+    *q='\0';
+    if ((size_t) (q-filename+MaxTextExtent) >= extent)
+      {
+        extent+=MaxTextExtent;
+        filename=(char *) ResizeQuantumMemory(filename,extent+MaxTextExtent,
+          sizeof(*filename));
+        if (filename == (char *) NULL)
+          return((char *) NULL);
+        q=filename+strlen(filename);
+      }
+    /*
+      The format of the filename is defined by embedding special format
+      characters:
+
+        %c   client name
+        %n   log name
+        %p   process id
+        %v   version
+        %%   percent sign
+    */
+    if (*p != '%')
+      {
+        *q++=(*p);
+        continue;
+      }
+    p++;
+    switch (*p)
+    {
+      case 'c':
+      {
+        q+=CopyMagickString(q,GetClientName(),extent);
+        break;
+      }
+      case 'g':
+      {
+        if (log_info->generations == 0)
+          {
+            (void) CopyMagickString(q,"0",extent);
+            q++;
+            break;
+          }
+        q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
+          log_info->generations));
+        break;
+      }
+      case 'n':
+      {
+        q+=CopyMagickString(q,GetLogName(),extent);
+        break;
+      }
+      case 'p':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
+        break;
+      }
+      case 'v':
+      {
+        q+=CopyMagickString(q,MagickLibVersionText,extent);
+        break;
+      }
+      case '%':
+      {
+        *q++=(*p);
+        break;
+      }
+      default:
+      {
+        *q++='%';
+        *q++=(*p);
+        break;
+      }
+    }
+  }
+  *q='\0';
+  return(filename);
+}
+
+MagickBooleanType LogMagickEventList(const LogEventType type,const char *module,
+  const char *function,const size_t line,const char *format,
+  va_list operands)
+{
+  char
+    event[MaxTextExtent],
+    *text;
+
+  const char
+    *domain;
+
+  ExceptionInfo
+    *exception;
+
+  int
+    n;
+
+  LogInfo
+    *log_info;
+
+  if (IsEventLogging() == MagickFalse)
+    return(MagickFalse);
+  exception=AcquireExceptionInfo();
+  log_info=(LogInfo *) GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  LockSemaphoreInfo(log_semaphore);
+  if ((log_info->event_mask & type) == 0)
+    {
+      UnlockSemaphoreInfo(log_semaphore);
+      return(MagickTrue);
+    }
+  domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
+#if defined(MAGICKCORE_HAVE_VSNPRINTF)
+  n=vsnprintf(event,MaxTextExtent,format,operands);
+#else
+  n=vsprintf(event,format,operands);
+#endif
+  if (n < 0)
+    event[MaxTextExtent-1]='\0';
+  text=TranslateEvent(type,module,function,line,domain,event);
+  if (text == (char *) NULL)
+    {
+      (void) ContinueTimer((TimerInfo *) &log_info->timer);
+      UnlockSemaphoreInfo(log_semaphore);
+      return(MagickFalse);
+    }
+  if ((log_info->handler_mask & ConsoleHandler) != 0)
+    {
+      (void) FormatLocaleFile(stderr,"%s\n",text);
+      (void) fflush(stderr);
+    }
+  if ((log_info->handler_mask & DebugHandler) != 0)
+    {
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+      OutputDebugString(text);
+#endif
+    }
+  if ((log_info->handler_mask & EventHandler) != 0)
+    {
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+      (void) NTReportEvent(text,MagickFalse);
+#endif
+    }
+  if ((log_info->handler_mask & FileHandler) != 0)
+    {
+      struct stat
+        file_info;
+
+      file_info.st_size=0;
+      if (log_info->file != (FILE *) NULL)
+        (void) fstat(fileno(log_info->file),&file_info);
+      if (file_info.st_size > (1024*1024*log_info->limit))
+        {
+          (void) FormatLocaleFile(log_info->file,"</log>\n");
+          (void) fclose(log_info->file);
+          log_info->file=(FILE *) NULL;
+        }
+      if (log_info->file == (FILE *) NULL)
+        {
+          char
+            *filename;
+
+          filename=TranslateFilename(log_info);
+          if (filename == (char *) NULL)
+            {
+              (void) ContinueTimer((TimerInfo *) &log_info->timer);
+              UnlockSemaphoreInfo(log_semaphore);
+              return(MagickFalse);
+            }
+          log_info->append=IsPathAccessible(filename);
+          log_info->file=OpenMagickStream(filename,"ab");
+          filename=(char  *) RelinquishMagickMemory(filename);
+          if (log_info->file == (FILE *) NULL)
+            {
+              UnlockSemaphoreInfo(log_semaphore);
+              return(MagickFalse);
+            }
+          log_info->generation++;
+          if (log_info->append == MagickFalse)
+            {
+              (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
+                "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
+              (void) FormatLocaleFile(log_info->file,"<log>\n");
+            }
+        }
+      (void) FormatLocaleFile(log_info->file,"%s\n",text);
+      (void) fflush(log_info->file);
+    }
+  if ((log_info->handler_mask & StdoutHandler) != 0)
+    {
+      (void) FormatLocaleFile(stdout,"%s\n",text);
+      (void) fflush(stdout);
+    }
+  if ((log_info->handler_mask & StderrHandler) != 0)
+    {
+      (void) FormatLocaleFile(stderr,"%s\n",text);
+      (void) fflush(stderr);
+    }
+  text=(char  *) RelinquishMagickMemory(text);
+  (void) ContinueTimer((TimerInfo *) &log_info->timer);
+  UnlockSemaphoreInfo(log_semaphore);
+  return(MagickTrue);
+}
+
+MagickBooleanType LogMagickEvent(const LogEventType type,const char *module,
+  const char *function,const size_t line,const char *format,...)
+{
+  va_list
+    operands;
+
+  MagickBooleanType
+    status;
+
+  va_start(operands,format);
+  status=LogMagickEventList(type,module,function,line,format,operands);
+  va_end(operands);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d L o g L i s t                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadLogList() loads the log configuration file which provides a
+%  mapping between log attributes and log name.
+%
+%  The format of the LoadLogList method is:
+%
+%      MagickBooleanType LoadLogList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The log list in XML format.
+%
+%    o filename:  The log list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadLogList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  LogInfo
+    *log_info = (LogInfo *) NULL;
+
+  MagickStatusType
+    status;
+
+  /*
+    Load the log map file.
+  */
+  if (xml == (const char *) NULL)
+    return(MagickFalse);
+  if (log_list == (LinkedListInfo *) NULL)
+    {
+      log_list=NewLinkedList(0);
+      if (log_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  token=AcquireString((const char *) xml);
+  for (q=(const char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status|=LoadLogList(xml,path,depth+1,exception);
+                      xml=DestroyString(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<logmap>") == 0)
+      {
+        /*
+          Allocate memory for the log list.
+        */
+        log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
+        if (log_info == (LogInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
+        log_info->path=ConstantString(filename);
+        GetTimerInfo((TimerInfo *) &log_info->timer);
+        log_info->exempt=MagickFalse;
+        log_info->signature=MagickSignature;
+        continue;
+      }
+    if (log_info == (LogInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"</logmap>") == 0)
+      {
+        status=AppendValueToLinkedList(log_list,log_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
+        log_info=(LogInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'E':
+      case 'e':
+      {
+        if (LocaleCompare((char *) keyword,"events") == 0)
+          {
+            log_info->event_mask=(LogEventType) (log_info->event_mask |
+              ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
+            break;
+          }
+        break;
+      }
+      case 'F':
+      case 'f':
+      {
+        if (LocaleCompare((char *) keyword,"filename") == 0)
+          {
+            if (log_info->filename != (char *) NULL)
+              log_info->filename=(char *)
+                RelinquishMagickMemory(log_info->filename);
+            log_info->filename=ConstantString(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"format") == 0)
+          {
+            if (log_info->format != (char *) NULL)
+              log_info->format=(char *)
+                RelinquishMagickMemory(log_info->format);
+            log_info->format=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'G':
+      case 'g':
+      {
+        if (LocaleCompare((char *) keyword,"generations") == 0)
+          {
+            if (LocaleCompare(token,"unlimited") == 0)
+              {
+                log_info->generations=(~0UL);
+                break;
+              }
+            log_info->generations=StringToUnsignedLong(token);
+            break;
+          }
+        break;
+      }
+      case 'L':
+      case 'l':
+      {
+        if (LocaleCompare((char *) keyword,"limit") == 0)
+          {
+            if (LocaleCompare(token,"unlimited") == 0)
+              {
+                log_info->limit=(~0UL);
+                break;
+              }
+            log_info->limit=StringToUnsignedLong(token);
+            break;
+          }
+        break;
+      }
+      case 'O':
+      case 'o':
+      {
+        if (LocaleCompare((char *) keyword,"output") == 0)
+          {
+            log_info->handler_mask=(LogHandlerType)
+              (log_info->handler_mask | ParseLogHandlers(token));
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=DestroyString(token);
+  if (log_list == (LinkedListInfo *) NULL)
+    return(MagickFalse);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d L o g L i s t s                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadLogLists() loads one or more log configuration file which provides a
+%  mapping between log attributes and log name.
+%
+%  The format of the LoadLogLists method is:
+%
+%      MagickBooleanType LoadLogLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the log configuration filename.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadLogLists(const char *filename,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Load built-in log map.
+  */
+  status=MagickFalse;
+  if (log_list == (LinkedListInfo *) NULL)
+    {
+      log_list=NewLinkedList(0);
+      if (log_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
+  {
+    LogInfo
+      *log_info;
+
+    register const LogMapInfo
+      *p;
+
+    p=LogMap+i;
+    log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
+    if (log_info == (LogInfo *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
+        continue;
+      }
+    (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
+    log_info->path=(char *) "[built-in]";
+    GetTimerInfo((TimerInfo *) &log_info->timer);
+    log_info->event_mask=p->event_mask;
+    log_info->handler_mask=p->handler_mask;
+    log_info->filename=ConstantString(p->filename);
+    log_info->format=ConstantString(p->format);
+    log_info->exempt=MagickTrue;
+    log_info->signature=MagickSignature;
+    status=AppendValueToLinkedList(log_list,log_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
+  }
+  /*
+    Load external log map.
+  */
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadLogList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P a r s e L o g H a n d l e r s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseLogHandlers() parses a string defining which handlers takes a log
+%  message and exports them.
+%
+%  The format of the ParseLogHandlers method is:
+%
+%      LogHandlerType ParseLogHandlers(const char *handlers)
+%
+%  A description of each parameter follows:
+%
+%    o handlers: one or more handlers separated by commas.
+%
+*/
+static LogHandlerType ParseLogHandlers(const char *handlers)
+{
+  LogHandlerType
+    handler_mask;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  handler_mask=NoHandler;
+  for (p=handlers; p != (char *) NULL; p=strchr(p,','))
+  {
+    while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
+           (*p == ',')))
+      p++;
+    for (i=0; LogHandlers[i].name != (char *) NULL; i++)
+    {
+      length=strlen(LogHandlers[i].name);
+      if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
+        {
+          handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
+          break;
+        }
+    }
+    if (LogHandlers[i].name == (char *) NULL)
+      return(UndefinedHandler);
+  }
+  return(handler_mask);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t L o g E v e n t M a s k                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetLogEventMask() accepts a list that determines which events to log.  All
+%  other events are ignored.  By default, no debug is enabled.  This method
+%  returns the previous log event mask.
+%
+%  The format of the SetLogEventMask method is:
+%
+%      LogEventType SetLogEventMask(const char *events)
+%
+%  A description of each parameter follows:
+%
+%    o events: log these events.
+%
+*/
+MagickExport LogEventType SetLogEventMask(const char *events)
+{
+  ExceptionInfo
+    *exception;
+
+  LogInfo
+    *log_info;
+
+  ssize_t
+    option;
+
+  exception=AcquireExceptionInfo();
+  log_info=(LogInfo *) GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
+  LockSemaphoreInfo(log_semaphore);
+  log_info=(LogInfo *) GetValueFromLinkedList(log_list,0);
+  log_info->event_mask=(LogEventType) option;
+  if (option == -1)
+    log_info->event_mask=UndefinedEvents;
+  UnlockSemaphoreInfo(log_semaphore);
+  return(log_info->event_mask);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t L o g F o r m a t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetLogFormat() sets the format for the "human readable" log record.
+%
+%  The format of the LogMagickFormat method is:
+%
+%      SetLogFormat(const char *format)
+%
+%  A description of each parameter follows:
+%
+%    o format: the log record format.
+%
+*/
+MagickExport void SetLogFormat(const char *format)
+{
+  LogInfo
+    *log_info;
+
+  ExceptionInfo
+    *exception;
+
+  exception=AcquireExceptionInfo();
+  log_info=(LogInfo *) GetLogInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  LockSemaphoreInfo(log_semaphore);
+  if (log_info->format != (char *) NULL)
+    log_info->format=DestroyString(log_info->format);
+  log_info->format=ConstantString(format);
+  UnlockSemaphoreInfo(log_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t L o g N a m e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetLogName() sets the log name and returns it.
+%
+%  The format of the SetLogName method is:
+%
+%      const char *SetLogName(const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o log_name: SetLogName() returns the current client name.
+%
+%    o name: Specifies the new client name.
+%
+*/
+MagickExport const char *SetLogName(const char *name)
+{
+  if ((name != (char *) NULL) && (*name != '\0'))
+    (void) CopyMagickString(log_name,name,MaxTextExtent);
+  return(log_name);
+}
diff --git a/MagickCore/log.h b/MagickCore/log.h
new file mode 100644
index 0000000..0323476
--- /dev/null
+++ b/MagickCore/log.h
@@ -0,0 +1,94 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore log methods.
+*/
+#ifndef _MAGICKCORE_LOG_H
+#define _MAGICKCORE_LOG_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include "MagickCore/exception.h"
+
+#if !defined(GetMagickModule)
+# define GetMagickModule()  __FILE__,__func__,(unsigned long) __LINE__
+#endif
+
+#define MagickLogFilename  "log.xml"
+
+typedef enum
+{
+  UndefinedEvents,
+  NoEvents = 0x00000,
+  TraceEvent = 0x00001,
+  AnnotateEvent = 0x00002,
+  BlobEvent = 0x00004,
+  CacheEvent = 0x00008,
+  CoderEvent = 0x00010,
+  ConfigureEvent = 0x00020,
+  DeprecateEvent = 0x00040,
+  DrawEvent = 0x00080,
+  ExceptionEvent = 0x00100,
+  ImageEvent = 0x00200,
+  LocaleEvent = 0x00400,
+  ModuleEvent = 0x00800,
+  PolicyEvent = 0x01000,
+  ResourceEvent = 0x02000,
+  TransformEvent = 0x04000,
+  UserEvent = 0x09000,
+  WandEvent = 0x10000,
+  X11Event = 0x20000,
+  AllEvents = 0x7fffffff
+} LogEventType;
+
+typedef struct _LogInfo
+  LogInfo;
+
+extern MagickExport char
+  **GetLogList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetLogName(void),
+  *SetLogName(const char *);
+                                                                                
+extern MagickExport const LogInfo
+  **GetLogInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport LogEventType
+  SetLogEventMask(const char *);
+
+extern MagickExport MagickBooleanType
+  IsEventLogging(void),
+  ListLogInfo(FILE *,ExceptionInfo *),
+  LogComponentGenesis(void),
+  LogMagickEvent(const LogEventType,const char *,const char *,const size_t,
+    const char *,...) 
+    magick_attribute((format (printf,5,6))),
+  LogMagickEventList(const LogEventType,const char *,const char *,const size_t,
+    const char *,va_list) magick_attribute((format (printf,5,0)));
+
+extern MagickExport void
+  CloseMagickLog(void),
+  LogComponentTerminus(void),
+  SetLogFormat(const char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/mac.c b/MagickCore/mac.c
new file mode 100644
index 0000000..f441c36
--- /dev/null
+++ b/MagickCore/mac.c
@@ -0,0 +1,1601 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                            M   M   AAA    CCCC                              %
+%                            MM MM  A   A  C                                  %
+%                            M M M  AAAAA  C                                  %
+%                            M   M  A   A  C                                  %
+%                            M   M  A   A   CCCC                              %
+%                                                                             %
+%                                                                             %
+%                    Macintosh Utility Methods for MagickCore                 %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                September 1996                               %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The directory methods are strongly based on similar methods written
+%  by Steve Summit, scs@eskimo.com.  The Ghostscript launch code is strongly
+%  based on Dave Schooley's Mac Gnuplot and contributed by
+%  schindall@wave14i.nrl.navy.mil.  Mac-centric improvements contributed by
+%  leonardr@digapp.com.
+%
+%
+*/
+
+#if defined(macintosh)
+/*
+  Include declarations.
+*/
+#define _X_H
+#define _WIDGET_H
+#include <AppleEvents.h>
+#include <AERegistry.h>
+#include <AEObjects.h>
+#include <AEPackObject.h>
+#include <Processes.h>
+#include <QuickDraw.h>
+#include <QDOffscreen.h>
+#include <Palettes.h>
+#include <ImageCompression.h>
+#include <PictUtils.h>
+#include <Files.h>
+#include <Gestalt.h>
+#include <TextUtils.h>
+#define ColorInfo  KolorInfo
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/mac.h"
+
+/*
+  Global declaractions.
+*/
+ImageDescriptionHandle
+  image_description = nil;
+
+/*
+  Forward declaractions.
+*/
+static Boolean
+  SearchForFile(OSType,OSType,FSSpec *,short);
+
+static pascal void
+  ArcMethod(GrafVerb,Rect *,short,short),
+  BitsMethod(BitMap *,Rect *,Rect *,short,RgnHandle),
+  FilenameToFSSpec(const char *filename,FSSpec *fsspec),
+  LineMethod(Point),
+  OvalMethod(GrafVerb,Rect *),
+  PolyMethod(GrafVerb,PolyHandle),
+  RRectMethod(GrafVerb,Rect *,short,short),
+  RectMethod(GrafVerb,Rect *),
+  RegionMethod(GrafVerb,RgnHandle),
+  StandardPixmap(PixMapPtr,Rect *,MatrixRecordPtr,short,RgnHandle,PixMapPtr,
+    Rect *,short),
+  TextMethod(short,Ptr,Point,Point);
+
+/*
+  Static declarations
+ */
+#if defined(DISABLE_SIOUX)
+static MACEventHookPtr
+  event_hook = nil;
+
+static MACErrorHookPtr
+  exception.hook = nil;
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   B o t t l e n e c k T e s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BottleneckTest() intercepts any compressed images.
+%
+%  The format of the BottleneckTest method is:
+%
+%      int BottleneckTest(const char *magick)
+%
+%  A description of each parameter follows:
+%
+%    o picture: Specifies a pointer to a PicHandle structure.
+%
+%    o codec: the code type is returned in this CodecType pointer structure.
+%
+%    o depth: the image depth is returned as an integer pointer.
+%
+%    o colormap_id: the colormap ID is returned in this short pointer.
+%
+%
+*/
+
+static pascal void ArcMethod(GrafVerb verb,Rect *r,short startAngle,
+  short arcAngle)
+{
+#pragma unused (verb,r,startAngle,arcAngle)
+}
+
+static pascal void BitsMethod(BitMap *bitPtr,Rect *source_rectangle,
+  Rect *dstRect,short mode,RgnHandle maskRgn)
+{
+#pragma unused (bitPtr,source_rectangle,dstRect,mode,maskRgn)
+}
+
+static pascal void LineMethod(Point newPt)
+{
+#pragma unused (newPt)
+}
+
+static pascal void OvalMethod(GrafVerb verb,Rect *r)
+{
+#pragma unused (verb,r)
+}
+
+static pascal void PolyMethod(GrafVerb verb,PolyHandle poly)
+{
+#pragma unused (verb,poly)
+}
+
+static pascal void RectMethod(GrafVerb verb,Rect *r)
+{
+#pragma unused (verb,r)
+}
+
+static pascal void RegionMethod(GrafVerb verb,RgnHandle rgn)
+{
+#pragma unused (verb,rgn)
+}
+
+static pascal void RRectMethod(GrafVerb verb,Rect *r,short ovalWidth,
+  short ovalHeight)
+{
+#pragma unused (verb,r,ovalWidth,ovalHeight)
+}
+
+static pascal void StandardPixmap(PixMapPtr source,Rect *source_rectangle,
+  MatrixRecordPtr matrix,short mode,RgnHandle mask,PixMapPtr matte,
+  Rect *matte_rectangle,short flags)
+{
+#pragma unused (source_rectangle,matrix,mode,mask,matte,matte_rectangle,flags)
+
+  Ptr
+    data;
+
+  ssize_t
+    size;
+
+  GetCompressedPixMapInfo(source,&image_description,&data,&size,nil,nil);
+}
+
+static pascal void TextMethod(short byteCount,Ptr textBuf,Point numer,
+  Point denom)
+{
+#pragma unused (byteCount,textBuf,numer,denom)
+}
+
+#if !defined(DISABLE_QUICKTIME)
+static short BottleneckTest(PicHandle picture,CodecType *codec,int *depth,
+  short *colormap_id)
+{
+  CQDProcs
+    bottlenecks;
+
+  int
+    status;
+
+  Rect
+    rectangle;
+
+  ssize_t
+    version;
+
+  status=Gestalt(gestaltQuickTime,&version);
+  if (status != noErr)
+    {
+      ParamText("\pQuickTime not installed.  Please install, then try again.",
+        "\p","\p","\p");
+      Alert(128,nil);
+      return(-1);
+    }
+  /*
+    Define our own bottlenecks to do nothing.
+  */
+  SetStdCProcs(&bottlenecks);
+  bottlenecks.textProc=NewQDTextUPP(&TextMethod);
+  bottlenecks.lineProc=NewQDLineUPP(&LineMethod);
+  bottlenecks.rectProc=NewQDRectUPP(&RectMethod);
+  bottlenecks.rRectProc=NewQDRRectUPP(&RRectMethod);
+  bottlenecks.ovalProc=NewQDOvalUPP(&OvalMethod);
+  bottlenecks.arcProc=NewQDArcUPP(&ArcMethod);
+  bottlenecks.polyProc=NewQDPolyUPP(&PolyMethod);
+  bottlenecks.rgnProc=NewQDRgnUPP(&RegionMethod);
+  bottlenecks.bitsProc=NewQDBitsUPP(&BitsMethod);
+  bottlenecks.newProc1=(UniversalProcPtr) NewStdPixUPP(&StandardPixmap);
+  /*
+    Install our custom bottlenecks to intercept any compressed images.
+  */
+  (*(qd.thePort)).grafProcs=(QDProcs *) &bottlenecks;
+  DrawPicture(picture,&((**picture).picFrame));
+  PaintRect(&rectangle);
+  (*(qd.thePort)).grafProcs=0L;
+  /*
+    Initialize our return values.
+  */
+  *codec='unkn';
+  *depth=0;
+  *colormap_id=(-1);
+  if (image_description != nil)
+    {
+      *codec=(**image_description).cType;
+      *depth=(**image_description).depth;
+      *colormap_id=(**image_description).clutID;
+    }
+  DisposeQDTextUPP(bottlenecks.textProc);
+  DisposeQDLineUPP(bottlenecks.lineProc);
+  DisposeQDRectUPP(bottlenecks.rectProc);
+  DisposeQDRRectUPP(bottlenecks.rRectProc);
+  DisposeQDOvalUPP(bottlenecks.ovalProc);
+  DisposeQDArcUPP(bottlenecks.arcProc);
+  DisposeQDPolyUPP(bottlenecks.polyProc);
+  DisposeQDRgnUPP(bottlenecks.rgnProc);
+  DisposeQDBitsUPP(bottlenecks.bitsProc);
+  DisposeStdPixUPP(bottlenecks.newProc1);
+  return(0);
+}
+#endif
+
+#if !defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   c l o s e d i r                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  closedir() closes the named directory stream and frees the DIR structure.
+%
+%  The format of the closedir method is:
+%
+%      closedir(entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+MagickExport void closedir(DIR *entry)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(entry != (DIR *) NULL);
+  RelinquishMagickMemory(entry);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x i t                                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Exit() exits the process.
+%
+%  The format of the exit method is:
+%
+%      Exit(status)
+%
+%  A description of each parameter follows:
+%
+%    o status: an integer value representing the status of the terminating
+%      process.
+%
+%
+*/
+MagickExport int Exit(int status)
+{
+#if !defined(DISABLE_SIOUX)
+  (void) FormatLocaleFile(stdout,"Select File->Quit to exit.\n");
+#endif
+  exit(status);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F i l e n a m e T o F S S p e c                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FilenameToFSSpec() sets the file type of an image.
+%
+%  The format of the FilenameToFSSpec method is:
+%
+%      FilenameToFSSpec(filename,fsspec)
+%
+%  A description of each parameter follows:
+%
+%    o filename: Specifies the name of the file.
+%
+%    o fsspec: A pointer to type FSSpec.
+%
+%
+*/
+MagickExport void pascal FilenameToFSSpec(const char *filename,FSSpec *fsspec)
+{
+  Str255
+    name;
+
+  assert(filename != (char *) NULL);
+  c2pstrcpy(name,filename);
+  FSMakeFSSpec(0,0,name,fsspec);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s M a g i c k C o n f l i c t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MACIsMagickConflict() returns true if the image format conflicts with a
+%  logical drive (.e.g. X:).
+%
+%  Contributed by Mark Gavin of Digital Applications, Inc.
+%
+%  The format of the MACIsMagickConflict method is:
+%
+%      status=MACIsMagickConflict(magick)
+%
+%  A description of each parameter follows:
+%
+%    o magick: Specifies the image format.
+%
+%
+*/
+
+static OSErr HGetVInfo(short volume_index,StringPtr volume_name,short *volume,
+  size_t *free_bytes,size_t *total_bytes)
+{
+  HParamBlockRec
+    pb;
+
+  OSErr
+    result;
+
+  size_t
+    blocksize;
+
+  unsigned short
+    allocation_blocks,
+    free_blocks;
+
+  /*
+    Use the File Manager to get the real vRefNum.
+  */
+  pb.volumeParam.ioVRefNum=0;
+  pb.volumeParam.ioNamePtr=volume_name;
+  pb.volumeParam.ioVolIndex=volume_index;
+  result=PBHGetVInfoSync(&pb);
+  if (result != noErr)
+    return(result);
+  *volume=pb.volumeParam.ioVRefNum;
+  blocksize=(size_t) pb.volumeParam.ioVAlBlkSiz;
+  allocation_blocks=(unsigned short) pb.volumeParam.ioVNmAlBlks;
+  free_blocks=(unsigned short) pb.volumeParam.ioVFrBlk;
+  *free_bytes=free_blocks*blocksize;
+  *total_bytes=allocation_blocks*blocksize;
+  return(result);
+}
+
+MagickExport MagickBooleanType MACIsMagickConflict(const char *magick)
+{
+  size_t
+    free_bytes,
+    number_bytes;
+
+  OSErr
+    status;
+
+  short
+    volume;
+
+  Str255
+    volume_name;
+
+  assert(magick != (char *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",magick);
+  (void) CopyMagickString((char *) volume_name,magick,MaxTextExtent);
+  c2pstr((char *) volume_name);
+  if (volume_name[volume_name[0]] != ':')
+    volume_name[++volume_name[0]]=':';
+  status=HGetVInfo(-1,volume_name,&volume,&free_bytes,&number_bytes);
+  return(status != 0 ? MagickFalse : MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M A C E r r o r H a n d l e r                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MACErrorHandler() displays an error reason and then terminates the program.
+%
+%  The format of the MACErrorHandler method is:
+%
+%      void MACErrorHandler(const ExceptionType error,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o exception: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+%
+*/
+MagickExport void MACErrorHandler(const ExceptionType error,const char *reason,
+  const char *description)
+{
+  char
+    buffer[3*MaxTextExtent];
+
+  if (reason == (char *) NULL)
+    return;
+  if (description == (char *) NULL)
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s (%s).\n",
+      GetClientName(),reason,description);
+#if defined(DISABLE_SIOUX)
+  if(exception.hook != (MACErrorHookPtr) NULL)
+    exception.hook(error,buffer);
+  else
+    {
+      MagickCoreTerminus();
+      exit(error);
+    }
+#else
+  puts(buffer);
+  MagickCoreTerminus();
+  exit(error);
+#endif
+}
+
+#if defined(DISABLE_SIOUX)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M A C F a t a l E r r o r H a n d l e r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MACFatalErrorHandler() displays an error reason and then terminates the
+%  program.
+%
+%  The format of the MACFatalErrorHandler method is:
+%
+%      void MACFatalErrorHandler(const ExceptionType severity,
+%        const char *reason,const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o severity: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+static void MACFatalErrorHandler(const ExceptionType severity,
+  const char *reason,const char *description)
+{
+  char
+    buffer[3*MaxTextExtent];
+
+  if (reason == (char *) NULL)
+    return;
+  if (description == (char *) NULL)
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s (%s).\n",
+      GetClientName(),reason,description);
+  if(exception.hook != (MACErrorHookPtr) NULL)
+    exception.hook(severity, buffer);
+  else
+    {
+      MagickCoreTerminus();
+      exit(severity);
+    }
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a c G S E x e c u t e C o m m a n d                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MacGSExecuteCommand() executes the Ghostscript command.
+%
+%
+*/
+static OSErr MacGSExecuteCommand(const char *command,ssize_t length)
+{
+  AEAddressDesc
+    event_descriptor;
+
+  AEDesc
+    reply = {typeNull, NULL};
+
+  AppleEvent
+    event = {typeNull, NULL};
+
+  DescType
+    descriptor_type;
+
+  int
+    error;
+
+  OSType
+    id = 'gsVR';
+
+  Size
+    actualSize;
+
+  /*
+    Send the Apple Event.
+  */
+  (void) AECreateDesc(typeApplSignature,&id,sizeof(id),&event_descriptor);
+  (void) AECreateAppleEvent(id,'exec',&event_descriptor,-1,kAnyTransactionID,
+    &event);
+  (void) AEPutParamPtr(&event,keyDirectObject,typeChar,command,length);
+  (void) AESend(&event,&reply,kAEWaitReply+kAENeverInteract,kAENormalPriority,
+    kNoTimeOut,NULL,NULL);
+  /*
+    Handle the reply and exit.
+  */
+  (void) AEGetParamPtr(&reply,keyDirectObject,typeInteger,&descriptor_type,
+    &error,sizeof(error),&actualSize);
+  (void) AEDisposeDesc(&event_descriptor);
+  (void) AEDisposeDesc(&event);
+  if (reply.descriptorType != NULL)
+    AEDisposeDesc(&reply);
+  return((OSErr) error);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a c G S L a u n c h A p p l i c a t i o n C o r e                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MacGSLaunchApplicationCore() launches the Ghostscript command.
+%
+%
+*/
+static OSErr MacGSLaunchApplicationCore(ssize_t flags)
+{
+  FSSpec
+    file_info;
+
+  LaunchParamBlockRec
+    launch_info;
+
+  OSErr
+    error;
+
+  if (!SearchForFile('gsVR','APPL',&file_info,1))
+    return(-43);
+  launch_info.launchBlockID=extendedBlock;
+  launch_info.launchEPBLength=extendedBlockLen;
+  launch_info.launchFileFlags=0;
+  launch_info.launchControlFlags=launchContinue+launchNoFileFlags+flags;
+  launch_info.launchAppSpec=(&file_info);
+  launch_info.launchAppParameters=nil;
+  error=LaunchApplication(&launch_info);
+  return(error);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a c G S L a u n c h A p p l i c a t i o n                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MacGSLaunchApplication() launches the Ghostscript command.
+%
+%
+*/
+static OSErr MacGSLaunchApplication(void)
+{
+  return(MacGSLaunchApplicationCore(launchDontSwitch));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a c G S L a u n c h A p p l i c a t i o n T o F r o n t                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MacGSLaunchApplicationToFront() moves the Ghostscript window to the front.
+%
+%
+*/
+static OSErr MacGSLaunchApplicationToFront(void)
+{
+  return(MacGSLaunchApplicationCore(0));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a c G S Q u i t A p p l i c a t i o n                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MacGSQuitApplication() quits the Ghostscript application.
+%
+%
+*/
+static void MacGSQuitApplication(void)
+{
+  AEAddressDesc
+    event_descriptor;
+
+  AEDesc
+    reply = {typeNull, NULL};
+
+  AppleEvent
+    event = {typeNull, NULL};
+
+  OSType
+    id = 'GPLT';
+
+  /*
+    Send the Apple Event.
+  */
+  (void) AECreateDesc(typeApplSignature,&id,sizeof(id),&event_descriptor);
+  (void) AECreateAppleEvent(typeAppleEvent,kAEQuitApplication,
+    &event_descriptor,-1,kAnyTransactionID,&event);
+  (void) AESend(&event,&reply,kAENoReply,kAENormalPriority,kNoTimeOut,NULL,
+    NULL);
+  /*
+    Clean up and exit.
+  */
+  (void) AEDisposeDesc(&event_descriptor);
+  (void) AEDisposeDesc(&event);
+  if (reply.descriptorType != NULL)
+    AEDisposeDesc(&reply);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a c G S S e t W o r k i n g F o l d e r                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MacGSSetWorkingFolder() set the Ghostscript working folder.
+%
+%
+*/
+static OSErr MacGSSetWorkingFolder(char *directory)
+{
+  AEDesc
+    application_descriptor,
+    event_descriptor,
+    object,
+    path_descriptor,
+    type_descriptor,
+    reply;
+
+  AppleEvent
+    event;
+
+  DescType
+    folder_type = 'wfdr';
+
+  OSErr
+    error;
+
+  OSType
+    id = 'GPLT';
+
+  /*
+    Send the Apple Event.
+  */
+  AECreateDesc(typeNull,NULL,0,&application_descriptor);
+  AECreateDesc(typeChar,directory,strlen(directory),&path_descriptor);
+  (void) AECreateDesc(typeType,&folder_type,sizeof(DescType),&type_descriptor);
+  CreateObjSpecifier(cProperty,&application_descriptor,formPropertyID,
+    &type_descriptor,0,&object);
+  (void) AECreateDesc(typeApplSignature,&id,sizeof(id),&event_descriptor);
+  (void) AECreateAppleEvent(kAECoreSuite,kAESetData,&event_descriptor,-1,
+    kAnyTransactionID,&event);
+  (void) AEPutParamDesc(&event,keyDirectObject,&object);
+  (void) AEPutParamDesc(&event,keyAEData,&path_descriptor);
+  error=AESend(&event,&reply,kAENoReply+kAENeverInteract,kAENormalPriority,
+    kNoTimeOut,NULL,NULL);
+  (void) AEDisposeDesc(&event);
+  (void) AEDisposeDesc(&event_descriptor);
+  (void) AEDisposeDesc(&object);
+  (void) AEDisposeDesc(&type_descriptor);
+  (void) AEDisposeDesc(&path_descriptor);
+  (void) AEDisposeDesc(&application_descriptor);
+  return(error);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M A C S e t E r r o r H o o k                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%   MACSetErrorHook sets a callback function which is called if any error
+%   occurs within ImageMagick.
+%
+%  The format of the MACSetErrorHook method is:
+%
+%      int MACSetErrorHook(MACErrorHookPtr hook)
+%
+%  A description of each parameter follows:
+%
+%    o hook: This function pointer is the callback function.
+%
+%
+*/
+MagickExport void MACSetErrorHook(MACErrorHookPtr hook)
+{
+  /*
+    We forget any previously set exception.hook.
+  */
+  exception.hook=hook;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M A C S e t E v e n t H o o k                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%   MACSetEventHook sets a callback function which is called every time
+%   ImageMagick likes to release the processor.
+%
+%  The format of the MACSetEventHook method is:
+%
+%      int MACSetEventHook(MACEventHookPtr hook)
+%
+%  A description of each parameter follows:
+%
+%    o hook: This function pointer is the callback function.
+%
+%
+*/
+MagickExport void MACSetEventHook(MACEventHookPtr hook)
+{
+  /*
+    We forget any previously set event hook.
+   */
+  event_hook=hook;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M A C S y s t e m C o m m a n d                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%   Method MACSystemCommand executes the specified command and waits until it
+%   terminates.  The returned value is the exit status of the command.
+%
+%  The format of the MACSystemCommand method is:
+%
+%      int MACSystemCommand(MagickFalse,const char * command)
+%
+%  A description of each parameter follows:
+%
+%    o command: This string is the command to execute.
+%
+*/
+MagickExport int MACSystemCommand(const char * command)
+{
+  /*
+    We only know how to launch Ghostscript.
+  */
+  if (MacGSLaunchApplicationToFront())
+    return(-1);
+  return(MacGSExecuteCommand(command,strlen(command)));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M A C W a r n i n g H a n d l e r                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MACWarningHandler() displays a warning reason.
+%
+%  The format of the MACWarningHandler method is:
+%
++      void MACWarningHandler(const ExceptionType warning,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o warning: Specifies the numeric warning category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+%
+*/
+MagickExport void MACWarningHandler(const ExceptionType warning,
+  const char *reason,const char *description)
+{
+  char
+    buffer[1664];
+
+  if (reason == (char *) NULL)
+    return;
+  if (description == (char *) NULL)
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s (%s).\n",
+      GetClientName(),reason,description);
+#if defined(DISABLE_SIOUX)
+  if(exception.hook != (MACErrorHookPtr) NULL)
+    exception.hook(warning, buffer);
+#else
+  (void)warning;
+  puts(buffer);
+#endif
+}
+
+#if !defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   o p e n d i r                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  opendir() opens the directory named by filename and associates a directory
+%  stream with it.
+%
+%  The format of the opendir method is:
+%
+%      MagickExport DIR *opendir(char *path)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+MagickExport DIR *opendir(const char *path)
+{
+  Str255 pathname;
+
+  CInfoPBRec
+    search_info;
+
+  DIR
+    *entry;
+
+  int
+    error;
+
+  search_info.hFileInfo.ioNamePtr=0;
+  if ((path != (char *) NULL) || (*path != '\0'))
+    if ((path[0] != '.') || (path[1] != '\0'))
+      {
+        c2pstrcpy(pathname,path);
+        search_info.hFileInfo.ioNamePtr=pathname;
+      }
+  search_info.hFileInfo.ioCompletion=0;
+  search_info.hFileInfo.ioVRefNum=0;
+  search_info.hFileInfo.ioFDirIndex=0;
+  search_info.hFileInfo.ioDirID=0;
+  error=PBGetCatInfoSync(&search_info);
+  if (error != noErr)
+    {
+      errno=error;
+      return((DIR *) NULL);
+    }
+  entry=(DIR *) AcquireMagickMemory(sizeof(DIR));
+  if (entry == (DIR *) NULL)
+    return((DIR *) NULL);
+  entry->d_VRefNum=search_info.hFileInfo.ioVRefNum;
+  entry->d_DirID=search_info.hFileInfo.ioDirID;
+  entry->d_index=1;
+  return(entry);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P r o c e s s P e n d i n g E v e n t s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ProcessPendingEvents() processes any pending events.  This prevents
+%  ImageMagick from monopolizing the processor.
+%
+%  The format of the ProcessPendingEvents method is:
+%
+%      ProcessPendingEvents(text)
+%
+%  A description of each parameter follows:
+%
+%    o text: A character string representing the current process.
+%
+%
+*/
+MagickExport void ProcessPendingEvents(const char *text)
+{
+#if defined(DISABLE_SIOUX)
+  if (event_hook != (MACEventHookPtr) NULL)
+    event_hook(text);
+#else
+  static const char
+    *mark = (char *) NULL;
+
+  EventRecord
+    event;
+
+  while (WaitNextEvent(everyEvent,&event,0L,nil))
+    SIOUXHandleOneEvent(&event);
+  if (isatty(STDIN_FILENO) && (text != mark))
+    {
+      (void) puts(text);
+      mark=text;
+    }
+#endif
+}
+
+#if !defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   r e a d d i r                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  readdir() returns a pointer to a structure representing the directory entry
+%  at the current position in the directory stream to which entry refers.
+%
+%  The format of the readdir
+%
+%      struct dirent *readdir(DIR *entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+MagickExport struct dirent *readdir(DIR *entry)
+{
+  CInfoPBRec
+    search_info;
+
+  int
+    error;
+
+  static struct dirent
+    dir_entry;
+
+  static unsigned char
+    pathname[MaxTextExtent];
+
+  if (entry == (DIR *) NULL)
+    return((struct dirent *) NULL);
+  search_info.hFileInfo.ioCompletion=0;
+  search_info.hFileInfo.ioNamePtr=pathname;
+  search_info.hFileInfo.ioVRefNum=0;
+  search_info.hFileInfo.ioFDirIndex=entry->d_index;
+  search_info.hFileInfo.ioDirID=entry->d_DirID;
+  error=PBGetCatInfoSync(&search_info);
+  if (error != noErr)
+    {
+      errno=error;
+      return((struct dirent *) NULL);
+    }
+  entry->d_index++;
+  p2cstrcpy(dir_entry.d_name,search_info.hFileInfo.ioNamePtr);
+  dir_entry.d_namlen=strlen(dir_entry.d_name);
+  return(&dir_entry);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  R e a d P I C T I m a g e                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadPICTImage() reads an Apple Macintosh QuickDraw/PICT image file using
+%  MacOS QuickDraw methods and returns it.  It allocates the memory necessary
+%  for the new Image structure and returns a pointer to the new image.
+%
+%  This method was written and contributed by spd@daphne.cps.unizar.es
+%  (feel free to copy and use it as you want. No warranty).
+%
+%  The format of the ReadPICTImage method is:
+%
+%      Image *ReadPICTImage(const ImageInfo *image_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image:  Method ReadPICTImage returns a pointer to the image after
+%      reading.  A null image is returned if there is a memory shortage or
+%      if the image cannot be read.
+%
+%    o image_info: the image info..
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+MagickExport Image *ReadPICTImage(const ImageInfo *image_info,
+  ExceptionInfo *exception)
+{
+#define PICTHeaderSize    512
+
+  CodecType
+    codec;
+
+  GDHandle
+    device;
+
+  GWorldPtr
+    graphic_world,
+    port;
+
+  Image
+    *image;
+
+  int
+    depth,
+    status;
+
+  MagickBooleanType
+    proceed,
+    status;
+
+  PicHandle
+    picture_handle;
+
+  PictInfo
+    picture_info;
+
+  QDErr
+    theErr = noErr;
+
+  Rect
+    rectangle;
+
+  RGBColor
+    Pixel;
+
+  short
+    colormap_id;
+
+  ssize_t
+    y;
+
+  /*
+    Open image file.
+  */
+  image=AcquireImage(image_info);
+  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
+  if (status == MagickFalse)
+    return(NULL);
+  picture_handle=(PicHandle) NewHandle(MagickMax(GetBlobSize(image)-
+    PICTHeaderSize,PICTHeaderSize));
+  if (picture_handle == nil)
+    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+  HLock((Handle) picture_handle);
+  (void) ReadBlob(image,PICTHeaderSize,*(unsigned char **) picture_handle);
+  status=ReadBlob(image,GetBlobSize(image)-PICTHeaderSize,*(unsigned char **)
+    picture_handle);
+  if (status == MagickFalse)
+    {
+      DisposeHandle((Handle) picture_handle);
+      ThrowReaderException(CorruptImageError,"UnableToReadImageData");
+    }
+  GetGWorld(&port,&device);
+  theErr=NewGWorld(&graphic_world,0,&(**picture_handle).picFrame,nil,nil,
+    useTempMem | keepLocal);
+  if ((theErr != noErr) && (graphic_world == nil))
+    {
+      DisposeHandle((Handle) picture_handle);
+      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  HUnlock((Handle) picture_handle);
+  SetGWorld(graphic_world,nil);
+  theErr=GetPictInfo(picture_handle,&picture_info,0,1,systemMethod,0);
+  if (theErr != noErr)
+    {
+      DisposeGWorld(graphic_world);
+      DisposeHandle((Handle) picture_handle);
+      ThrowReaderException(CorruptImageError,"UnableToReadImageData");
+    }
+#if defined(DISABLE_QUICKTIME)
+  codec='unkn';
+  colormap_id=(-1);
+  depth=picture_info.depth;
+#else
+  BottleneckTest(picture_handle,&codec,&depth,&colormap_id);
+#endif
+  switch (codec)
+  {
+    case 'rpza':
+    case 'jpeg':
+    case 'rle ':
+    case 'raw ':
+    case 'smc ':
+    {
+      if (depth > 200)
+        {
+          depth-=32;
+          picture_info.theColorTable=GetCTable(colormap_id);
+        }
+      break;
+    }
+    default:
+    {
+      depth=picture_info.depth;
+      if (depth <= 8)
+        (void) GetPictInfo(picture_handle,&picture_info,returnColorTable,
+          (short) (1 << picture_info.depth),systemMethod,0);
+      break;
+    }
+  }
+  image->x_resolution=(picture_info.hRes) >> 16;
+  image->y_resolution=(picture_info.vRes) >> 16;
+  image->units=PixelsPerInchResolution;
+  image->columns=picture_info.sourceRect.right-picture_info.sourceRect.left;
+  image->rows=picture_info.sourceRect.bottom-picture_info.sourceRect.top;
+  if ((depth <= 8) && ((*(picture_info.theColorTable))->ctSize != 0))
+    {
+      size_t
+        number_colors;
+
+      /*
+        Colormapped PICT image.
+      */
+      number_colors=(*(picture_info.theColorTable))->ctSize;
+      if (!AcquireImageColormap(image,number_colors))
+        {
+          if (picture_info.theColorTable != nil)
+            DisposeHandle((Handle) picture_info.theColorTable);
+          DisposeGWorld(graphic_world);
+          DisposeHandle((Handle) picture_handle);
+          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+        }
+      for (x=0; x < image->colors; x++)
+      {
+        image->colormap[x].red=
+          (*(picture_info.theColorTable))->ctTable[x].rgb.red;
+        image->colormap[x].green=
+          (*(picture_info.theColorTable))->ctTable[x].rgb.green;
+        image->colormap[x].blue=
+          (*(picture_info.theColorTable))->ctTable[x].rgb.blue;
+      }
+    }
+  SetRect(&rectangle,0,0,image->columns,image->rows);
+  (void) UpdateGWorld(&graphic_world,depth,&rectangle,
+    picture_info.theColorTable,nil,0);
+  LockPixels(GetGWorldPixMap(graphic_world));  /*->portPixMap); */
+  EraseRect(&rectangle);
+  DrawPicture(picture_handle,&rectangle);
+  if ((depth <= 8) && (colormap_id == -1))
+    {
+      DisposeHandle((Handle) picture_info.theColorTable);
+      picture_info.theColorTable=nil;
+    }
+  DisposeHandle((Handle) picture_handle);
+  /*
+    Convert PICT pixels to pixel packets.
+  */
+  for (y=0; y < image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0; x < image->columns; x++)
+    {
+      GetCPixel(x,y,&Pixel);
+      SetPixelRed(image,ScaleCharToQuantum(Pixel.red & 0xff),q);
+      SetPixelGreen(image,ScaleCharToQuantum(Pixel.green & 0xff),q);
+      SetPixelBlue(image,ScaleCharToQuantum(Pixel.blue & 0xff),q);
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(image,Color2Index(&Pixel),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncAuthenticPixels(image,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,LoadImageTag,y,image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  UnlockPixels(GetGWorldPixMap(graphic_world));
+  SetGWorld(port,device);
+  if (picture_info.theColorTable != nil)
+    DisposeHandle((Handle) picture_info.theColorTable);
+  DisposeGWorld(graphic_world);
+  (void) CloseBlob(image);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e a r c h F o r F i l e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SearchForFile() searches for a file.
+%
+%
+*/
+static Boolean SearchForFile(OSType creator_type,OSType file_type,FSSpec *file,
+  short count)
+{
+  char
+    *buffer;
+
+  CInfoPBRec
+    search1_info,
+    search2_info;
+
+  FSSpec
+    application;
+
+  HParamBlockRec
+    parameter_info;
+
+  OSErr
+    error;
+
+  ProcessInfoRec
+    application_info;
+
+  ProcessSerialNumber
+    serial_number;
+
+  ssize_t
+    buffer_size = 16384;
+
+  serial_number.lowLongOfPSN=kCurrentProcess;
+  serial_number.highLongOfPSN=0;
+  application_info.processInfoLength=sizeof(ProcessInfoRec);
+  application_info.processName=NULL;
+  application_info.processAppSpec=(&application);
+  GetProcessInformation(&serial_number,&application_info);
+  buffer=NewPtr(buffer_size);
+  if (buffer == (char *) NULL)
+    return(false);
+  parameter_info.csParam.ioCompletion=NULL;
+  parameter_info.csParam.ioNamePtr=NULL;
+  parameter_info.csParam.ioVRefNum=application.vRefNum;
+  parameter_info.csParam.ioMatchPtr=file;
+  parameter_info.csParam.ioReqMatchCount=count;
+  parameter_info.csParam.ioSearchBits=fsSBFlFndrInfo;
+  parameter_info.csParam.ioSearchInfo1=&search1_info;
+  parameter_info.csParam.ioSearchInfo2=&search2_info;
+  parameter_info.csParam.ioSearchTime=0;
+  parameter_info.csParam.ioCatPosition.initialize=0;
+  parameter_info.csParam.ioOptBuffer=buffer;
+  parameter_info.csParam.ioOptBufSize=buffer_size;
+  search1_info.hFileInfo.ioNamePtr=NULL;
+  search1_info.hFileInfo.ioFlFndrInfo.fdType=file_type;
+  search1_info.hFileInfo.ioFlFndrInfo.fdCreator=creator_type;
+  search1_info.hFileInfo.ioFlAttrib=0;
+  search1_info.hFileInfo.ioFlParID=0;
+  search2_info=search1_info;
+  search2_info.hFileInfo.ioFlAttrib=0x10;
+  search2_info.hFileInfo.ioFlFndrInfo.fdCreator=creator_type;
+  search2_info.hFileInfo.ioFlFndrInfo.fdType=(-1);
+  search2_info.hFileInfo.ioFlFndrInfo.fdFlags=0;
+  search2_info.hFileInfo.ioFlFndrInfo.fdLocation.h=0;
+  search2_info.hFileInfo.ioFlFndrInfo.fdLocation.v=0;
+  search2_info.hFileInfo.ioFlFndrInfo.fdFldr=0;
+  search2_info.hFileInfo.ioFlParID=0;
+  error=PBCatSearchSync((CSParamPtr) &parameter_info);
+  DisposePtr(buffer);
+  if (parameter_info.csParam.ioReqMatchCount ==
+      parameter_info.csParam.ioActMatchCount)
+    error=eofErr;
+  if (parameter_info.csParam.ioActMatchCount == 0)
+    error=0;
+  return(error == eofErr);
+}
+
+#if !defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   s e e k d i r                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  seekdir() sets the position of the next readdir() operation on the directory
+%  stream.
+%
+%  The format of the seekdir method is:
+%
+%      void seekdir(DIR *entry,ssize_t position)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%    o position: specifies the position associated with the directory
+%      stream.
+%
+%
+%
+*/
+MagickExport void seekdir(DIR *entry,ssize_t position)
+{
+  assert(entry != (DIR *) NULL);
+  entry->d_index=position;
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t A p p l i c a t i o n T y p e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetApplicationType() sets the file type of an image.
+%
+%  The format of the SetApplicationType method is:
+%
+%      void SetApplicationType(const char *filename,const char *magick,
+%        OSType application)
+%
+%  A description of each parameter follows:
+%
+%    o filename: Specifies the name of the file.
+%
+%    o filename: Specifies the file type.
+%
+%    o application: Specifies the type of the application.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport void SetApplicationType(const char *filename,const char *magick,
+  OSType application)
+{
+  FSSpec
+    file_specification;
+
+  OSType
+    filetype;
+
+  Str255
+    name;
+
+  assert(filename != (char *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(magick != (const char *) NULL);
+  filetype='    ';
+  (void) CopyMagickString((char *) &filetype,magick,MagickMin(strlen(magick),
+    4));
+  if (LocaleCompare(magick,"JPG") == 0)
+    (void) CopyMagickString((char *) &filetype,"JPEG",MaxTextExtent);
+  c2pstrcpy(name,filename);
+  FSMakeFSSpec(0,0,name,&file_specification);
+  FSpCreate(&file_specification,application,filetype,smSystemScript);
+}
+
+#if !defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   t e l l d i r                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%   Method telldir returns the current location associated  with  the
+%   named directory stream.
+%
+%  The format of the telldir method is:
+%
+%      telldir(DIR *entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+MagickExport ssize_t telldir(DIR *entry)
+{
+  return(entry->d_index);
+}
+#endif
+
+#endif
diff --git a/MagickCore/mac.h b/MagickCore/mac.h
new file mode 100644
index 0000000..9491dc2
--- /dev/null
+++ b/MagickCore/mac.h
@@ -0,0 +1,111 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore utility methods.
+*/
+#ifndef _MAGICKCORE_MAC_H
+#define _MAGICKCORE_MAC_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <locale.h>
+#include <Errors.h>
+#include <Files.h>
+#include <errno.h>
+
+#if defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+# include <dirent.h>
+# if !defined(DISABLE_SIOUX)
+#  include <SIOUX.h>
+# endif
+#else
+# include <stat.h>
+
+#define S_IREAD  00400
+#define S_IWRITE  00200
+
+typedef struct _DIR
+{
+  int
+    d_VRefNum;
+
+  long
+    d_DirID;
+
+  int
+    d_index;
+} DIR;
+
+struct dirent
+{
+  char
+    d_name[255];
+
+  int
+    d_namlen;
+};
+#endif
+
+MagickExport Image
+  *ReadPICTImage(const ImageInfo *,ExceptionInfo *);
+
+extern MagickExport int
+  Exit(int),
+  MACSystemCommand(const char *);
+
+extern MagickExport MagickBooleanType
+  MACIsMagickConflict(const char *);
+
+extern MagickExport void
+  MACErrorHandler(const ExceptionType,const char *,const char *),
+  MACWarningHandler(const ExceptionType,const char *,const char *),
+  ProcessPendingEvents(const char *),
+  SetApplicationType(const char *,const char *,OSType);
+
+#if defined(DISABLE_SIOUX)
+typedef void
+  (*MACEventHookPtr)(const char *);
+
+typedef void
+  (*MACErrorHookPtr)(const short,const char *text);
+
+extern MagickExport void
+  MACSetErrorHook(MACErrorHookPtr),
+  MACSetEventHook(MACEventHookPtr),
+  MACFatalErrorHandler(const ExceptionType,const char *,const char *);
+#endif
+
+#if !defined(_MAGICKCORE_POSIX_SUPPORT_VERSION)
+extern MagickExport DIR
+  *opendir(const char *);
+
+extern MagickExport long
+  telldir(DIR *);
+
+extern MagickExport struct dirent
+  *readdir(DIR *);
+
+extern MagickExport void
+  seekdir(DIR *,long
+  closedir(DIR *);
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/magic.c b/MagickCore/magic.c
new file mode 100644
index 0000000..71d7414
--- /dev/null
+++ b/MagickCore/magic.c
@@ -0,0 +1,1074 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                    M   M   AAA    GGGG  IIIII   CCCC                        %
+%                    MM MM  A   A  G        I    C                            %
+%                    M M M  AAAAA  G GGG    I    C                            %
+%                    M   M  A   A  G   G    I    C                            %
+%                    M   M  A   A   GGGG  IIIII   CCCC                        %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Magic Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                              Bob Friesenhahn                                %
+%                                 July 2000                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define MagicFilename  "magic.xml"
+#define MagickString(magic)  (const unsigned char *) (magic), sizeof(magic)-1
+
+/*
+  Typedef declarations.
+*/
+typedef struct _MagicMapInfo
+{
+  const char
+    *name;
+
+  const MagickOffsetType
+    offset;
+
+  const unsigned char
+    *magic;
+
+  const size_t
+    length;
+} MagicMapInfo;
+
+/*
+  Static declarations.
+*/
+static const MagicMapInfo
+  MagicMap[] =
+  {
+    { "8BIMWTEXT", 0, MagickString("8\000B\000I\000M\000#") },
+    { "8BIMTEXT", 0, MagickString("8BIM#") },
+    { "8BIM", 0, MagickString("8BIM") },
+    { "BMP", 0, MagickString("BA") },
+    { "BMP", 0, MagickString("BM") },
+    { "BMP", 0, MagickString("CI") },
+    { "BMP", 0, MagickString("CP") },
+    { "BMP", 0, MagickString("IC") },
+    { "BMP", 0, MagickString("PI") },
+    { "CALS", 21, MagickString("version: MIL-STD-1840") },
+    { "CALS", 0, MagickString("srcdocid:") },
+    { "CALS", 9, MagickString("srcdocid:") },
+    { "CALS", 8, MagickString("rorient:") },
+    { "CGM", 0, MagickString("BEGMF") },
+    { "CIN", 0, MagickString("\200\052\137\327") },
+    { "CRW", 0, MagickString("II\x1a\x00\x00\x00HEAPCCDR") },
+    { "DCM", 128, MagickString("DICM") },
+    { "DCX", 0, MagickString("\261\150\336\72") },
+    { "DIB", 0, MagickString("\050\000") },
+    { "DDS", 0, MagickString("DDS ") },
+    { "DJVU", 0, MagickString("AT&TFORM") },
+    { "DOT", 0, MagickString("digraph") },
+    { "DPX", 0, MagickString("SDPX") },
+    { "DPX", 0, MagickString("XPDS") },
+    { "EMF", 40, MagickString("\040\105\115\106\000\000\001\000") },
+    { "EPT", 0, MagickString("\305\320\323\306") },
+    { "EXR", 0, MagickString("\166\057\061\001") },
+    { "FAX", 0, MagickString("DFAX") },
+    { "FIG", 0, MagickString("#FIG") },
+    { "FITS", 0, MagickString("IT0") },
+    { "FITS", 0, MagickString("SIMPLE") },
+    { "FPX", 0, MagickString("\320\317\021\340") },
+    { "GIF", 0, MagickString("GIF8") },
+    { "GPLT", 0, MagickString("#!/usr/local/bin/gnuplot") },
+    { "HDF", 1, MagickString("HDF") },
+    { "HDR", 0, MagickString("#?RADIANCE") },
+    { "HDR", 0, MagickString("#?RGBE") },
+    { "HPGL", 0, MagickString("IN;") },
+    { "HTML", 1, MagickString("HTML") },
+    { "HTML", 1, MagickString("html") },
+    { "ILBM", 8, MagickString("ILBM") },
+    { "IPTCWTEXT", 0, MagickString("\062\000#\000\060\000=\000\042\000&\000#\000\060\000;\000&\000#\000\062\000;\000\042\000") },
+    { "IPTCTEXT", 0, MagickString("2#0=\042&#0;&#2;\042") },
+    { "IPTC", 0, MagickString("\034\002") },
+    { "JNG", 0, MagickString("\213JNG\r\n\032\n") },
+    { "JPEG", 0, MagickString("\377\330\377") },
+    { "JPC", 0, MagickString("\377\117") },
+    { "JP2", 4, MagickString("\152\120\040\040\015") },
+    { "MAT", 0, MagickString("MATLAB 5.0 MAT-file,") },
+    { "MIFF", 0, MagickString("Id=ImageMagick") },
+    { "MIFF", 0, MagickString("id=ImageMagick") },
+    { "MNG", 0, MagickString("\212MNG\r\n\032\n") },
+    { "MPC", 0, MagickString("id=MagickCache") },
+    { "MPEG", 0, MagickString("\000\000\001\263") },
+    { "MRW", 0, MagickString("\x00MRM") },
+    { "MVG", 0, MagickString("push graphic-context") },
+    { "ORF", 0, MagickString("IIRO\x08\x00\x00\x00") },
+    { "PCD", 2048, MagickString("PCD_") },
+    { "PCL", 0, MagickString("\033E\033") },
+    { "PCX", 0, MagickString("\012\002") },
+    { "PCX", 0, MagickString("\012\005") },
+    { "PDB", 60, MagickString("vIMGView") },
+    { "PDF", 0, MagickString("%PDF-") },
+    { "PES", 0, MagickString("#PES") },
+    { "PFA", 0, MagickString("%!PS-AdobeFont-1.0") },
+    { "PFB", 6, MagickString("%!PS-AdobeFont-1.0") },
+    { "PGX", 0, MagickString("\050\107\020\115\046") },
+    { "PICT", 522, MagickString("\000\021\002\377\014\000") },
+    { "PNG", 0, MagickString("\211PNG\r\n\032\n") },
+    { "PBM", 0, MagickString("P1") },
+    { "PGM", 0, MagickString("P2") },
+    { "PPM", 0, MagickString("P3") },
+    { "PBM", 0, MagickString("P4") },
+    { "PGM", 0, MagickString("P5") },
+    { "PPM", 0, MagickString("P6") },
+    { "PAM", 0, MagickString("P7") },
+    { "PFM", 0, MagickString("PF") },
+    { "PFM", 0, MagickString("Pf") },
+    { "PS", 0, MagickString("%!") },
+    { "PS", 0, MagickString("\004%!") },
+    { "PS", 0, MagickString("\305\320\323\306") },
+    { "PSB", 0, MagickString("8BPB") },
+    { "PSD", 0, MagickString("8BPS") },
+    { "PWP", 0, MagickString("SFW95") },
+    { "RAF", 0, MagickString("FUJIFILMCCD-RAW ") },
+    { "RLE", 0, MagickString("\122\314") },
+    { "SCT", 0, MagickString("CT") },
+    { "SFW", 0, MagickString("SFW94") },
+    { "SGI", 0, MagickString("\001\332") },
+    { "SUN", 0, MagickString("\131\246\152\225") },
+    { "SVG", 1, MagickString("?XML") },
+    { "SVG", 1, MagickString("?xml") },
+    { "TIFF", 0, MagickString("\115\115\000\052") },
+    { "TIFF", 0, MagickString("\111\111\052\000") },
+    { "TIFF64", 0, MagickString("\115\115\000\053\000\010\000\000") },
+    { "TIFF64", 0, MagickString("\111\111\053\000\010\000\000\000") },
+    { "TXT", 0, MagickString("# ImageMagick pixel enumeration:") },
+    { "VICAR", 0, MagickString("LBLSIZE") },
+    { "VICAR", 0, MagickString("NJPL1I") },
+    { "VIFF", 0, MagickString("\253\001") },
+    { "WEBP", 8, MagickString("WEBP") },
+    { "WMF", 0, MagickString("\327\315\306\232") },
+    { "WMF", 0, MagickString("\001\000\011\000") },
+    { "WPG", 0, MagickString("\377WPC") },
+    { "XBM", 0, MagickString("#define") },
+    { "XCF", 0, MagickString("gimp xcf") },
+    { "XEF", 0, MagickString("FOVb") },
+    { "XPM", 1, MagickString("* XPM *") },
+    { "XWD", 4, MagickString("\007\000\000") },
+    { "XWD", 5, MagickString("\000\000\007") }
+ };
+
+static LinkedListInfo
+  *magic_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *magic_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_magic = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeMagicList(ExceptionInfo *),
+  LoadMagicLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c I n f o                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagicInfo() searches the magic list for the specified name and if found
+%  returns attributes for that magic.
+%
+%  The format of the GetMagicInfo method is:
+%
+%      const MagicInfo *GetMagicInfo(const unsigned char *magic,
+%        const size_t length,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o magic: A binary string generally representing the first few characters
+%      of the image file or blob.
+%
+%    o length: the length of the binary signature.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
+  const size_t length,ExceptionInfo *exception)
+{
+  register const MagicInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((magic_list == (LinkedListInfo *) NULL) ||
+      (instantiate_magic == MagickFalse))
+    if (InitializeMagicList(exception) == MagickFalse)
+      return((const MagicInfo *) NULL);
+  if ((magic_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(magic_list) != MagickFalse))
+    return((const MagicInfo *) NULL);
+  if (magic == (const unsigned char *) NULL)
+    return((const MagicInfo *) GetValueFromLinkedList(magic_list,0));
+  if (length == 0)
+    return((const MagicInfo *) NULL);
+  /*
+    Search for magic tag.
+  */
+  LockSemaphoreInfo(magic_semaphore);
+  ResetLinkedListIterator(magic_list);
+  p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
+  while (p != (const MagicInfo *) NULL)
+  {
+    assert(p->offset >= 0);
+    if (((size_t) (p->offset+p->length) <= length) &&
+        (memcmp(magic+p->offset,p->magic,p->length) == 0))
+      break;
+    p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
+  }
+  if (p != (const MagicInfo *) NULL)
+    (void) InsertValueInLinkedList(magic_list,0,
+      RemoveElementByValueFromLinkedList(magic_list,p));
+  UnlockSemaphoreInfo(magic_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c I n f o L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagicInfoList() returns any image aliases that match the specified
+%  pattern.
+%
+%  The magic of the GetMagicInfoList function is:
+%
+%      const MagicInfo **GetMagicInfoList(const char *pattern,
+%        size_t *number_aliases,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_aliases:  This integer returns the number of aliases in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int MagicInfoCompare(const void *x,const void *y)
+{
+  const MagicInfo
+    **p,
+    **q;
+
+  p=(const MagicInfo **) x,
+  q=(const MagicInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->name,(*q)->name));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
+  size_t *number_aliases,ExceptionInfo *exception)
+{
+  const MagicInfo
+    **aliases;
+
+  register const MagicInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate magic list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (size_t *) NULL);
+  *number_aliases=0;
+  p=GetMagicInfo((const unsigned char *) NULL,0,exception);
+  if (p == (const MagicInfo *) NULL)
+    return((const MagicInfo **) NULL);
+  aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
+  if (aliases == (const MagicInfo **) NULL)
+    return((const MagicInfo **) NULL);
+  /*
+    Generate magic list.
+  */
+  LockSemaphoreInfo(magic_semaphore);
+  ResetLinkedListIterator(magic_list);
+  p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
+  for (i=0; p != (const MagicInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      aliases[i++]=p;
+    p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
+  }
+  UnlockSemaphoreInfo(magic_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
+  aliases[i]=(MagicInfo *) NULL;
+  *number_aliases=(size_t) i;
+  return(aliases);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagicList() returns any image format aliases that match the specified
+%  pattern.
+%
+%  The format of the GetMagicList function is:
+%
+%      char **GetMagicList(const char *pattern,size_t *number_aliases,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_aliases:  This integer returns the number of image format aliases
+%      in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int MagicCompare(const void *x,const void *y)
+{
+  register const char
+    *p,
+    *q;
+
+  p=(const char *) x;
+  q=(const char *) y;
+  return(LocaleCompare(p,q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetMagicList(const char *pattern,
+  size_t *number_aliases,ExceptionInfo *exception)
+{
+  char
+    **aliases;
+
+  register const MagicInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (size_t *) NULL);
+  *number_aliases=0;
+  p=GetMagicInfo((const unsigned char *) NULL,0,exception);
+  if (p == (const MagicInfo *) NULL)
+    return((char **) NULL);
+  aliases=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
+  if (aliases == (char **) NULL)
+    return((char **) NULL);
+  LockSemaphoreInfo(magic_semaphore);
+  ResetLinkedListIterator(magic_list);
+  p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
+  for (i=0; p != (const MagicInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      aliases[i++]=ConstantString(p->name);
+    p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
+  }
+  UnlockSemaphoreInfo(magic_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
+  aliases[i]=(char *) NULL;
+  *number_aliases=(size_t) i;
+  return(aliases);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c N a m e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagicName() returns the name associated with the magic.
+%
+%  The format of the GetMagicName method is:
+%
+%      const char *GetMagicName(const MagicInfo *magic_info)
+%
+%  A description of each parameter follows:
+%
+%    o magic_info:  The magic info.
+%
+*/
+MagickExport const char *GetMagicName(const MagicInfo *magic_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magic_info != (MagicInfo *) NULL);
+  assert(magic_info->signature == MagickSignature);
+  return(magic_info->name);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e M a g i c L i s t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeMagicList() initializes the magic list.
+%
+%  The format of the InitializeMagicList method is:
+%
+%      MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
+{
+  if ((magic_list == (LinkedListInfo *) NULL) &&
+      (instantiate_magic == MagickFalse))
+    {
+      if (magic_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&magic_semaphore);
+      LockSemaphoreInfo(magic_semaphore);
+      if ((magic_list == (LinkedListInfo *) NULL) &&
+          (instantiate_magic == MagickFalse))
+        {
+          (void) LoadMagicLists(MagicFilename,exception);
+          instantiate_magic=MagickTrue;
+        }
+      UnlockSemaphoreInfo(magic_semaphore);
+    }
+  return(magic_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t M a g i c I n f o                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListMagicInfo() lists the magic info to a file.
+%
+%  The format of the ListMagicInfo method is:
+%
+%      MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListMagicInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const char
+    *path;
+
+  const MagicInfo
+    **magic_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_aliases;
+
+  ssize_t
+    j;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  magic_info=GetMagicInfoList("*",&number_aliases,exception);
+  if (magic_info == (const MagicInfo **) NULL)
+    return(MagickFalse);
+  j=0;
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_aliases; i++)
+  {
+    if (magic_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (LocaleCompare(path,magic_info[i]->path) != 0))
+      {
+        if (magic_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
+        (void) FormatLocaleFile(file,"Name      Offset Target\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=magic_info[i]->path;
+    (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
+    for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
+      (void) FormatLocaleFile(file," ");
+    (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
+    if (magic_info[i]->target != (char *) NULL)
+      {
+        register ssize_t
+          j;
+
+        for (j=0; magic_info[i]->target[j] != '\0'; j++)
+          if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
+            (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
+          else
+            (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
+              ((unsigned char) magic_info[i]->target[j]));
+      }
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d M a g i c L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadMagicList() loads the magic configuration file which provides a mapping
+%  between magic attributes and a magic name.
+%
+%  The format of the LoadMagicList method is:
+%
+%      MagickBooleanType LoadMagicList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml: The magic list in XML format.
+%
+%    o filename: The magic list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadMagicList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  MagickBooleanType
+    status;
+
+  MagicInfo
+    *magic_info;
+
+  /*
+    Load the magic map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading magic configure file \"%s\" ...",filename);
+  if (xml == (char *) NULL)
+    return(MagickFalse);
+  if (magic_list == (LinkedListInfo *) NULL)
+    {
+      magic_list=NewLinkedList(0);
+      if (magic_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  magic_info=(MagicInfo *) NULL;
+  token=AcquireString(xml);
+  for (q=(char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadMagicList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<magic") == 0)
+      {
+        /*
+          Magic element.
+        */
+        magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
+        if (magic_info == (MagicInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
+        magic_info->path=ConstantString(filename);
+        magic_info->exempt=MagickFalse;
+        magic_info->signature=MagickSignature;
+        continue;
+      }
+    if (magic_info == (MagicInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AppendValueToLinkedList(magic_list,magic_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            magic_info->name);
+        magic_info=(MagicInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'N':
+      case 'n':
+      {
+        if (LocaleCompare((char *) keyword,"name") == 0)
+          {
+            magic_info->name=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'O':
+      case 'o':
+      {
+        if (LocaleCompare((char *) keyword,"offset") == 0)
+          {
+            magic_info->offset=(MagickOffsetType) StringToLong(token);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            magic_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      case 'T':
+      case 't':
+      {
+        if (LocaleCompare((char *) keyword,"target") == 0)
+          {
+            char
+              *p;
+
+            register unsigned char
+              *q;
+
+            size_t
+              length;
+
+            length=strlen(token);
+            magic_info->target=ConstantString(token);
+            magic_info->magic=(unsigned char *) ConstantString(token);
+            q=magic_info->magic;
+            for (p=magic_info->target; *p != '\0'; )
+            {
+              if (*p == '\\')
+                {
+                  p++;
+                  if (isdigit((int) ((unsigned char) *p)) != 0)
+                    {
+                      char
+                        *end;
+
+                      *q++=(unsigned char) strtol(p,&end,8);
+                      p+=(end-p);
+                      magic_info->length++;
+                      continue;
+                    }
+                  switch (*p)
+                  {
+                    case 'b': *q='\b'; break;
+                    case 'f': *q='\f'; break;
+                    case 'n': *q='\n'; break;
+                    case 'r': *q='\r'; break;
+                    case 't': *q='\t'; break;
+                    case 'v': *q='\v'; break;
+                    case 'a': *q='a'; break;
+                    case '?': *q='\?'; break;
+                    default: *q=(unsigned char) (*p); break;
+                  }
+                  p++;
+                  q++;
+                  magic_info->length++;
+                  continue;
+                }
+              else
+                if (LocaleNCompare(p,"&amp;",5) == 0)
+                  (void) CopyMagickString(p+1,p+5,length-magic_info->length);
+              *q++=(unsigned char) (*p++);
+              magic_info->length++;
+            }
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d M a g i c L i s t s                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadMagicLists() loads one or more magic configuration file which provides a
+%  mapping between magic attributes and a magic name.
+%
+%  The format of the LoadMagicLists method is:
+%
+%      MagickBooleanType LoadMagicLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadMagicLists(const char *filename,
+  ExceptionInfo *exception)
+{
+  char
+    path[MaxTextExtent];
+
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Load built-in magic map.
+  */
+  status=MagickFalse;
+  if (magic_list == (LinkedListInfo *) NULL)
+    {
+      magic_list=NewLinkedList(0);
+      if (magic_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
+  {
+    MagicInfo
+      *magic_info;
+
+    register const MagicMapInfo
+      *p;
+
+    p=MagicMap+i;
+    magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
+    if (magic_info == (MagicInfo *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
+        continue;
+      }
+    (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
+    magic_info->path=(char *) "[built-in]";
+    magic_info->name=(char *) p->name;
+    magic_info->offset=p->offset;
+    magic_info->target=(char *) p->magic;
+    magic_info->magic=(unsigned char *) p->magic;
+    magic_info->length=p->length;
+    magic_info->exempt=MagickTrue;
+    magic_info->signature=MagickSignature;
+    status=AppendValueToLinkedList(magic_list,magic_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
+  }
+  /*
+    Load external magic map.
+  */
+  *path='\0';
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent);
+    status|=LoadMagicList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M a g i c C o m p o n e n t G e n e s i s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagicComponentGenesis() instantiates the magic component.
+%
+%  The format of the MagicComponentGenesis method is:
+%
+%      MagickBooleanType MagicComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType MagicComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&magic_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M a g i c C o m p o n e n t T e r m i n u s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagicComponentTerminus() destroys the magic component.
+%
+%  The format of the MagicComponentTerminus method is:
+%
+%      MagicComponentTerminus(void)
+%
+*/
+
+static void *DestroyMagicElement(void *magic_info)
+{
+  register MagicInfo
+    *p;
+
+  p=(MagicInfo *) magic_info;
+  if (p->exempt == MagickFalse)
+    {
+      if (p->path != (char *) NULL)
+        p->path=DestroyString(p->path);
+      if (p->name != (char *) NULL)
+        p->name=DestroyString(p->name);
+      if (p->target != (char *) NULL)
+        p->target=DestroyString(p->target);
+      if (p->magic != (unsigned char *) NULL)
+        p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
+    }
+  p=(MagicInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void MagicComponentTerminus(void)
+{
+  if (magic_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&magic_semaphore);
+  LockSemaphoreInfo(magic_semaphore);
+  if (magic_list != (LinkedListInfo *) NULL)
+    magic_list=DestroyLinkedList(magic_list,DestroyMagicElement);
+  instantiate_magic=MagickFalse;
+  UnlockSemaphoreInfo(magic_semaphore);
+  DestroySemaphoreInfo(&magic_semaphore);
+}
diff --git a/MagickCore/magic.h b/MagickCore/magic.h
new file mode 100644
index 0000000..8f2dd74
--- /dev/null
+++ b/MagickCore/magic.h
@@ -0,0 +1,70 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore magic methods.
+*/
+#ifndef _MAGICKCORE_MAGIC_H
+#define _MAGICKCORE_MAGIC_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _MagicInfo
+{
+  char
+    *path,
+    *name,
+    *target;
+
+  unsigned char
+    *magic;
+
+  size_t
+    length;
+
+  MagickOffsetType
+    offset;
+
+  MagickBooleanType
+    exempt,
+    stealth;
+
+  size_t
+    signature;
+} MagicInfo;
+
+extern MagickExport char
+  **GetMagicList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetMagicName(const MagicInfo *);
+
+extern MagickExport MagickBooleanType
+  ListMagicInfo(FILE *,ExceptionInfo *),
+  MagicComponentGenesis(void);
+
+extern MagickExport const MagicInfo
+  *GetMagicInfo(const unsigned char *,const size_t,ExceptionInfo *),
+  **GetMagicInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport void
+  MagicComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/magick-config.h b/MagickCore/magick-config.h
new file mode 100644
index 0000000..d87175c
--- /dev/null
+++ b/MagickCore/magick-config.h
@@ -0,0 +1,1635 @@
+#ifndef _MAGICKCORE_MAGICK_CONFIG_H
+#define _MAGICKCORE_MAGICK_CONFIG_H 1
+ 
+/* MagickCore/magick-config.h. Generated automatically at end of configure. */
+/* config/config.h.  Generated from config.h.in by configure.  */
+/* config/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define if you have AUTOTRACE library */
+/* #undef AUTOTRACE_DELEGATE */
+
+/* Define if coders and filters are to be built as modules. */
+/* #undef BUILD_MODULES */
+
+/* Define if you have the bzip2 library */
+#ifndef MAGICKCORE_BZLIB_DELEGATE
+#define MAGICKCORE_BZLIB_DELEGATE 1
+#endif
+
+/* Define if you have CAIRO library */
+#ifndef MAGICKCORE_CAIRO_DELEGATE
+#define MAGICKCORE_CAIRO_DELEGATE 1
+#endif
+
+/* permit enciphering and deciphering image pixels */
+#ifndef MAGICKCORE_CIPHER_SUPPORT
+#define MAGICKCORE_CIPHER_SUPPORT 1
+#endif
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+/* #undef CLOSEDIR_VOID */
+
+/* Location of coder modules */
+#ifndef MAGICKCORE_CODER_PATH
+#define MAGICKCORE_CODER_PATH "/usr/local/lib/ImageMagick-6.7.1/modules-Q16/coders/"
+#endif
+
+/* Subdirectory of lib where coder modules are installed */
+#ifndef MAGICKCORE_CODER_RELATIVE_PATH
+#define MAGICKCORE_CODER_RELATIVE_PATH "ImageMagick-6.7.1/modules-Q16/coders"
+#endif
+
+/* Directory where architecture-dependent configuration files live. */
+#ifndef MAGICKCORE_CONFIGURE_PATH
+#define MAGICKCORE_CONFIGURE_PATH "/usr/local/etc/ImageMagick/"
+#endif
+
+/* Subdirectory of lib where architecture-dependent configuration files live.
+   */
+#ifndef MAGICKCORE_CONFIGURE_RELATIVE_PATH
+#define MAGICKCORE_CONFIGURE_RELATIVE_PATH "ImageMagick"
+#endif
+
+/* Define if you have DJVU library */
+/* #undef DJVU_DELEGATE */
+
+/* Directory where ImageMagick documents live. */
+#ifndef MAGICKCORE_DOCUMENTATION_PATH
+#define MAGICKCORE_DOCUMENTATION_PATH "/usr/local/share/doc/ImageMagick-7.0.0//"
+#endif
+
+/* Define if you have Display Postscript */
+/* #undef DPS_DELEGATE */
+
+/* Build self-contained, embeddable, zero-configuration ImageMagick */
+/* #undef EMBEDDABLE_SUPPORT */
+
+/* exclude deprecated methods in MagickCore API */
+/* #undef EXCLUDE_DEPRECATED */
+
+/* Directory where executables are installed. */
+#ifndef MAGICKCORE_EXECUTABLE_PATH
+#define MAGICKCORE_EXECUTABLE_PATH "/usr/local/bin/"
+#endif
+
+/* Define if you have FFTW library */
+/* #undef FFTW_DELEGATE */
+
+/* Location of filter modules */
+#ifndef MAGICKCORE_FILTER_PATH
+#define MAGICKCORE_FILTER_PATH "/usr/local/lib/ImageMagick-6.7.1/modules-Q16/filters/"
+#endif
+
+/* Subdirectory of lib where filter modules are installed */
+#ifndef MAGICKCORE_FILTER_RELATIVE_PATH
+#define MAGICKCORE_FILTER_RELATIVE_PATH "ImageMagick-6.7.1/modules-Q16/filters"
+#endif
+
+/* Define if you have FONTCONFIG library */
+#ifndef MAGICKCORE_FONTCONFIG_DELEGATE
+#define MAGICKCORE_FONTCONFIG_DELEGATE 1
+#endif
+
+/* Define if you have FlashPIX library */
+/* #undef FPX_DELEGATE */
+
+/* Define if you have FreeType (TrueType font) library */
+#ifndef MAGICKCORE_FREETYPE_DELEGATE
+#define MAGICKCORE_FREETYPE_DELEGATE 1
+#endif
+
+/* Define if you have Ghostscript library or framework */
+/* #undef GS_DELEGATE */
+
+/* Define if you have GVC library */
+#ifndef MAGICKCORE_GVC_DELEGATE
+#define MAGICKCORE_GVC_DELEGATE 1
+#endif
+
+/* Define to 1 if you have the `argz_add' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_ADD
+#define MAGICKCORE_HAVE_ARGZ_ADD 1
+#endif
+
+/* Define to 1 if you have the `argz_append' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_APPEND
+#define MAGICKCORE_HAVE_ARGZ_APPEND 1
+#endif
+
+/* Define to 1 if you have the `argz_count' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_COUNT
+#define MAGICKCORE_HAVE_ARGZ_COUNT 1
+#endif
+
+/* Define to 1 if you have the `argz_create_sep' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_CREATE_SEP
+#define MAGICKCORE_HAVE_ARGZ_CREATE_SEP 1
+#endif
+
+/* Define to 1 if you have the <argz.h> header file. */
+#ifndef MAGICKCORE_HAVE_ARGZ_H
+#define MAGICKCORE_HAVE_ARGZ_H 1
+#endif
+
+/* Define to 1 if you have the `argz_insert' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_INSERT
+#define MAGICKCORE_HAVE_ARGZ_INSERT 1
+#endif
+
+/* Define to 1 if you have the `argz_next' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_NEXT
+#define MAGICKCORE_HAVE_ARGZ_NEXT 1
+#endif
+
+/* Define to 1 if you have the `argz_stringify' function. */
+#ifndef MAGICKCORE_HAVE_ARGZ_STRINGIFY
+#define MAGICKCORE_HAVE_ARGZ_STRINGIFY 1
+#endif
+
+/* Define to 1 if you have the <arm/limits.h> header file. */
+/* #undef HAVE_ARM_LIMITS_H */
+
+/* Define to 1 if you have the `atexit' function. */
+#ifndef MAGICKCORE_HAVE_ATEXIT
+#define MAGICKCORE_HAVE_ATEXIT 1
+#endif
+
+/* Define to 1 if you have the `atoll' function. */
+#ifndef MAGICKCORE_HAVE_ATOLL
+#define MAGICKCORE_HAVE_ATOLL 1
+#endif
+
+/* define if bool is a built-in type */
+#ifndef MAGICKCORE_HAVE_BOOL
+#define MAGICKCORE_HAVE_BOOL /**/
+#endif
+
+/* Define to 1 if you have the `cabs' function. */
+#ifndef MAGICKCORE_HAVE_CABS
+#define MAGICKCORE_HAVE_CABS 1
+#endif
+
+/* Define to 1 if you have the `carg' function. */
+#ifndef MAGICKCORE_HAVE_CARG
+#define MAGICKCORE_HAVE_CARG 1
+#endif
+
+/* Define to 1 if you have the `cimag' function. */
+#ifndef MAGICKCORE_HAVE_CIMAG
+#define MAGICKCORE_HAVE_CIMAG 1
+#endif
+
+/* Define to 1 if you have the `clock' function. */
+#ifndef MAGICKCORE_HAVE_CLOCK
+#define MAGICKCORE_HAVE_CLOCK 1
+#endif
+
+/* Define to 1 if you have clock_gettime. */
+#ifndef MAGICKCORE_HAVE_CLOCK_GETTIME
+#define MAGICKCORE_HAVE_CLOCK_GETTIME 1
+#endif
+
+/* Define to 1 if clock_gettime supports CLOCK_REALTIME. */
+#ifndef MAGICKCORE_HAVE_CLOCK_REALTIME
+#define MAGICKCORE_HAVE_CLOCK_REALTIME 1
+#endif
+
+/* Define to 1 if you have the `closedir' function. */
+#ifndef MAGICKCORE_HAVE_CLOSEDIR
+#define MAGICKCORE_HAVE_CLOSEDIR 1
+#endif
+
+/* Define to 1 if you have the <CL/cl.h> header file. */
+/* #undef HAVE_CL_CL_H */
+
+/* Define to 1 if you have the <complex.h> header file. */
+#ifndef MAGICKCORE_HAVE_COMPLEX_H
+#define MAGICKCORE_HAVE_COMPLEX_H 1
+#endif
+
+/* Define to 1 if you have the `creal' function. */
+#ifndef MAGICKCORE_HAVE_CREAL
+#define MAGICKCORE_HAVE_CREAL 1
+#endif
+
+/* Define to 1 if you have the `ctime_r' function. */
+#ifndef MAGICKCORE_HAVE_CTIME_R
+#define MAGICKCORE_HAVE_CTIME_R 1
+#endif
+
+/* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if
+   you don't. */
+/* #undef HAVE_DECL_CYGWIN_CONV_PATH */
+
+/* Define to 1 if you have the declaration of `pread', and to 0 if you don't.
+   */
+#ifndef MAGICKCORE_HAVE_DECL_PREAD
+#define MAGICKCORE_HAVE_DECL_PREAD 1
+#endif
+
+/* Define to 1 if you have the declaration of `pwrite', and to 0 if you don't.
+   */
+#ifndef MAGICKCORE_HAVE_DECL_PWRITE
+#define MAGICKCORE_HAVE_DECL_PWRITE 1
+#endif
+
+/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
+   don't. */
+#ifndef MAGICKCORE_HAVE_DECL_STRLCPY
+#define MAGICKCORE_HAVE_DECL_STRLCPY 0
+#endif
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+   */
+/* #undef HAVE_DECL_TZNAME */
+
+/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you
+   don't. */
+#ifndef MAGICKCORE_HAVE_DECL_VSNPRINTF
+#define MAGICKCORE_HAVE_DECL_VSNPRINTF 1
+#endif
+
+/* Define to 1 if you have the `directio' function. */
+/* #undef HAVE_DIRECTIO */
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#ifndef MAGICKCORE_HAVE_DIRENT_H
+#define MAGICKCORE_HAVE_DIRENT_H 1
+#endif
+
+/* Define if you have the GNU dld library. */
+/* #undef HAVE_DLD */
+
+/* Define to 1 if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define to 1 if you have the `dlerror' function. */
+#ifndef MAGICKCORE_HAVE_DLERROR
+#define MAGICKCORE_HAVE_DLERROR 1
+#endif
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#ifndef MAGICKCORE_HAVE_DLFCN_H
+#define MAGICKCORE_HAVE_DLFCN_H 1
+#endif
+
+/* Define to 1 if you have the <dl.h> header file. */
+/* #undef HAVE_DL_H */
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the _dyld_func_lookup function. */
+/* #undef HAVE_DYLD */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#ifndef MAGICKCORE_HAVE_ERRNO_H
+#define MAGICKCORE_HAVE_ERRNO_H 1
+#endif
+
+/* Define to 1 if the system has the type `error_t'. */
+#ifndef MAGICKCORE_HAVE_ERROR_T
+#define MAGICKCORE_HAVE_ERROR_T 1
+#endif
+
+/* Define to 1 if you have the `execvp' function. */
+#ifndef MAGICKCORE_HAVE_EXECVP
+#define MAGICKCORE_HAVE_EXECVP 1
+#endif
+
+/* Define to 1 if you have the `fchmod' function. */
+#ifndef MAGICKCORE_HAVE_FCHMOD
+#define MAGICKCORE_HAVE_FCHMOD 1
+#endif
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#ifndef MAGICKCORE_HAVE_FCNTL_H
+#define MAGICKCORE_HAVE_FCNTL_H 1
+#endif
+
+/* Define to 1 if you have the `floor' function. */
+#ifndef MAGICKCORE_HAVE_FLOOR
+#define MAGICKCORE_HAVE_FLOOR 1
+#endif
+
+/* Define to 1 if you have the `fork' function. */
+#ifndef MAGICKCORE_HAVE_FORK
+#define MAGICKCORE_HAVE_FORK 1
+#endif
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#ifndef MAGICKCORE_HAVE_FSEEKO
+#define MAGICKCORE_HAVE_FSEEKO 1
+#endif
+
+/* Define to 1 if you have the <ft2build.h> header file. */
+#ifndef MAGICKCORE_HAVE_FT2BUILD_H
+#define MAGICKCORE_HAVE_FT2BUILD_H 1
+#endif
+
+/* Define to 1 if you have the `ftime' function. */
+#ifndef MAGICKCORE_HAVE_FTIME
+#define MAGICKCORE_HAVE_FTIME 1
+#endif
+
+/* Define to 1 if you have the `ftruncate' function. */
+#ifndef MAGICKCORE_HAVE_FTRUNCATE
+#define MAGICKCORE_HAVE_FTRUNCATE 1
+#endif
+
+/* Define to 1 if you have the `getcwd' function. */
+#ifndef MAGICKCORE_HAVE_GETCWD
+#define MAGICKCORE_HAVE_GETCWD 1
+#endif
+
+/* Define to 1 if you have the `getc_unlocked' function. */
+#ifndef MAGICKCORE_HAVE_GETC_UNLOCKED
+#define MAGICKCORE_HAVE_GETC_UNLOCKED 1
+#endif
+
+/* Define to 1 if you have the `getdtablesize' function. */
+#ifndef MAGICKCORE_HAVE_GETDTABLESIZE
+#define MAGICKCORE_HAVE_GETDTABLESIZE 1
+#endif
+
+/* Define to 1 if you have the `getexecname' function. */
+/* #undef HAVE_GETEXECNAME */
+
+/* Define to 1 if you have the `getpagesize' function. */
+#ifndef MAGICKCORE_HAVE_GETPAGESIZE
+#define MAGICKCORE_HAVE_GETPAGESIZE 1
+#endif
+
+/* Define to 1 if you have the `getpid' function. */
+#ifndef MAGICKCORE_HAVE_GETPID
+#define MAGICKCORE_HAVE_GETPID 1
+#endif
+
+/* Define to 1 if you have the `getrlimit' function. */
+#ifndef MAGICKCORE_HAVE_GETRLIMIT
+#define MAGICKCORE_HAVE_GETRLIMIT 1
+#endif
+
+/* Define to 1 if you have the `getrusage' function. */
+#ifndef MAGICKCORE_HAVE_GETRUSAGE
+#define MAGICKCORE_HAVE_GETRUSAGE 1
+#endif
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#ifndef MAGICKCORE_HAVE_GETTIMEOFDAY
+#define MAGICKCORE_HAVE_GETTIMEOFDAY 1
+#endif
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#ifndef MAGICKCORE_HAVE_GMTIME_R
+#define MAGICKCORE_HAVE_GMTIME_R 1
+#endif
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#ifndef MAGICKCORE_HAVE_INTMAX_T
+#define MAGICKCORE_HAVE_INTMAX_T 1
+#endif
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#ifndef MAGICKCORE_HAVE_INTPTR_T
+#define MAGICKCORE_HAVE_INTPTR_T 1
+#endif
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#ifndef MAGICKCORE_HAVE_INTTYPES_H
+#define MAGICKCORE_HAVE_INTTYPES_H 1
+#endif
+
+/* Define to 1 if you have the `j0' function. */
+#ifndef MAGICKCORE_HAVE_J0
+#define MAGICKCORE_HAVE_J0 1
+#endif
+
+/* Define to 1 if you have the `j1' function. */
+#ifndef MAGICKCORE_HAVE_J1
+#define MAGICKCORE_HAVE_J1 1
+#endif
+
+/* Define if you have the <lcms2.h> header file. */
+#ifndef MAGICKCORE_HAVE_LCMS2_H
+#define MAGICKCORE_HAVE_LCMS2_H 1
+#endif
+
+/* Define if you have the <lcms2/lcms2.h> header file. */
+/* #undef HAVE_LCMS2_LCMS2_H */
+
+/* Define if you have the <lcms.h> header file. */
+/* #undef HAVE_LCMS_H */
+
+/* Define if you have the <lcms/lcms.h> header file. */
+/* #undef HAVE_LCMS_LCMS_H */
+
+/* Define if you have the libdl library or equivalent. */
+#ifndef MAGICKCORE_HAVE_LIBDL
+#define MAGICKCORE_HAVE_LIBDL 1
+#endif
+
+/* Define if libdlloader will be built on this platform */
+#ifndef MAGICKCORE_HAVE_LIBDLLOADER
+#define MAGICKCORE_HAVE_LIBDLLOADER 1
+#endif
+
+/* Define to 1 if you have the `gcov' library (-lgcov). */
+/* #undef HAVE_LIBGCOV */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#ifndef MAGICKCORE_HAVE_LIMITS_H
+#define MAGICKCORE_HAVE_LIMITS_H 1
+#endif
+
+/* Define to 1 if you have the <linux/unistd.h> header file. */
+#ifndef MAGICKCORE_HAVE_LINUX_UNISTD_H
+#define MAGICKCORE_HAVE_LINUX_UNISTD_H 1
+#endif
+
+/* Define to 1 if you have the `lltostr' function. */
+/* #undef HAVE_LLTOSTR */
+
+/* Define to 1 if you have the <locale.h> header file. */
+#ifndef MAGICKCORE_HAVE_LOCALE_H
+#define MAGICKCORE_HAVE_LOCALE_H 1
+#endif
+
+/* Define to 1 if you have the `localtime_r' function. */
+#ifndef MAGICKCORE_HAVE_LOCALTIME_R
+#define MAGICKCORE_HAVE_LOCALTIME_R 1
+#endif
+
+/* Define to 1 if the system has the type `long double'. */
+#ifndef MAGICKCORE_HAVE_LONG_DOUBLE
+#define MAGICKCORE_HAVE_LONG_DOUBLE 1
+#endif
+
+/* Define to 1 if the type `long double' works and has more range or precision
+   than `double'. */
+#ifndef MAGICKCORE_HAVE_LONG_DOUBLE_WIDER
+#define MAGICKCORE_HAVE_LONG_DOUBLE_WIDER 1
+#endif
+
+/* Define to 1 if the system has the type `long long int'. */
+#ifndef MAGICKCORE_HAVE_LONG_LONG_INT
+#define MAGICKCORE_HAVE_LONG_LONG_INT 1
+#endif
+
+/* Define to 1 if you have the `lstat' function. */
+#ifndef MAGICKCORE_HAVE_LSTAT
+#define MAGICKCORE_HAVE_LSTAT 1
+#endif
+
+/* Define this if a modern libltdl is already installed */
+#ifndef MAGICKCORE_HAVE_LTDL
+#define MAGICKCORE_HAVE_LTDL 1
+#endif
+
+/* Define to 1 if you have the <machine/param.h> header file. */
+/* #undef HAVE_MACHINE_PARAM_H */
+
+/* Define to 1 if you have the <mach-o/dyld.h> header file. */
+/* #undef HAVE_MACH_O_DYLD_H */
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#ifndef MAGICKCORE_HAVE_MBSTATE_T
+#define MAGICKCORE_HAVE_MBSTATE_T 1
+#endif
+
+/* Define to 1 if you have the `memmove' function. */
+#ifndef MAGICKCORE_HAVE_MEMMOVE
+#define MAGICKCORE_HAVE_MEMMOVE 1
+#endif
+
+/* Define to 1 if you have the <memory.h> header file. */
+#ifndef MAGICKCORE_HAVE_MEMORY_H
+#define MAGICKCORE_HAVE_MEMORY_H 1
+#endif
+
+/* Define to 1 if you have the `memset' function. */
+#ifndef MAGICKCORE_HAVE_MEMSET
+#define MAGICKCORE_HAVE_MEMSET 1
+#endif
+
+/* Define to 1 if you have the `mkstemp' function. */
+#ifndef MAGICKCORE_HAVE_MKSTEMP
+#define MAGICKCORE_HAVE_MKSTEMP 1
+#endif
+
+/* Define to 1 if you have a working `mmap' system call. */
+#ifndef MAGICKCORE_HAVE_MMAP
+#define MAGICKCORE_HAVE_MMAP 1
+#endif
+
+/* Define to 1 if you have a working `mmap' system call. */
+#ifndef MAGICKCORE_HAVE_MMAP_FILEIO
+#define MAGICKCORE_HAVE_MMAP_FILEIO 1
+#endif
+
+/* Define to 1 if you have the `munmap' function. */
+#ifndef MAGICKCORE_HAVE_MUNMAP
+#define MAGICKCORE_HAVE_MUNMAP 1
+#endif
+
+/* define if the compiler implements namespaces */
+#ifndef MAGICKCORE_HAVE_NAMESPACES
+#define MAGICKCORE_HAVE_NAMESPACES /**/
+#endif
+
+/* Define if g++ supports namespace std. */
+#ifndef MAGICKCORE_HAVE_NAMESPACE_STD
+#define MAGICKCORE_HAVE_NAMESPACE_STD /**/
+#endif
+
+/* Define to 1 if you have the `nanosleep' function. */
+#ifndef MAGICKCORE_HAVE_NANOSLEEP
+#define MAGICKCORE_HAVE_NANOSLEEP 1
+#endif
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Define to 1 if you have the `newlocale' function. */
+#ifndef MAGICKCORE_HAVE_NEWLOCALE
+#define MAGICKCORE_HAVE_NEWLOCALE 1
+#endif
+
+/* Define to 1 if you have the <OpenCL/cl.h> header file. */
+/* #undef HAVE_OPENCL_CL_H */
+
+/* Define to 1 if you have the `opendir' function. */
+#ifndef MAGICKCORE_HAVE_OPENDIR
+#define MAGICKCORE_HAVE_OPENDIR 1
+#endif
+
+/* Define to 1 if you have the <OS.h> header file. */
+/* #undef HAVE_OS_H */
+
+/* Define to 1 if you have the `pclose' function. */
+#ifndef MAGICKCORE_HAVE_PCLOSE
+#define MAGICKCORE_HAVE_PCLOSE 1
+#endif
+
+/* Define to 1 if you have the `poll' function. */
+#ifndef MAGICKCORE_HAVE_POLL
+#define MAGICKCORE_HAVE_POLL 1
+#endif
+
+/* Define to 1 if you have the `popen' function. */
+#ifndef MAGICKCORE_HAVE_POPEN
+#define MAGICKCORE_HAVE_POPEN 1
+#endif
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+#ifndef MAGICKCORE_HAVE_POSIX_FADVISE
+#define MAGICKCORE_HAVE_POSIX_FADVISE 1
+#endif
+
+/* Define to 1 if you have the `posix_fallocate' function. */
+#ifndef MAGICKCORE_HAVE_POSIX_FALLOCATE
+#define MAGICKCORE_HAVE_POSIX_FALLOCATE 1
+#endif
+
+/* Define to 1 if you have the `posix_madvise' function. */
+#ifndef MAGICKCORE_HAVE_POSIX_MADVISE
+#define MAGICKCORE_HAVE_POSIX_MADVISE 1
+#endif
+
+/* Define to 1 if you have the `posix_memalign' function. */
+#ifndef MAGICKCORE_HAVE_POSIX_MEMALIGN
+#define MAGICKCORE_HAVE_POSIX_MEMALIGN 1
+#endif
+
+/* Define to 1 if you have the `posix_spawnp' function. */
+#ifndef MAGICKCORE_HAVE_POSIX_SPAWNP
+#define MAGICKCORE_HAVE_POSIX_SPAWNP 1
+#endif
+
+/* Define to 1 if you have the `pow' function. */
+#ifndef MAGICKCORE_HAVE_POW
+#define MAGICKCORE_HAVE_POW 1
+#endif
+
+/* Define to 1 if you have the `pread' function. */
+#ifndef MAGICKCORE_HAVE_PREAD
+#define MAGICKCORE_HAVE_PREAD 1
+#endif
+
+/* Define if libtool can extract symbol lists from object files. */
+#ifndef MAGICKCORE_HAVE_PRELOADED_SYMBOLS
+#define MAGICKCORE_HAVE_PRELOADED_SYMBOLS 1
+#endif
+
+/* Define to 1 if you have the <process.h> header file. */
+/* #undef HAVE_PROCESS_H */
+
+/* Define if you have POSIX threads libraries and header files. */
+#ifndef MAGICKCORE_HAVE_PTHREAD
+#define MAGICKCORE_HAVE_PTHREAD 1
+#endif
+
+/* Define to 1 if you have the `pwrite' function. */
+#ifndef MAGICKCORE_HAVE_PWRITE
+#define MAGICKCORE_HAVE_PWRITE 1
+#endif
+
+/* Define to 1 if you have the `qsort_r' function. */
+#ifndef MAGICKCORE_HAVE_QSORT_R
+#define MAGICKCORE_HAVE_QSORT_R 1
+#endif
+
+/* Define to 1 if you have the `raise' function. */
+#ifndef MAGICKCORE_HAVE_RAISE
+#define MAGICKCORE_HAVE_RAISE 1
+#endif
+
+/* Define to 1 if you have the `rand_r' function. */
+#ifndef MAGICKCORE_HAVE_RAND_R
+#define MAGICKCORE_HAVE_RAND_R 1
+#endif
+
+/* Define to 1 if you have the `readdir' function. */
+#ifndef MAGICKCORE_HAVE_READDIR
+#define MAGICKCORE_HAVE_READDIR 1
+#endif
+
+/* Define to 1 if you have the `readdir_r' function. */
+#ifndef MAGICKCORE_HAVE_READDIR_R
+#define MAGICKCORE_HAVE_READDIR_R 1
+#endif
+
+/* Define to 1 if you have the `readlink' function. */
+#ifndef MAGICKCORE_HAVE_READLINK
+#define MAGICKCORE_HAVE_READLINK 1
+#endif
+
+/* Define to 1 if you have the `realpath' function. */
+#ifndef MAGICKCORE_HAVE_REALPATH
+#define MAGICKCORE_HAVE_REALPATH 1
+#endif
+
+/* Define to 1 if you have the `seekdir' function. */
+#ifndef MAGICKCORE_HAVE_SEEKDIR
+#define MAGICKCORE_HAVE_SEEKDIR 1
+#endif
+
+/* Define to 1 if you have the `select' function. */
+#ifndef MAGICKCORE_HAVE_SELECT
+#define MAGICKCORE_HAVE_SELECT 1
+#endif
+
+/* Define to 1 if you have the `setlocale' function. */
+#ifndef MAGICKCORE_HAVE_SETLOCALE
+#define MAGICKCORE_HAVE_SETLOCALE 1
+#endif
+
+/* Define to 1 if you have the `setvbuf' function. */
+#ifndef MAGICKCORE_HAVE_SETVBUF
+#define MAGICKCORE_HAVE_SETVBUF 1
+#endif
+
+/* X11 server supports shape extension */
+#ifndef MAGICKCORE_HAVE_SHAPE
+#define MAGICKCORE_HAVE_SHAPE 1
+#endif
+
+/* X11 server supports shared memory extension */
+#ifndef MAGICKCORE_HAVE_SHARED_MEMORY
+#define MAGICKCORE_HAVE_SHARED_MEMORY 1
+#endif
+
+/* Define if you have the shl_load function. */
+/* #undef HAVE_SHL_LOAD */
+
+/* Define to 1 if you have the `sigaction' function. */
+#ifndef MAGICKCORE_HAVE_SIGACTION
+#define MAGICKCORE_HAVE_SIGACTION 1
+#endif
+
+/* Define to 1 if you have the `sigemptyset' function. */
+#ifndef MAGICKCORE_HAVE_SIGEMPTYSET
+#define MAGICKCORE_HAVE_SIGEMPTYSET 1
+#endif
+
+/* Define to 1 if you have the `spawnvp' function. */
+/* #undef HAVE_SPAWNVP */
+
+/* Define to 1 if you have the `sqrt' function. */
+#ifndef MAGICKCORE_HAVE_SQRT
+#define MAGICKCORE_HAVE_SQRT 1
+#endif
+
+/* Define to 1 if you have the `stat' function. */
+#ifndef MAGICKCORE_HAVE_STAT
+#define MAGICKCORE_HAVE_STAT 1
+#endif
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#ifndef MAGICKCORE_HAVE_STDARG_H
+#define MAGICKCORE_HAVE_STDARG_H 1
+#endif
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#ifndef MAGICKCORE_HAVE_STDBOOL_H
+#define MAGICKCORE_HAVE_STDBOOL_H 1
+#endif
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#ifndef MAGICKCORE_HAVE_STDINT_H
+#define MAGICKCORE_HAVE_STDINT_H 1
+#endif
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#ifndef MAGICKCORE_HAVE_STDLIB_H
+#define MAGICKCORE_HAVE_STDLIB_H 1
+#endif
+
+/* define if the compiler supports ISO C++ standard library */
+#ifndef MAGICKCORE_HAVE_STD_LIBS
+#define MAGICKCORE_HAVE_STD_LIBS /**/
+#endif
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#ifndef MAGICKCORE_HAVE_STRCASECMP
+#define MAGICKCORE_HAVE_STRCASECMP 1
+#endif
+
+/* Define to 1 if you have the `strchr' function. */
+#ifndef MAGICKCORE_HAVE_STRCHR
+#define MAGICKCORE_HAVE_STRCHR 1
+#endif
+
+/* Define to 1 if you have the `strcspn' function. */
+#ifndef MAGICKCORE_HAVE_STRCSPN
+#define MAGICKCORE_HAVE_STRCSPN 1
+#endif
+
+/* Define to 1 if you have the `strdup' function. */
+#ifndef MAGICKCORE_HAVE_STRDUP
+#define MAGICKCORE_HAVE_STRDUP 1
+#endif
+
+/* Define to 1 if you have the `strerror' function. */
+#ifndef MAGICKCORE_HAVE_STRERROR
+#define MAGICKCORE_HAVE_STRERROR 1
+#endif
+
+/* Define to 1 if you have the `strerror_r' function. */
+#ifndef MAGICKCORE_HAVE_STRERROR_R
+#define MAGICKCORE_HAVE_STRERROR_R 1
+#endif
+
+/* Define to 1 if cpp supports the ANSI # stringizing operator. */
+#ifndef MAGICKCORE_HAVE_STRINGIZE
+#define MAGICKCORE_HAVE_STRINGIZE 1
+#endif
+
+/* Define to 1 if you have the <strings.h> header file. */
+#ifndef MAGICKCORE_HAVE_STRINGS_H
+#define MAGICKCORE_HAVE_STRINGS_H 1
+#endif
+
+/* Define to 1 if you have the <string.h> header file. */
+#ifndef MAGICKCORE_HAVE_STRING_H
+#define MAGICKCORE_HAVE_STRING_H 1
+#endif
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#ifndef MAGICKCORE_HAVE_STRNCASECMP
+#define MAGICKCORE_HAVE_STRNCASECMP 1
+#endif
+
+/* Define to 1 if you have the `strpbrk' function. */
+#ifndef MAGICKCORE_HAVE_STRPBRK
+#define MAGICKCORE_HAVE_STRPBRK 1
+#endif
+
+/* Define to 1 if you have the `strrchr' function. */
+#ifndef MAGICKCORE_HAVE_STRRCHR
+#define MAGICKCORE_HAVE_STRRCHR 1
+#endif
+
+/* Define to 1 if you have the `strspn' function. */
+#ifndef MAGICKCORE_HAVE_STRSPN
+#define MAGICKCORE_HAVE_STRSPN 1
+#endif
+
+/* Define to 1 if you have the `strstr' function. */
+#ifndef MAGICKCORE_HAVE_STRSTR
+#define MAGICKCORE_HAVE_STRSTR 1
+#endif
+
+/* Define to 1 if you have the `strtod' function. */
+#ifndef MAGICKCORE_HAVE_STRTOD
+#define MAGICKCORE_HAVE_STRTOD 1
+#endif
+
+/* Define to 1 if you have the `strtod_l' function. */
+#ifndef MAGICKCORE_HAVE_STRTOD_L
+#define MAGICKCORE_HAVE_STRTOD_L 1
+#endif
+
+/* Define to 1 if you have the `strtol' function. */
+#ifndef MAGICKCORE_HAVE_STRTOL
+#define MAGICKCORE_HAVE_STRTOL 1
+#endif
+
+/* Define to 1 if you have the `strtoul' function. */
+#ifndef MAGICKCORE_HAVE_STRTOUL
+#define MAGICKCORE_HAVE_STRTOUL 1
+#endif
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#ifndef MAGICKCORE_HAVE_STRUCT_TM_TM_ZONE
+#define MAGICKCORE_HAVE_STRUCT_TM_TM_ZONE 1
+#endif
+
+/* Define to 1 if you have the `symlink' function. */
+#ifndef MAGICKCORE_HAVE_SYMLINK
+#define MAGICKCORE_HAVE_SYMLINK 1
+#endif
+
+/* Define to 1 if you have the `sysconf' function. */
+#ifndef MAGICKCORE_HAVE_SYSCONF
+#define MAGICKCORE_HAVE_SYSCONF 1
+#endif
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/dl.h> header file. */
+/* #undef HAVE_SYS_DL_H */
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_IPC_H
+#define MAGICKCORE_HAVE_SYS_IPC_H 1
+#endif
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_PARAM_H
+#define MAGICKCORE_HAVE_SYS_PARAM_H 1
+#endif
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_RESOURCE_H
+#define MAGICKCORE_HAVE_SYS_RESOURCE_H 1
+#endif
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_SELECT_H
+#define MAGICKCORE_HAVE_SYS_SELECT_H 1
+#endif
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_SOCKET_H
+#define MAGICKCORE_HAVE_SYS_SOCKET_H 1
+#endif
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_STAT_H
+#define MAGICKCORE_HAVE_SYS_STAT_H 1
+#endif
+
+/* Define to 1 if you have the <sys/syslimits.h> header file. */
+/* #undef HAVE_SYS_SYSLIMITS_H */
+
+/* Define to 1 if you have the <sys/timeb.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_TIMEB_H
+#define MAGICKCORE_HAVE_SYS_TIMEB_H 1
+#endif
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_TIMES_H
+#define MAGICKCORE_HAVE_SYS_TIMES_H 1
+#endif
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_TIME_H
+#define MAGICKCORE_HAVE_SYS_TIME_H 1
+#endif
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_TYPES_H
+#define MAGICKCORE_HAVE_SYS_TYPES_H 1
+#endif
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#ifndef MAGICKCORE_HAVE_SYS_WAIT_H
+#define MAGICKCORE_HAVE_SYS_WAIT_H 1
+#endif
+
+/* Define to 1 if you have the `telldir' function. */
+#ifndef MAGICKCORE_HAVE_TELLDIR
+#define MAGICKCORE_HAVE_TELLDIR 1
+#endif
+
+/* Define to 1 if you have the `tempnam' function. */
+#ifndef MAGICKCORE_HAVE_TEMPNAM
+#define MAGICKCORE_HAVE_TEMPNAM 1
+#endif
+
+/* Define to 1 if you have the <tiffconf.h> header file. */
+#ifndef MAGICKCORE_HAVE_TIFFCONF_H
+#define MAGICKCORE_HAVE_TIFFCONF_H 1
+#endif
+
+/* Define to 1 if you have the `TIFFIsCODECConfigured' function. */
+#ifndef MAGICKCORE_HAVE_TIFFISCODECCONFIGURED
+#define MAGICKCORE_HAVE_TIFFISCODECCONFIGURED 1
+#endif
+
+/* Define to 1 if you have the `TIFFMergeFieldInfo' function. */
+#ifndef MAGICKCORE_HAVE_TIFFMERGEFIELDINFO
+#define MAGICKCORE_HAVE_TIFFMERGEFIELDINFO 1
+#endif
+
+/* Define to 1 if you have the `TIFFReadEXIFDirectory' function. */
+#ifndef MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY
+#define MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY 1
+#endif
+
+/* Define to 1 if you have the `TIFFSetErrorHandlerExt' function. */
+#ifndef MAGICKCORE_HAVE_TIFFSETERRORHANDLEREXT
+#define MAGICKCORE_HAVE_TIFFSETERRORHANDLEREXT 1
+#endif
+
+/* Define to 1 if you have the `TIFFSetTagExtender' function. */
+#ifndef MAGICKCORE_HAVE_TIFFSETTAGEXTENDER
+#define MAGICKCORE_HAVE_TIFFSETTAGEXTENDER 1
+#endif
+
+/* Define to 1 if you have the `TIFFSetWarningHandlerExt' function. */
+#ifndef MAGICKCORE_HAVE_TIFFSETWARNINGHANDLEREXT
+#define MAGICKCORE_HAVE_TIFFSETWARNINGHANDLEREXT 1
+#endif
+
+/* Define to 1 if you have the `TIFFSwabArrayOfTriples' function. */
+#ifndef MAGICKCORE_HAVE_TIFFSWABARRAYOFTRIPLES
+#define MAGICKCORE_HAVE_TIFFSWABARRAYOFTRIPLES 1
+#endif
+
+/* Define to 1 if you have the `times' function. */
+#ifndef MAGICKCORE_HAVE_TIMES
+#define MAGICKCORE_HAVE_TIMES 1
+#endif
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+   `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#ifndef MAGICKCORE_HAVE_TM_ZONE
+#define MAGICKCORE_HAVE_TM_ZONE 1
+#endif
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+   `tzname'. */
+/* #undef HAVE_TZNAME */
+
+/* Define to 1 if the system has the type `uintmax_t'. */
+#ifndef MAGICKCORE_HAVE_UINTMAX_T
+#define MAGICKCORE_HAVE_UINTMAX_T 1
+#endif
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#ifndef MAGICKCORE_HAVE_UINTPTR_T
+#define MAGICKCORE_HAVE_UINTPTR_T 1
+#endif
+
+/* Define to 1 if you have the `ulltostr' function. */
+/* #undef HAVE_ULLTOSTR */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#ifndef MAGICKCORE_HAVE_UNISTD_H
+#define MAGICKCORE_HAVE_UNISTD_H 1
+#endif
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#ifndef MAGICKCORE_HAVE_UNSIGNED_LONG_LONG_INT
+#define MAGICKCORE_HAVE_UNSIGNED_LONG_LONG_INT 1
+#endif
+
+/* Define to 1 if you have the `uselocale' function. */
+#ifndef MAGICKCORE_HAVE_USELOCALE
+#define MAGICKCORE_HAVE_USELOCALE 1
+#endif
+
+/* Define to 1 if you have the `usleep' function. */
+#ifndef MAGICKCORE_HAVE_USLEEP
+#define MAGICKCORE_HAVE_USLEEP 1
+#endif
+
+/* Define to 1 if you have the `utime' function. */
+#ifndef MAGICKCORE_HAVE_UTIME
+#define MAGICKCORE_HAVE_UTIME 1
+#endif
+
+/* Define to 1 if you have the `vfork' function. */
+#ifndef MAGICKCORE_HAVE_VFORK
+#define MAGICKCORE_HAVE_VFORK 1
+#endif
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 if you have the `vfprintf' function. */
+#ifndef MAGICKCORE_HAVE_VFPRINTF
+#define MAGICKCORE_HAVE_VFPRINTF 1
+#endif
+
+/* Define to 1 if you have the `vfprintf_l' function. */
+/* #undef HAVE_VFPRINTF_L */
+
+/* Define to 1 if you have the `vprintf' function. */
+#ifndef MAGICKCORE_HAVE_VPRINTF
+#define MAGICKCORE_HAVE_VPRINTF 1
+#endif
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#ifndef MAGICKCORE_HAVE_VSNPRINTF
+#define MAGICKCORE_HAVE_VSNPRINTF 1
+#endif
+
+/* Define to 1 if you have the `vsnprintf_l' function. */
+/* #undef HAVE_VSNPRINTF_L */
+
+/* Define to 1 if you have the `vsprintf' function. */
+#ifndef MAGICKCORE_HAVE_VSPRINTF
+#define MAGICKCORE_HAVE_VSPRINTF 1
+#endif
+
+/* Define to 1 if you have the `waitpid' function. */
+#ifndef MAGICKCORE_HAVE_WAITPID
+#define MAGICKCORE_HAVE_WAITPID 1
+#endif
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#ifndef MAGICKCORE_HAVE_WCHAR_H
+#define MAGICKCORE_HAVE_WCHAR_H 1
+#endif
+
+/* Define to 1 if you have the <windows.h> header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* This value is set to 1 to indicate that the system argz facility works */
+#ifndef MAGICKCORE_HAVE_WORKING_ARGZ
+#define MAGICKCORE_HAVE_WORKING_ARGZ 1
+#endif
+
+/* Define to 1 if `fork' works. */
+#ifndef MAGICKCORE_HAVE_WORKING_FORK
+#define MAGICKCORE_HAVE_WORKING_FORK 1
+#endif
+
+/* Define to 1 if `vfork' works. */
+#ifndef MAGICKCORE_HAVE_WORKING_VFORK
+#define MAGICKCORE_HAVE_WORKING_VFORK 1
+#endif
+
+/* Define to 1 if you have the <xlocale.h> header file. */
+#ifndef MAGICKCORE_HAVE_XLOCALE_H
+#define MAGICKCORE_HAVE_XLOCALE_H 1
+#endif
+
+/* Define to 1 if the system has the type `_Bool'. */
+#ifndef MAGICKCORE_HAVE__BOOL
+#define MAGICKCORE_HAVE__BOOL 1
+#endif
+
+/* Define to 1 if you have the `_exit' function. */
+#ifndef MAGICKCORE_HAVE__EXIT
+#define MAGICKCORE_HAVE__EXIT 1
+#endif
+
+/* Define to 1 if you have the `_NSGetExecutablePath' function. */
+/* #undef HAVE__NSGETEXECUTABLEPATH */
+
+/* Define to 1 if you have the `_pclose' function. */
+/* #undef HAVE__PCLOSE */
+
+/* Define to 1 if you have the `_popen' function. */
+/* #undef HAVE__POPEN */
+
+/* Define to 1 if you have the `_wfopen' function. */
+/* #undef HAVE__WFOPEN */
+
+/* Define to 1 if you have the `_wstat' function. */
+/* #undef HAVE__WSTAT */
+
+/* define if your compiler has __attribute__ */
+#ifndef MAGICKCORE_HAVE___ATTRIBUTE__
+#define MAGICKCORE_HAVE___ATTRIBUTE__ 1
+#endif
+
+/* accurately represent the wide range of intensity levels in real scenes */
+/* #undef HDRI_SUPPORT */
+
+/* Define if you have umem memory allocation library */
+/* #undef HasUMEM */
+
+/* ImageMagick is formally installed under prefix */
+#ifndef MAGICKCORE_INSTALLED_SUPPORT
+#define MAGICKCORE_INSTALLED_SUPPORT 1
+#endif
+
+/* Define if you have JBIG library */
+/* #undef JBIG_DELEGATE */
+
+/* Define if you have JPEG version 2 "Jasper" library */
+#ifndef MAGICKCORE_JP2_DELEGATE
+#define MAGICKCORE_JP2_DELEGATE 1
+#endif
+
+/* Define if you have JPEG library */
+#ifndef MAGICKCORE_JPEG_DELEGATE
+#define MAGICKCORE_JPEG_DELEGATE 1
+#endif
+
+/* Define if you have LCMS (v1.11 or later) library */
+#ifndef MAGICKCORE_LCMS_DELEGATE
+#define MAGICKCORE_LCMS_DELEGATE 1
+#endif
+
+/* Directory where architecture-dependent files live. */
+#ifndef MAGICKCORE_LIBRARY_PATH
+#define MAGICKCORE_LIBRARY_PATH "/usr/local/lib/ImageMagick-6.7.1/"
+#endif
+
+/* Subdirectory of lib where ImageMagick architecture dependent files are
+   installed */
+#ifndef MAGICKCORE_LIBRARY_RELATIVE_PATH
+#define MAGICKCORE_LIBRARY_RELATIVE_PATH "ImageMagick-6.7.1"
+#endif
+
+/* Define if you have LQR library */
+/* #undef LQR_DELEGATE */
+
+/* Define if using libltdl to support dynamically loadable modules */
+#ifndef MAGICKCORE_LTDL_DELEGATE
+#define MAGICKCORE_LTDL_DELEGATE 1
+#endif
+
+/* Define if the OS needs help to load dependent libraries for dlopen(). */
+/* #undef LTDL_DLOPEN_DEPLIBS */
+
+/* Define to the system default library search path. */
+#ifndef MAGICKCORE_LT_DLSEARCH_PATH
+#define MAGICKCORE_LT_DLSEARCH_PATH "/lib64:/usr/lib64:/lib:/usr/lib:/usr/lib64/atlas:/usr/lib64/mysql:/usr/lib64/qt-3.3/lib:/usr/lib64/tcl8.5/tclx8.4:/usr/lib64/tcl8.5:/usr/lib/wine/:/usr/lib64/wine/:/usr/lib64/xulrunner-2"
+#endif
+
+/* The archive extension */
+#ifndef MAGICKCORE_LT_LIBEXT
+#define MAGICKCORE_LT_LIBEXT "a"
+#endif
+
+/* The archive prefix */
+#ifndef MAGICKCORE_LT_LIBPREFIX
+#define MAGICKCORE_LT_LIBPREFIX "lib"
+#endif
+
+/* Define to the extension used for runtime loadable modules, say, ".so". */
+#ifndef MAGICKCORE_LT_MODULE_EXT
+#define MAGICKCORE_LT_MODULE_EXT ".so"
+#endif
+
+/* Define to the name of the environment variable that determines the run-time
+   module search path. */
+#ifndef MAGICKCORE_LT_MODULE_PATH_VAR
+#define MAGICKCORE_LT_MODULE_PATH_VAR "LD_LIBRARY_PATH"
+#endif
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#ifndef MAGICKCORE_LT_OBJDIR
+#define MAGICKCORE_LT_OBJDIR ".libs/"
+#endif
+
+/* Define if you have lzma compression library */
+#ifndef MAGICKCORE_LZMA_DELEGATE
+#define MAGICKCORE_LZMA_DELEGATE 1
+#endif
+
+/* Define to prepend to default font search path. */
+/* #undef MAGICK_FONT_PATH */
+
+/* Magick API method prefix */
+/* #undef NAMESPACE_PREFIX */
+
+/* Define to 1 if assertions should be disabled. */
+/* #undef NDEBUG */
+
+/* Define if dlsym() requires a leading underscore in symbol names. */
+/* #undef NEED_USCORE */
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Define if you have OPENEXR library */
+/* #undef OPENEXR_DELEGATE */
+
+/* Define to the address where bug reports for this package should be sent. */
+#ifndef MAGICKCORE_PACKAGE_BUGREPORT
+#define MAGICKCORE_PACKAGE_BUGREPORT "http://www.imagemagick.org"
+#endif
+
+/* Define to the full name of this package. */
+#ifndef MAGICKCORE_PACKAGE_NAME
+#define MAGICKCORE_PACKAGE_NAME "ImageMagick"
+#endif
+
+/* Define to the full name and version of this package. */
+#ifndef MAGICKCORE_PACKAGE_STRING
+#define MAGICKCORE_PACKAGE_STRING "ImageMagick 7.0.0"
+#endif
+
+/* Define to the one symbol short name of this package. */
+#ifndef MAGICKCORE_PACKAGE_TARNAME
+#define MAGICKCORE_PACKAGE_TARNAME "ImageMagick-7.0.0"
+#endif
+
+/* Define to the home page for this package. */
+#ifndef MAGICKCORE_PACKAGE_URL
+#define MAGICKCORE_PACKAGE_URL ""
+#endif
+
+/* Define to the version of this package. */
+#ifndef MAGICKCORE_PACKAGE_VERSION
+#define MAGICKCORE_PACKAGE_VERSION "7.0.0"
+#endif
+
+/* Define if you have PNG library */
+#ifndef MAGICKCORE_PNG_DELEGATE
+#define MAGICKCORE_PNG_DELEGATE 1
+#endif
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Pixel cache threshold in MB (defaults to available memory) */
+/* #undef PixelCacheThreshold */
+
+/* Number of bits in a pixel Quantum (8/16/32/64) */
+#ifndef MAGICKCORE_QUANTUM_DEPTH
+#define MAGICKCORE_QUANTUM_DEPTH 16
+#endif
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#ifndef MAGICKCORE_RETSIGTYPE
+#define MAGICKCORE_RETSIGTYPE void
+#endif
+
+/* Define if you have RSVG library */
+/* #undef RSVG_DELEGATE */
+
+/* Define to the type of arg 1 for `select'. */
+#ifndef MAGICKCORE_SELECT_TYPE_ARG1
+#define MAGICKCORE_SELECT_TYPE_ARG1 int
+#endif
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#ifndef MAGICKCORE_SELECT_TYPE_ARG234
+#define MAGICKCORE_SELECT_TYPE_ARG234 (fd_set *)
+#endif
+
+/* Define to the type of arg 5 for `select'. */
+#ifndef MAGICKCORE_SELECT_TYPE_ARG5
+#define MAGICKCORE_SELECT_TYPE_ARG5 (struct timeval *)
+#endif
+
+/* Directory where architecture-independent configuration files live. */
+#ifndef MAGICKCORE_SHARE_PATH
+#define MAGICKCORE_SHARE_PATH "/usr/local/share/ImageMagick-6.7.1/"
+#endif
+
+/* Subdirectory of lib where architecture-independent configuration files
+   live. */
+#ifndef MAGICKCORE_SHARE_RELATIVE_PATH
+#define MAGICKCORE_SHARE_RELATIVE_PATH "ImageMagick-6.7.1"
+#endif
+
+/* The size of `off_t', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_OFF_T
+#define MAGICKCORE_SIZEOF_OFF_T 8
+#endif
+
+/* The size of `signed int', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_SIGNED_INT
+#define MAGICKCORE_SIZEOF_SIGNED_INT 4
+#endif
+
+/* The size of `signed long', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_SIGNED_LONG
+#define MAGICKCORE_SIZEOF_SIGNED_LONG 8
+#endif
+
+/* The size of `signed long long', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_SIGNED_LONG_LONG
+#define MAGICKCORE_SIZEOF_SIGNED_LONG_LONG 8
+#endif
+
+/* The size of `signed short', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_SIGNED_SHORT
+#define MAGICKCORE_SIZEOF_SIGNED_SHORT 2
+#endif
+
+/* The size of `size_t', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_SIZE_T
+#define MAGICKCORE_SIZEOF_SIZE_T 8
+#endif
+
+/* The size of `ssize_t', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_SSIZE_T
+#define MAGICKCORE_SIZEOF_SSIZE_T 8
+#endif
+
+/* The size of `unsigned int', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_UNSIGNED_INT
+#define MAGICKCORE_SIZEOF_UNSIGNED_INT 4
+#endif
+
+/* The size of `unsigned int*', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_UNSIGNED_INTP
+#define MAGICKCORE_SIZEOF_UNSIGNED_INTP 8
+#endif
+
+/* The size of `unsigned long', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_UNSIGNED_LONG
+#define MAGICKCORE_SIZEOF_UNSIGNED_LONG 8
+#endif
+
+/* The size of `unsigned long long', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_UNSIGNED_LONG_LONG
+#define MAGICKCORE_SIZEOF_UNSIGNED_LONG_LONG 8
+#endif
+
+/* The size of `unsigned short', as computed by sizeof. */
+#ifndef MAGICKCORE_SIZEOF_UNSIGNED_SHORT
+#define MAGICKCORE_SIZEOF_UNSIGNED_SHORT 2
+#endif
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define to 1 if you have the ANSI C header files. */
+#ifndef MAGICKCORE_STDC_HEADERS
+#define MAGICKCORE_STDC_HEADERS 1
+#endif
+
+/* Define if you have POSIX threads libraries and header files. */
+#ifndef MAGICKCORE_THREAD_SUPPORT
+#define MAGICKCORE_THREAD_SUPPORT 1
+#endif
+
+/* Define if you have TIFF library */
+#ifndef MAGICKCORE_TIFF_DELEGATE
+#define MAGICKCORE_TIFF_DELEGATE 1
+#endif
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#ifndef MAGICKCORE_TIME_WITH_SYS_TIME
+#define MAGICKCORE_TIME_WITH_SYS_TIME 1
+#endif
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Define if you have WEBP library */
+/* #undef WEBP_DELEGATE */
+
+/* Define to use the Windows GDI32 library */
+/* #undef WINGDI32_DELEGATE */
+
+/* Define if using the dmalloc debugging malloc package */
+/* #undef WITH_DMALLOC */
+
+/* Define if you have WMF library */
+/* #undef WMF_DELEGATE */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Location of X11 configure files */
+#ifndef MAGICKCORE_X11_CONFIGURE_PATH
+#define MAGICKCORE_X11_CONFIGURE_PATH ""
+#endif
+
+/* Define if you have X11 library */
+#ifndef MAGICKCORE_X11_DELEGATE
+#define MAGICKCORE_X11_DELEGATE 1
+#endif
+
+/* Define if you have XML library */
+#ifndef MAGICKCORE_XML_DELEGATE
+#define MAGICKCORE_XML_DELEGATE 1
+#endif
+
+/* Define to 1 if the X Window System is missing or not being used. */
+/* #undef X_DISPLAY_MISSING */
+
+/* Define if you have zlib compression library */
+#ifndef MAGICKCORE_ZLIB_DELEGATE
+#define MAGICKCORE_ZLIB_DELEGATE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* enable run-time bounds-checking */
+/* #undef _FORTIFY_SOURCE */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define this for the OpenCL Accelerator */
+/* #undef _OPENCL */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to 1 if type `char' is unsigned and you are not using gcc.  */
+#ifndef __CHAR_UNSIGNED__
+/* # undef __CHAR_UNSIGNED__ */
+#endif
+
+/* Define so that glibc/gnulib argp.h does not typedef error_t. */
+/* #undef __error_t_defined */
+
+/* Define to appropriate substitue if compiler does not have __func__ */
+/* #undef __func__ */
+
+/* Define to a type to use for `error_t' if it is not otherwise available. */
+/* #undef error_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the type of a signed integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int16_t */
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int64_t */
+
+/* Define to the type of a signed integer type of width exactly 8 bits if such
+   a type exists and the standard includes do not define it. */
+/* #undef int8_t */
+
+/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do
+   not define. */
+/* #undef intmax_t */
+
+/* Define to the type of a signed integer type wide enough to hold a pointer,
+   if such a type exists, and if the system does not define it. */
+/* #undef intptr_t */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef mode_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#ifndef _magickcore_restrict
+#define _magickcore_restrict __restrict
+#endif
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef ssize_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
+
+/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>
+   do not define. */
+/* #undef uintmax_t */
+
+/* Define to the type of an unsigned integer type wide enough to hold a
+   pointer, if such a type exists, and if the system does not define it. */
+/* #undef uintptr_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+/* #undef volatile */
+ 
+/* once: _MAGICKCORE_MAGICK_CONFIG_H */
+#endif
diff --git a/MagickCore/magick-type.h b/MagickCore/magick-type.h
new file mode 100644
index 0000000..a70527f
--- /dev/null
+++ b/MagickCore/magick-type.h
@@ -0,0 +1,190 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore types.
+*/
+#ifndef _MAGICKCORE_MAGICK_TYPE_H
+#define _MAGICKCORE_MAGICK_TYPE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/magick-config.h"
+
+#if !defined(MAGICKCORE_QUANTUM_DEPTH)
+#define MAGICKCORE_QUANTUM_DEPTH  16
+#endif
+
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
+#  define MagickLLConstant(c)  (MagickOffsetType) (c ## i64)
+#  define MagickULLConstant(c)  (MagickSizeType) (c ## ui64)
+#else
+#  define MagickLLConstant(c)  (MagickOffsetType) (c ## LL)
+#  define MagickULLConstant(c)  (MagickSizeType) (c ## ULL)
+#endif
+
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+#define MagickEpsilon  1.0e-6
+#define MagickHuge     1.0e6
+#define MaxColormapSize  256UL
+#define MaxMap  255UL
+
+typedef double MagickRealType;
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+typedef float Quantum;
+#define QuantumRange  255.0
+#define QuantumFormat  "%g"
+#else
+typedef unsigned char Quantum;
+#define QuantumRange  255
+#define QuantumFormat  "%u"
+#endif
+#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
+#define MagickEpsilon  1.0e-10
+#define MagickHuge     1.0e12
+#define MaxColormapSize  65536UL
+#define MaxMap  65535UL
+
+typedef double MagickRealType;
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+typedef float Quantum;
+#define QuantumRange  65535.0
+#define QuantumFormat  "%g"
+#else
+typedef unsigned short Quantum;
+#define QuantumRange  65535
+#define QuantumFormat  "%u"
+#endif
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+#define MagickEpsilon  1.0e-10
+#define MagickHuge     1.0e12
+#define MaxColormapSize  65536UL
+#define MaxMap  65535UL
+
+typedef double MagickRealType;
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+typedef float Quantum;
+#define QuantumRange  4294967295.0
+#define QuantumFormat  "%g"
+#else
+typedef unsigned int Quantum;
+#define QuantumRange  4294967295
+#define QuantumFormat  "%u"
+#endif
+#elif (MAGICKCORE_QUANTUM_DEPTH == 64) && defined(MAGICKCORE_HAVE_LONG_DOUBLE_WIDER)
+#define MagickEpsilon  1.0e-10
+#define MagickHuge     1.0e12
+#define MaxColormapSize  65536UL
+#define MaxMap  65535UL
+
+typedef long double MagickRealType;
+typedef double Quantum;
+#define QuantumRange  18446744073709551615.0
+#define QuantumFormat  "%g"
+#else
+#if !defined(_CH_)
+# error "MAGICKCORE_QUANTUM_DEPTH must be one of 8, 16, 32, or 64"
+#endif
+#endif
+#define MagickPI     3.14159265358979323846264338327950288419716939937510L
+#define QuantumScale  ((double) 1.0/(double) QuantumRange)
+
+/*
+  Typedef declarations.
+*/
+typedef unsigned int MagickStatusType;
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
+#if (MAGICKCORE_SIZEOF_UNSIGNED_LONG_LONG == 8)
+typedef long long MagickOffsetType;
+typedef unsigned long long MagickSizeType;
+#define MagickOffsetFormat  "lld"
+#define MagickSizeFormat  "llu"
+#else
+typedef ssize_t MagickOffsetType;
+typedef size_t MagickSizeType;
+#define MagickOffsetFormat  "ld"
+#define MagickSizeFormat  "lu"
+#endif
+#else
+typedef __int64 MagickOffsetType;
+typedef unsigned __int64 MagickSizeType;
+#define MagickOffsetFormat  "I64i"
+#define MagickSizeFormat  "I64u"
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER == 1200)
+typedef MagickOffsetType QuantumAny;
+#else
+typedef MagickSizeType QuantumAny;
+#endif
+
+#define MaxPixelChannels  4096
+
+#if defined(macintosh)
+#define ExceptionInfo  MagickExceptionInfo
+#endif
+
+typedef enum
+{
+  UndefinedChannel,
+  RedChannel = 0x0001,
+  GrayChannel = 0x0001,
+  CyanChannel = 0x0001,
+  GreenChannel = 0x0002,
+  MagentaChannel = 0x0002,
+  BlueChannel = 0x0004,
+  YellowChannel = 0x0004,
+  AlphaChannel = 0x0008,
+  OpacityChannel = 0x0008,
+  BlackChannel = 0x0020,
+  CompositeChannels = 0x002F,
+  AllChannels = ~0L,
+  /*
+    Special purpose channel types.
+  */
+  TrueAlphaChannel = 0x0040, /* extract actual alpha channel from opacity */
+  RGBChannels = 0x0080,      /* set alpha from  grayscale mask in RGB */
+  GrayChannels = 0x0080,
+  SyncChannels = 0x0100,     /* channels should be modified equally */
+  DefaultChannels = ((AllChannels | SyncChannels) &~ OpacityChannel)
+} ChannelType;
+
+typedef enum
+{
+  UndefinedClass,
+  DirectClass,
+  PseudoClass
+} ClassType;
+
+typedef enum
+{
+  MagickFalse = 0,
+  MagickTrue = 1
+} MagickBooleanType;
+
+typedef struct _BlobInfo BlobInfo;
+
+typedef struct _ExceptionInfo ExceptionInfo;
+
+typedef struct _Image Image;
+
+typedef struct _ImageInfo ImageInfo;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/magick.c b/MagickCore/magick.c
new file mode 100644
index 0000000..cff452b
--- /dev/null
+++ b/MagickCore/magick.c
@@ -0,0 +1,1588 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  M   M   AAA    GGGG  IIIII   CCCC  K   K                   %
+%                  MM MM  A   A  G        I    C      K  K                    %
+%                  M M M  AAAAA  G GGG    I    C      KKK                     %
+%                  M   M  A   A  G   G    I    C      K  K                    %
+%                  M   M  A   A   GGGG  IIIII   CCCC  K   K                   %
+%                                                                             %
+%                                                                             %
+%               Methods to Read or List ImageMagick Image formats             %
+%                                                                             %
+%                            Software Design                                  %
+%                            Bob Friesenhahn                                  %
+%                              John Cristy                                    %
+%                             November 1998                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/coder.h"
+#include "MagickCore/client.h"
+#include "MagickCore/coder.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/mime.h"
+#include "MagickCore/module.h"
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+# include "MagickCore/nt-feature.h"
+#endif
+#include "MagickCore/random_.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/semaphore-private.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xwindow-private.h"
+
+/*
+  Define declarations.
+*/
+#if !defined(MAGICKCORE_RETSIGTYPE)
+# define MAGICKCORE_RETSIGTYPE  void
+#endif
+#if !defined(SIG_DFL)
+# define SIG_DFL  ((SignalHandler *) 0)
+#endif
+#if !defined(SIG_ERR)
+# define SIG_ERR  ((SignalHandler *) -1)
+#endif
+#if !defined(SIGMAX)
+#define SIGMAX  64
+#endif
+
+/*
+  Typedef declarations.
+*/
+typedef MAGICKCORE_RETSIGTYPE
+  SignalHandler(int);
+
+/*
+  Global declarations.
+*/
+static SemaphoreInfo
+  *magick_semaphore = (SemaphoreInfo *) NULL;
+
+static SignalHandler
+  *signal_handlers[SIGMAX] = { (SignalHandler *) NULL };
+
+static SplayTreeInfo
+  *magick_list = (SplayTreeInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_magick = MagickFalse,
+  instantiate_magickcore = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeMagickList(ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e D e c o d e r                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageDecoder() returns the image decoder.
+%
+%  The format of the GetImageDecoder method is:
+%
+%      DecodeImageHandler *GetImageDecoder(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport DecodeImageHandler *GetImageDecoder(const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->decoder);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e E n c o d e r                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageEncoder() returns the image encoder.
+%
+%  The format of the GetImageEncoder method is:
+%
+%      EncodeImageHandler *GetImageEncoder(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport EncodeImageHandler *GetImageEncoder(const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->encoder);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e M a g i c k                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageMagick() searches for an image format that matches the specified
+%  magick string.  If one is found, MagickTrue is returned otherwise
+%  MagickFalse.
+%
+%  The format of the GetImageMagick method is:
+%
+%      MagickBooleanType GetImageMagick(const unsigned char *magick,
+%        const size_t length,char *format)
+%
+%  A description of each parameter follows:
+%
+%    o magick: the image format we are searching for.
+%
+%    o length: the length of the binary string.
+%
+%    o format: the image format as determined by the magick bytes.
+%
+*/
+MagickExport MagickBooleanType GetImageMagick(const unsigned char *magick,
+  const size_t length,char *format)
+{
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  register const MagickInfo
+    *p;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick != (const unsigned char *) NULL);
+  exception=AcquireExceptionInfo();
+  p=GetMagickInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  if (p == (const MagickInfo *) NULL)
+    return(MagickFalse);
+  status=MagickFalse;
+  LockSemaphoreInfo(magick_semaphore);
+  ResetSplayTreeIterator(magick_list);
+  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  while (p != (const MagickInfo *) NULL)
+  {
+    if ((p->magick != (IsImageFormatHandler *) NULL) &&
+        (p->magick(magick,length) != 0))
+      {
+        status=MagickTrue;
+        (void) CopyMagickString(format,p->name,MaxTextExtent);
+        break;
+      }
+    p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  }
+  UnlockSemaphoreInfo(magick_semaphore);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k A d j o i n                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickAdjoin() returns MagickTrue if the magick adjoin is MagickTrue.
+%
+%  The format of the GetMagickAdjoin method is:
+%
+%      MagickBooleanType GetMagickAdjoin(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport MagickBooleanType GetMagickAdjoin(const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->adjoin);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k B l o b S u p p o r t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickBlobSupport() returns MagickTrue if the magick supports blobs.
+%
+%  The format of the GetMagickBlobSupport method is:
+%
+%      MagickBooleanType GetMagickBlobSupport(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport MagickBooleanType GetMagickBlobSupport(
+  const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->blob_support);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k D e s c r i p t i o n                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickDescription() returns the magick description.
+%
+%  The format of the GetMagickDescription method is:
+%
+%      const char *GetMagickDescription(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport const char *GetMagickDescription(const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k E n d i a n S u p p o r t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickEndianSupport() returns the MagickTrue if the coder respects
+%  endianness other than MSBEndian.
+%
+%  The format of the GetMagickEndianSupport method is:
+%
+%      MagickBooleanType GetMagickEndianSupport(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport MagickBooleanType GetMagickEndianSupport(
+  const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->endian_support);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickInfo() returns a pointer MagickInfo structure that matches
+%  the specified name.  If name is NULL, the head of the image format list
+%  is returned.
+%
+%  The format of the GetMagickInfo method is:
+%
+%      const MagickInfo *GetMagickInfo(const char *name,Exception *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the image format we are looking for.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const MagickInfo *GetMagickInfo(const char *name,
+  ExceptionInfo *exception)
+{
+  register const MagickInfo
+    *p;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((magick_list == (SplayTreeInfo *) NULL) ||
+      (instantiate_magick == MagickFalse))
+    if (InitializeMagickList(exception) == MagickFalse)
+      return((const MagickInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    {
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+      if (LocaleCompare(name,"*") == 0)
+        (void) OpenModules(exception);
+#endif
+      LockSemaphoreInfo(magick_semaphore);
+      ResetSplayTreeIterator(magick_list);
+      p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+      UnlockSemaphoreInfo(magick_semaphore);
+      return(p);
+    }
+  /*
+    Find name in list.
+  */
+  LockSemaphoreInfo(magick_semaphore);
+  ResetSplayTreeIterator(magick_list);
+  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  while (p != (const MagickInfo *) NULL)
+  {
+    if (LocaleCompare(p->name,name) == 0)
+      break;
+    p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  }
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+  if (p == (const MagickInfo *) NULL)
+    {
+      if (*name != '\0')
+        (void) OpenModule(name,exception);
+      ResetSplayTreeIterator(magick_list);
+      p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+      while (p != (const MagickInfo *) NULL)
+      {
+        if (LocaleCompare(p->name,name) == 0)
+          break;
+        p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+      }
+    }
+#endif
+  UnlockSemaphoreInfo(magick_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k I n f o L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickInfoList() returns any image formats that match the specified
+%  pattern.
+%
+%  The format of the GetMagickInfoList function is:
+%
+%      const MagickInfo **GetMagickInfoList(const char *pattern,
+%        size_t *number_formats,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_formats:  This integer returns the number of formats in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int MagickInfoCompare(const void *x,const void *y)
+{
+  const MagickInfo
+    **p,
+    **q;
+
+  p=(const MagickInfo **) x,
+  q=(const MagickInfo **) y;
+  return(LocaleCompare((*p)->name,(*q)->name));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const MagickInfo **GetMagickInfoList(const char *pattern,
+  size_t *number_formats,ExceptionInfo *exception)
+{
+  const MagickInfo
+    **formats;
+
+  register const MagickInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate magick list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_formats != (size_t *) NULL);
+  *number_formats=0;
+  p=GetMagickInfo("*",exception);
+  if (p == (const MagickInfo *) NULL)
+    return((const MagickInfo **) NULL);
+  formats=(const MagickInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(magick_list)+1UL,sizeof(*formats));
+  if (formats == (const MagickInfo **) NULL)
+    return((const MagickInfo **) NULL);
+  /*
+    Generate magick list.
+  */
+  LockSemaphoreInfo(magick_semaphore);
+  ResetSplayTreeIterator(magick_list);
+  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  for (i=0; p != (const MagickInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      formats[i++]=p;
+    p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  }
+  UnlockSemaphoreInfo(magick_semaphore);
+  qsort((void *) formats,(size_t) i,sizeof(*formats),MagickInfoCompare);
+  formats[i]=(MagickInfo *) NULL;
+  *number_formats=(size_t) i;
+  return(formats);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickList() returns any image formats that match the specified pattern.
+%
+%  The format of the GetMagickList function is:
+%
+%      char **GetMagickList(const char *pattern,size_t *number_formats,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_formats:  This integer returns the number of formats in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int MagickCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetMagickList(const char *pattern,
+  size_t *number_formats,ExceptionInfo *exception)
+{
+  char
+    **formats;
+
+  register const MagickInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate magick list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_formats != (size_t *) NULL);
+  *number_formats=0;
+  p=GetMagickInfo("*",exception);
+  if (p == (const MagickInfo *) NULL)
+    return((char **) NULL);
+  formats=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(magick_list)+1UL,sizeof(*formats));
+  if (formats == (char **) NULL)
+    return((char **) NULL);
+  LockSemaphoreInfo(magick_semaphore);
+  ResetSplayTreeIterator(magick_list);
+  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  for (i=0; p != (const MagickInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      formats[i++]=ConstantString(p->name);
+    p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  }
+  UnlockSemaphoreInfo(magick_semaphore);
+  qsort((void *) formats,(size_t) i,sizeof(*formats),MagickCompare);
+  formats[i]=(char *) NULL;
+  *number_formats=(size_t) i;
+  return(formats);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k P r e c i s i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickPrecision() returns the maximum number of significant digits to be
+%  printed.
+%
+%  The format of the GetMagickPrecision method is:
+%
+%      int GetMagickPrecision(void)
+%
+*/
+MagickExport int GetMagickPrecision(void)
+{
+#define MagickPrecision  6
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (SetMagickPrecision(0) == 0)
+    {
+      char
+        *limit;
+
+      (void) SetMagickPrecision(MagickPrecision);
+      limit=GetEnvironmentValue("MAGICK_PRECISION");
+      if (limit == (char *) NULL)
+        limit=GetPolicyValue("precision");
+      if (limit != (char *) NULL)
+        {
+          (void) SetMagickPrecision(StringToInteger(limit));
+          limit=DestroyString(limit);
+        }
+    }
+  return(SetMagickPrecision(0));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k R a w S u p p o r t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickRawSupport() returns the MagickTrue if the coder is a raw format.
+%
+%  The format of the GetMagickRawSupport method is:
+%
+%      MagickBooleanType GetMagickRawSupport(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport MagickBooleanType GetMagickRawSupport(
+  const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->raw);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k S e e k a b l e S t r e a m                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickSeekableStream() returns MagickTrue if the magick supports a
+%  seekable stream.
+%
+%  The format of the GetMagickSeekableStream method is:
+%
+%      MagickBooleanType GetMagickSeekableStream(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport MagickBooleanType GetMagickSeekableStream(
+  const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->seekable_stream);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k T h r e a d S u p p o r t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickThreadSupport() returns MagickTrue if the magick supports threads.
+%
+%  The format of the GetMagickThreadSupport method is:
+%
+%      MagickStatusType GetMagickThreadSupport(const MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info:  The magick info.
+%
+*/
+MagickExport MagickStatusType GetMagickThreadSupport(
+  const MagickInfo *magick_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  return(magick_info->thread_support);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e M a g i c k L i s t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeMagickList() initializes the magick list.
+%
+%  The format of the InitializeMagickList() method is:
+%
+%      InitializeMagickList(Exceptioninfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void *DestroyMagickNode(void *magick_info)
+{
+  register MagickInfo
+    *p;
+
+  p=(MagickInfo *) magick_info;
+  if (p->name != (char *) NULL)
+    p->name=DestroyString(p->name);
+  if (p->description != (char *) NULL)
+    p->description=DestroyString(p->description);
+  if (p->version != (char *) NULL)
+    p->version=DestroyString(p->version);
+  if (p->note != (char *) NULL)
+    p->note=DestroyString(p->note);
+  if (p->module != (char *) NULL)
+    p->module=DestroyString(p->module);
+  return(RelinquishMagickMemory(p));
+}
+
+static MagickBooleanType InitializeMagickList(ExceptionInfo *exception)
+{
+  (void) exception;
+  if ((magick_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_magick == MagickFalse))
+    {
+      if (magick_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&magick_semaphore);
+      LockSemaphoreInfo(magick_semaphore);
+      if ((magick_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_magick == MagickFalse))
+        {
+          MagickBooleanType
+            status;
+
+          MagickInfo
+            *magick_info;
+
+          magick_list=NewSplayTree(CompareSplayTreeString,
+            (void *(*)(void *)) NULL,DestroyMagickNode);
+          if (magick_list == (SplayTreeInfo *) NULL)
+            ThrowFatalException(ResourceLimitFatalError,
+              "MemoryAllocationFailed");
+          magick_info=SetMagickInfo("ephemeral");
+          magick_info->stealth=MagickTrue;
+          status=AddValueToSplayTree(magick_list,magick_info->name,magick_info);
+          if (status == MagickFalse)
+            ThrowFatalException(ResourceLimitFatalError,
+              "MemoryAllocationFailed");
+          magick_info=SetMagickInfo("clipmask");
+          magick_info->stealth=MagickTrue;
+          status=AddValueToSplayTree(magick_list,magick_info->name,magick_info);
+          if (status == MagickFalse)
+            {
+              char
+                *message;
+
+              message=GetExceptionMessage(errno);
+              ThrowFatalException(ResourceLimitFatalError,
+                "MemoryAllocationFailed");
+              message=DestroyString(message);
+            }
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+          (void) GetModuleInfo((char *) NULL,exception);
+#endif
+#if !defined(MAGICKCORE_BUILD_MODULES)
+          RegisterStaticModules();
+#endif
+          instantiate_magick=MagickTrue;
+        }
+      UnlockSemaphoreInfo(magick_semaphore);
+    }
+  return(magick_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s M a g i c k C o n f l i c t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMagickConflict() returns MagickTrue if the image format conflicts with a
+%  logical drive (.e.g. X:).
+%
+%  The format of the IsMagickConflict method is:
+%
+%      MagickBooleanType IsMagickConflict(const char *magick)
+%
+%  A description of each parameter follows:
+%
+%    o magick: Specifies the image format.
+%
+*/
+MagickExport MagickBooleanType IsMagickConflict(const char *magick)
+{
+  assert(magick != (char *) NULL);
+#if defined(macintosh)
+  return(MACIsMagickConflict(magick));
+#elif defined(vms)
+  return(VMSIsMagickConflict(magick));
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  return(NTIsMagickConflict(magick));
+#else
+  return(MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  L i s t M a g i c k I n f o                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListMagickInfo() lists the image formats to a file.
+%
+%  The format of the ListMagickInfo method is:
+%
+%      MagickBooleanType ListMagickInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file: A file handle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListMagickInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const MagickInfo
+    **magick_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_formats;
+
+  ssize_t
+    j;
+
+  if (file == (FILE *) NULL)
+    file=stdout;
+  magick_info=GetMagickInfoList("*",&number_formats,exception);
+  if (magick_info == (const MagickInfo **) NULL)
+    return(MagickFalse);
+  ClearMagickException(exception);
+#if !defined(MAGICKCORE_MODULES_SUPPORT)
+  (void) FormatLocaleFile(file,"   Format  Mode  Description\n");
+#else
+  (void) FormatLocaleFile(file,"   Format  Module    Mode  Description\n");
+#endif
+  (void) FormatLocaleFile(file,
+    "--------------------------------------------------------"
+    "-----------------------\n");
+  for (i=0; i < (ssize_t) number_formats; i++)
+  {
+    if (magick_info[i]->stealth != MagickFalse)
+      continue;
+    (void) FormatLocaleFile(file,"%9s%c ",
+      magick_info[i]->name != (char *) NULL ? magick_info[i]->name : "",
+      magick_info[i]->blob_support != MagickFalse ? '*' : ' ');
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+    {
+      char
+        module[MaxTextExtent];
+
+      *module='\0';
+      if (magick_info[i]->module != (char *) NULL)
+        (void) CopyMagickString(module,magick_info[i]->module,MaxTextExtent);
+      (void) ConcatenateMagickString(module,"          ",MaxTextExtent);
+      module[9]='\0';
+      (void) FormatLocaleFile(file,"%9s ",module);
+    }
+#endif
+    (void) FormatLocaleFile(file,"%c%c%c ",magick_info[i]->decoder ? 'r' : '-',
+      magick_info[i]->encoder ? 'w' : '-',magick_info[i]->encoder != NULL &&
+      magick_info[i]->adjoin != MagickFalse ? '+' : '-');
+    if (magick_info[i]->description != (char *) NULL)
+      (void) FormatLocaleFile(file,"  %s",magick_info[i]->description);
+    if (magick_info[i]->version != (char *) NULL)
+      (void) FormatLocaleFile(file," (%s)",magick_info[i]->version);
+    (void) FormatLocaleFile(file,"\n");
+    if (magick_info[i]->note != (char *) NULL)
+      {
+        char
+          **text;
+
+        text=StringToList(magick_info[i]->note);
+        if (text != (char **) NULL)
+          {
+            for (j=0; text[j] != (char *) NULL; j++)
+            {
+              (void) FormatLocaleFile(file,"           %s\n",text[j]);
+              text[j]=DestroyString(text[j]);
+            }
+            text=(char **) RelinquishMagickMemory(text);
+          }
+      }
+  }
+  (void) FormatLocaleFile(file,"\n* native blob support\n");
+  (void) FormatLocaleFile(file,"r read support\n");
+  (void) FormatLocaleFile(file,"w write support\n");
+  (void) FormatLocaleFile(file,"+ support for multiple images\n");
+  (void) fflush(file);
+  magick_info=(const MagickInfo **) RelinquishMagickMemory((void *)
+    magick_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I s M a g i c k I n s t a n t i a t e d                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMagickInstantiated() returns MagickTrue if the ImageMagick environment
+%  is currently instantiated:  MagickCoreGenesis() has been called but
+%  MagickDestroy() has not.
+%
+%  The format of the IsMagickInstantiated method is:
+%
+%      MagickBooleanType IsMagickInstantiated(void)
+%
+*/
+MagickExport MagickBooleanType IsMagickInstantiated(void)
+{
+  return(instantiate_magick);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M a g i c k C o m p o n e n t G e n e s i s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickComponentGenesis() instantiates the magick component.
+%
+%  The format of the MagickComponentGenesis method is:
+%
+%      MagickBooleanType MagickComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType MagickComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&magick_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M a g i c k C o m p o n e n t T e r m i n u s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickComponentTerminus() destroys the magick component.
+%
+%  The format of the MagickComponentTerminus method is:
+%
+%      void MagickComponentTerminus(void)
+%
+*/
+MagickExport void MagickComponentTerminus(void)
+{
+  if (magick_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&magick_semaphore);
+  LockSemaphoreInfo(magick_semaphore);
+  if (magick_list != (SplayTreeInfo *) NULL)
+    magick_list=DestroySplayTree(magick_list);
+  instantiate_magick=MagickFalse;
+  UnlockSemaphoreInfo(magick_semaphore);
+  DestroySemaphoreInfo(&magick_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k C o r e G e n e s i s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickCoreGenesis() initializes the MagickCore environment.
+%
+%  The format of the MagickCoreGenesis function is:
+%
+%      MagickCoreGenesis(const char *path,
+%        const MagickBooleanType establish_signal_handlers)
+%
+%  A description of each parameter follows:
+%
+%    o path: the execution path of the current ImageMagick client.
+%
+%    o establish_signal_handlers: set to MagickTrue to use MagickCore's own
+%      signal handlers for common signals.
+%
+*/
+
+static SignalHandler *SetMagickSignalHandler(int signal_number,
+  SignalHandler *handler)
+{
+#if defined(MAGICKCORE_HAVE_SIGACTION) && defined(MAGICKCORE_HAVE_SIGEMPTYSET)
+  int
+    status;
+
+  sigset_t
+    mask;
+
+  struct sigaction
+    action,
+    previous_action;
+
+  sigemptyset(&mask);
+  sigaddset(&mask,signal_number);
+  sigprocmask(SIG_BLOCK,&mask,NULL);
+  action.sa_mask=mask;
+  action.sa_handler=handler;
+  action.sa_flags=0;
+#if defined(SA_INTERRUPT)
+  action.sa_flags|=SA_INTERRUPT;
+#endif
+  status=sigaction(signal_number,&action,&previous_action);
+  if (status < 0)
+    return(SIG_ERR);
+  sigprocmask(SIG_UNBLOCK,&mask,NULL);
+  return(previous_action.sa_handler);
+#else
+  return(signal(signal_number,handler));
+#endif
+}
+
+static void MagickSignalHandler(int signal_number)
+{
+#if !defined(MAGICKCORE_HAVE_SIGACTION)
+  (void) signal(signal_number,SIG_IGN);
+#endif
+  AsynchronousResourceComponentTerminus();
+  instantiate_magick=MagickFalse;
+  (void) SetMagickSignalHandler(signal_number,signal_handlers[signal_number]);
+#if defined(MAGICKCORE_HAVE_RAISE)
+  if (signal_handlers[signal_number] != MagickSignalHandler)
+    raise(signal_number);
+#endif
+#if defined(SIGQUIT)
+  if (signal_number == SIGQUIT)
+    abort();
+#endif
+#if defined(SIGABRT)
+  if (signal_number == SIGABRT)
+    abort();
+#endif
+#if defined(SIGFPE)
+  if (signal_number == SIGFPE)
+    abort();
+#endif
+#if defined(SIGXCPU)
+  if (signal_number == SIGXCPU)
+    abort();
+#endif
+#if defined(SIGXFSZ)
+  if (signal_number == SIGXFSZ)
+    abort();
+#endif
+#if defined(SIGSEGV)
+  if (signal_number == SIGSEGV)
+    abort();
+#endif
+#if !defined(MAGICKCORE_HAVE__EXIT)
+  exit(signal_number);
+#else
+#if defined(SIGHUP)
+  if (signal_number == SIGHUP)
+    exit(signal_number);
+#endif
+#if defined(SIGINT) && !defined(MAGICKCORE_WINDOWS_SUPPORT)
+  if (signal_number == SIGINT)
+    exit(signal_number);
+#endif
+#if defined(SIGTERM)
+  if (signal_number == SIGTERM)
+    exit(signal_number);
+#endif
+  _exit(signal_number);  /* do not invoke registered atexit() methods */
+#endif
+}
+
+static SignalHandler *RegisterMagickSignalHandler(int signal_number)
+{
+  SignalHandler
+    *handler;
+
+  handler=SetMagickSignalHandler(signal_number,MagickSignalHandler);
+  if (handler == SIG_ERR)
+    return(handler);
+  if (handler != SIG_DFL)
+    handler=SetMagickSignalHandler(signal_number,handler);
+  else
+    (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+      "Register handler for signal: %d",signal_number);
+  return(handler);
+}
+
+MagickExport void MagickCoreGenesis(const char *path,
+  const MagickBooleanType establish_signal_handlers)
+{
+  char
+    *events,
+    execution_path[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  /*
+    Initialize the Magick environment.
+  */
+  LockMagickMutex();
+  if (instantiate_magickcore != MagickFalse)
+    {
+      UnlockMagickMutex();
+      return;
+    }
+  (void) SemaphoreComponentGenesis();
+  (void) LogComponentGenesis();
+  (void) LocaleComponentGenesis();
+  (void) RandomComponentGenesis();
+  events=GetEnvironmentValue("MAGICK_DEBUG");
+  if (events != (char *) NULL)
+    {
+      (void) SetLogEventMask(events);
+      events=DestroyString(events);
+    }
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+#if defined(_DEBUG) && !defined(__BORLANDC__) && !defined(__MINGW32__)
+  if (IsEventLogging() != MagickFalse)
+    {
+      int
+        debug;
+
+      debug=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+      debug|=_CRTDBG_CHECK_ALWAYS_DF |_CRTDBG_DELAY_FREE_MEM_DF |
+        _CRTDBG_LEAK_CHECK_DF;
+      if (0)
+        {
+          debug=_CrtSetDbgFlag(debug);
+          _ASSERTE(_CrtCheckMemory());
+        }
+    }
+#endif
+#endif
+  /*
+    Set client name and execution path.
+  */
+  (void) GetExecutionPath(execution_path,MaxTextExtent);
+  if ((path != (const char *) NULL) && (*path != '\0'))
+    (void) CopyMagickString(execution_path,path,MaxTextExtent);
+  GetPathComponent(execution_path,TailPath,filename);
+  (void) SetClientName(filename);
+  GetPathComponent(execution_path,HeadPath,execution_path);
+  (void) SetClientPath(execution_path);
+  if (establish_signal_handlers != MagickFalse)
+    {
+      /*
+        Set signal handlers.
+      */
+#if defined(SIGABRT)
+      if (signal_handlers[SIGABRT] == (SignalHandler *) NULL)
+        signal_handlers[SIGABRT]=RegisterMagickSignalHandler(SIGABRT);
+#endif
+#if defined(SIGSEGV)
+      if (signal_handlers[SIGSEGV] == (SignalHandler *) NULL)
+        signal_handlers[SIGSEGV]=RegisterMagickSignalHandler(SIGSEGV);
+#endif
+#if defined(SIGFPE)
+      if (signal_handlers[SIGFPE] == (SignalHandler *) NULL)
+        signal_handlers[SIGFPE]=RegisterMagickSignalHandler(SIGFPE);
+#endif
+#if defined(SIGHUP)
+      if (signal_handlers[SIGHUP] == (SignalHandler *) NULL)
+        signal_handlers[SIGHUP]=RegisterMagickSignalHandler(SIGHUP);
+#endif
+#if defined(SIGINT) && !defined(MAGICKCORE_WINDOWS_SUPPORT)
+      if (signal_handlers[SIGINT] == (SignalHandler *) NULL)
+        signal_handlers[SIGINT]=RegisterMagickSignalHandler(SIGINT);
+#endif
+#if defined(SIGQUIT)
+      if (signal_handlers[SIGQUIT] == (SignalHandler *) NULL)
+        signal_handlers[SIGQUIT]=RegisterMagickSignalHandler(SIGQUIT);
+#endif
+#if defined(SIGTERM)
+      if (signal_handlers[SIGTERM] == (SignalHandler *) NULL)
+        signal_handlers[SIGTERM]=RegisterMagickSignalHandler(SIGTERM);
+#endif
+#if defined(SIGXCPU)
+      if (signal_handlers[SIGXCPU] == (SignalHandler *) NULL)
+        signal_handlers[SIGXCPU]=RegisterMagickSignalHandler(SIGXCPU);
+#endif
+#if defined(SIGXFSZ)
+      if (signal_handlers[SIGXFSZ] == (SignalHandler *) NULL)
+        signal_handlers[SIGXFSZ]=RegisterMagickSignalHandler(SIGXFSZ);
+#endif
+    }
+  /*
+    Instantiate magick resources.
+  */
+  (void) ConfigureComponentGenesis();
+  (void) PolicyComponentGenesis();
+  (void) CacheComponentGenesis();
+  (void) RegistryComponentGenesis();
+  (void) ResourceComponentGenesis();
+  (void) CoderComponentGenesis();
+  (void) MagickComponentGenesis();
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+  (void) ModuleComponentGenesis();
+#endif
+  (void) DelegateComponentGenesis();
+  (void) MagicComponentGenesis();
+  (void) ColorComponentGenesis();
+  (void) TypeComponentGenesis();
+  (void) MimeComponentGenesis();
+  (void) ConstituteComponentGenesis();
+  (void) AnnotateComponentGenesis();
+#if defined(MAGICKCORE_X11_DELEGATE)
+  (void) XComponentGenesis();
+#endif
+  instantiate_magickcore=MagickTrue;
+  UnlockMagickMutex();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k C o r e T e r m i n u s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickCoreTerminus() destroys the MagickCore environment.
+%
+%  The format of the MagickCoreTerminus function is:
+%
+%      MagickCoreTerminus(void)
+%
+*/
+MagickExport void MagickCoreTerminus(void)
+{
+  LockMagickMutex();
+  if (instantiate_magickcore == MagickFalse)
+    {
+      UnlockMagickMutex();
+      return;
+    }
+#if defined(MAGICKCORE_X11_DELEGATE)
+  XComponentTerminus();
+#endif
+  AnnotateComponentTerminus();
+  ConstituteComponentTerminus();
+  MimeComponentTerminus();
+  TypeComponentTerminus();
+  ColorComponentTerminus();
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  NTGhostscriptUnLoadDLL();
+#endif
+  MagicComponentTerminus();
+  DelegateComponentTerminus();
+  MagickComponentTerminus();
+#if !defined(MAGICKCORE_BUILD_MODULES)
+  UnregisterStaticModules();
+#endif
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+  ModuleComponentTerminus();
+#endif
+  CoderComponentTerminus();
+  ResourceComponentTerminus();
+  RegistryComponentTerminus();
+  CacheComponentTerminus();
+  PolicyComponentTerminus();
+  ConfigureComponentTerminus();
+  RandomComponentTerminus();
+  LocaleComponentTerminus();
+  LogComponentTerminus();
+  SemaphoreComponentTerminus();
+  instantiate_magickcore=MagickFalse;
+  UnlockMagickMutex();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e g i s t e r M a g i c k I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RegisterMagickInfo() adds attributes for a particular image format to the
+%  list of supported formats.  The attributes include the image format name,
+%  a method to read and/or write the format, whether the format supports the
+%  saving of more than one frame to the same file or blob, whether the format
+%  supports native in-memory I/O, and a brief description of the format.
+%
+%  The format of the RegisterMagickInfo method is:
+%
+%      MagickInfo *RegisterMagickInfo(MagickInfo *magick_info)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info: the magick info.
+%
+*/
+MagickExport MagickInfo *RegisterMagickInfo(MagickInfo *magick_info)
+{
+  MagickBooleanType
+    status;
+
+  /*
+    Delete any existing name.
+  */
+  assert(magick_info != (MagickInfo *) NULL);
+  assert(magick_info->signature == MagickSignature);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",magick_info->name);
+  if (magick_list == (SplayTreeInfo *) NULL)
+    return((MagickInfo *) NULL);
+  status=AddValueToSplayTree(magick_list,magick_info->name,magick_info);
+  if (status == MagickFalse)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  return(magick_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t M a g i c k I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetMagickInfo() allocates a MagickInfo structure and initializes the members
+%  to default values.
+%
+%  The format of the SetMagickInfo method is:
+%
+%      MagickInfo *SetMagickInfo(const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o magick_info: Method SetMagickInfo returns the allocated and initialized
+%      MagickInfo structure.
+%
+%    o name: a character string that represents the image format associated
+%      with the MagickInfo structure.
+%
+*/
+MagickExport MagickInfo *SetMagickInfo(const char *name)
+{
+  MagickInfo
+    *magick_info;
+
+  assert(name != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
+  magick_info=(MagickInfo *) AcquireMagickMemory(sizeof(*magick_info));
+  if (magick_info == (MagickInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(magick_info,0,sizeof(*magick_info));
+  magick_info->name=ConstantString(name);
+  magick_info->adjoin=MagickTrue;
+  magick_info->blob_support=MagickTrue;
+  magick_info->thread_support=(MagickStatusType) (DecoderThreadSupport |
+    EncoderThreadSupport);
+  magick_info->signature=MagickSignature;
+  return(magick_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t M a g i c k P r e c i s i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetMagickPrecision() sets the maximum number of significant digits to be
+%  printed and returns it.
+%
+%  The format of the SetMagickPrecision method is:
+%
+%      int SetMagickPrecision(const int precision)
+%
+%  A description of each parameter follows:
+%
+%    o precision: set the maximum number of significant digits to be printed.
+%
+*/
+MagickExport int SetMagickPrecision(const int precision)
+{
+  static int
+    magick_precision = 0;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (precision != 0)
+    magick_precision=precision;
+  return(magick_precision);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   U n r e g i s t e r M a g i c k I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnregisterMagickInfo() removes a name from the magick info list.  It returns
+%  MagickFalse if the name does not exist in the list otherwise MagickTrue.
+%
+%  The format of the UnregisterMagickInfo method is:
+%
+%      MagickBooleanType UnregisterMagickInfo(const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o name: a character string that represents the image format we are
+%      looking for.
+%
+*/
+MagickExport MagickBooleanType UnregisterMagickInfo(const char *name)
+{
+  register const MagickInfo
+    *p;
+
+  MagickBooleanType
+    status;
+
+  assert(name != (const char *) NULL);
+  if (magick_list == (SplayTreeInfo *) NULL)
+    return(MagickFalse);
+  if (GetNumberOfNodesInSplayTree(magick_list) == 0)
+    return(MagickFalse);
+  LockSemaphoreInfo(magick_semaphore);
+  ResetSplayTreeIterator(magick_list);
+  p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  while (p != (const MagickInfo *) NULL)
+  {
+    if (LocaleCompare(p->name,name) == 0)
+      break;
+    p=(const MagickInfo *) GetNextValueInSplayTree(magick_list);
+  }
+  status=DeleteNodeByValueFromSplayTree(magick_list,p);
+  UnlockSemaphoreInfo(magick_semaphore);
+  return(status);
+}
diff --git a/MagickCore/magick.h b/MagickCore/magick.h
new file mode 100644
index 0000000..f5aa868
--- /dev/null
+++ b/MagickCore/magick.h
@@ -0,0 +1,139 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore magick methods.
+*/
+#ifndef _MAGICKCORE_MAGICK_H
+#define _MAGICKCORE_MAGICK_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedFormatType,
+  ImplicitFormatType,
+  ExplicitFormatType
+} MagickFormatType;
+
+typedef enum
+{
+  NoThreadSupport = 0x0000,
+  DecoderThreadSupport = 0x0001,
+  EncoderThreadSupport = 0x0002
+} MagickThreadSupport;
+
+typedef Image
+  *DecodeImageHandler(const ImageInfo *,ExceptionInfo *);
+
+typedef MagickBooleanType
+  EncodeImageHandler(const ImageInfo *,Image *);
+
+typedef MagickBooleanType
+  IsImageFormatHandler(const unsigned char *,const size_t);
+
+typedef struct _MagickInfo
+{
+  char
+    *name,
+    *description,
+    *version,
+    *note,
+    *module;
+
+  ImageInfo
+    *image_info;
+
+  DecodeImageHandler
+    *decoder;
+
+  EncodeImageHandler
+    *encoder;
+
+  IsImageFormatHandler
+    *magick;
+
+  void
+    *client_data;
+
+  MagickBooleanType
+    adjoin,
+    raw,
+    endian_support,
+    blob_support,
+    seekable_stream;
+
+  MagickFormatType
+    format_type;
+
+  MagickStatusType
+    thread_support;
+
+  MagickBooleanType
+    stealth;
+
+  size_t
+    signature;
+} MagickInfo;
+
+extern MagickExport char
+  **GetMagickList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const char
+  *GetMagickDescription(const MagickInfo *);
+
+extern MagickExport DecodeImageHandler
+  *GetImageDecoder(const MagickInfo *);
+
+extern MagickExport EncodeImageHandler
+  *GetImageEncoder(const MagickInfo *);
+
+extern MagickExport int
+  GetMagickPrecision(void),
+  SetMagickPrecision(const int);
+
+extern MagickExport MagickBooleanType
+  GetImageMagick(const unsigned char *,const size_t,char *),
+  GetMagickAdjoin(const MagickInfo *),
+  GetMagickBlobSupport(const MagickInfo *),
+  GetMagickEndianSupport(const MagickInfo *),
+  GetMagickRawSupport(const MagickInfo *),
+  GetMagickSeekableStream(const MagickInfo *),
+  IsMagickInstantiated(void),
+  MagickComponentGenesis(void),
+  UnregisterMagickInfo(const char *);
+
+extern const MagickExport MagickInfo
+  *GetMagickInfo(const char *,ExceptionInfo *),
+  **GetMagickInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport MagickInfo
+  *RegisterMagickInfo(MagickInfo *),
+  *SetMagickInfo(const char *);
+
+extern MagickExport MagickStatusType
+  GetMagickThreadSupport(const MagickInfo *);
+
+extern MagickExport void
+  MagickComponentTerminus(void),
+  MagickCoreGenesis(const char *,const MagickBooleanType),
+  MagickCoreTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/matrix.c b/MagickCore/matrix.c
new file mode 100644
index 0000000..db6d69c
--- /dev/null
+++ b/MagickCore/matrix.c
@@ -0,0 +1,415 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  M   M   AAA   TTTTT  RRRR   IIIII  X   X                   %
+%                  MM MM  A   A    T    R   R    I     X X                    %
+%                  M M M  AAAAA    T    RRRR     I      X                     %
+%                  M   M  A   A    T    R R      I     X X                    %
+%                  M   M  A   A    T    R  R   IIIII  X   X                   %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Matrix Methods                           %
+%                                                                             %
+%                            Software Design                                  %
+%                              John Cristy                                    %
+%                              August 2007                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/matrix.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/utility.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e M a g i c k M a t r i x                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireMagickMatrix() allocates and returns a matrix in the form of an
+%  array of pointers to an array of doubles, with all values pre-set to zero.
+%
+%  This used to generate the two dimensional matrix, and vectors required
+%  for the GaussJordanElimination() method below, solving some system of
+%  simultanious equations.
+%
+%  The format of the AcquireMagickMatrix method is:
+%
+%      double **AcquireMagickMatrix(const size_t number_rows,
+%        const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o number_rows: the number pointers for the array of pointers
+%      (first dimension).
+%
+%    o size: the size of the array of doubles each pointer points to
+%      (second dimension).
+%
+*/
+MagickExport double **AcquireMagickMatrix(const size_t number_rows,
+  const size_t size)
+{
+  double
+    **matrix;
+
+  register ssize_t
+    i,
+    j;
+
+  matrix=(double **) AcquireQuantumMemory(number_rows,sizeof(*matrix));
+  if (matrix == (double **) NULL)
+    return((double **)NULL);
+  for (i=0; i < (ssize_t) number_rows; i++)
+  {
+    matrix[i]=(double *) AcquireQuantumMemory(size,sizeof(*matrix[i]));
+    if (matrix[i] == (double *) NULL)
+    {
+      for (j=0; j < i; j++)
+        matrix[j]=(double *) RelinquishMagickMemory(matrix[j]);
+      matrix=(double **) RelinquishMagickMemory(matrix);
+      return((double **) NULL);
+    }
+    for (j=0; j < (ssize_t) size; j++)
+      matrix[i][j]=0.0;
+  }
+  return(matrix);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G a u s s J o r d a n E l i m i n a t i o n                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GaussJordanElimination() returns a matrix in reduced row echelon form,
+%  while simultaneously reducing and thus solving the augumented results
+%  matrix.
+%
+%  See also  http://en.wikipedia.org/wiki/Gauss-Jordan_elimination
+%
+%  The format of the GaussJordanElimination method is:
+%
+%      MagickBooleanType GaussJordanElimination(double **matrix,double **vectors,
+%        const size_t rank,const size_t number_vectors)
+%
+%  A description of each parameter follows:
+%
+%    o matrix: the matrix to be reduced, as an 'array of row pointers'.
+%
+%    o vectors: the additional matrix argumenting the matrix for row reduction.
+%             Producing an 'array of column vectors'.
+%
+%    o rank:  The size of the matrix (both rows and columns).
+%             Also represents the number terms that need to be solved.
+%
+%    o number_vectors: Number of vectors columns, argumenting the above matrix.
+%             Usally 1, but can be more for more complex equation solving.
+%
+%  Note that the 'matrix' is given as a 'array of row pointers' of rank size.
+%  That is values can be assigned as   matrix[row][column]   where 'row' is
+%  typically the equation, and 'column' is the term of the equation.
+%  That is the matrix is in the form of a 'row first array'.
+%
+%  However 'vectors' is a 'array of column pointers' which can have any number
+%  of columns, with each column array the same 'rank' size as 'matrix'.
+%
+%  This allows for simpler handling of the results, especially is only one
+%  column 'vector' is all that is required to produce the desired solution.
+%
+%  For example, the 'vectors' can consist of a pointer to a simple array of
+%  doubles.  when only one set of simultanious equations is to be solved from
+%  the given set of coefficient weighted terms.
+%
+%     double **matrix = AcquireMagickMatrix(8UL,8UL);
+%     double coefficents[8];
+%     ...
+%     GaussJordanElimination(matrix, &coefficents, 8UL, 1UL);
+%
+%  However by specifing more 'columns' (as an 'array of vector columns',
+%  you can use this function to solve a set of 'separable' equations.
+%
+%  For example a distortion function where    u = U(x,y)   v = V(x,y)
+%  And the functions U() and V() have separate coefficents, but are being
+%  generated from a common x,y->u,v  data set.
+%
+%  Another example is generation of a color gradient from a set of colors
+%  at specific coordients, such as a list    x,y -> r,g,b,a
+%  (Reference to be added - Anthony)
+%
+%  You can also use the 'vectors' to generate an inverse of the given 'matrix'
+%  though as a 'column first array' rather than a 'row first array'. For
+%  details see    http://en.wikipedia.org/wiki/Gauss-Jordan_elimination
+%
+*/
+MagickExport MagickBooleanType GaussJordanElimination(double **matrix,
+  double **vectors,const size_t rank,const size_t number_vectors)
+{
+#define GaussJordanSwap(x,y) \
+{ \
+  if ((x) != (y)) \
+    { \
+      (x)+=(y); \
+      (y)=(x)-(y); \
+      (x)=(x)-(y); \
+    } \
+}
+
+  double
+    max,
+    scale;
+
+  register ssize_t
+    i,
+    j,
+    k;
+
+  ssize_t
+    column,
+    *columns,
+    *pivots,
+    row,
+    *rows;
+
+  columns=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*columns));
+  rows=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*rows));
+  pivots=(ssize_t *) AcquireQuantumMemory(rank,sizeof(*pivots));
+  if ((rows == (ssize_t *) NULL) || (columns == (ssize_t *) NULL) ||
+      (pivots == (ssize_t *) NULL))
+    {
+      if (pivots != (ssize_t *) NULL)
+        pivots=(ssize_t *) RelinquishMagickMemory(pivots);
+      if (columns != (ssize_t *) NULL)
+        columns=(ssize_t *) RelinquishMagickMemory(columns);
+      if (rows != (ssize_t *) NULL)
+        rows=(ssize_t *) RelinquishMagickMemory(rows);
+      return(MagickFalse);
+    }
+  (void) ResetMagickMemory(columns,0,rank*sizeof(*columns));
+  (void) ResetMagickMemory(rows,0,rank*sizeof(*rows));
+  (void) ResetMagickMemory(pivots,0,rank*sizeof(*pivots));
+  column=0;
+  row=0;
+  for (i=0; i < (ssize_t) rank; i++)
+  {
+    max=0.0;
+    for (j=0; j < (ssize_t) rank; j++)
+      if (pivots[j] != 1)
+        {
+          for (k=0; k < (ssize_t) rank; k++)
+            if (pivots[k] != 0)
+              {
+                if (pivots[k] > 1)
+                  return(MagickFalse);
+              }
+            else
+              if (fabs(matrix[j][k]) >= max)
+                {
+                  max=fabs(matrix[j][k]);
+                  row=j;
+                  column=k;
+                }
+        }
+    pivots[column]++;
+    if (row != column)
+      {
+        for (k=0; k < (ssize_t) rank; k++)
+          GaussJordanSwap(matrix[row][k],matrix[column][k]);
+        for (k=0; k < (ssize_t) number_vectors; k++)
+          GaussJordanSwap(vectors[k][row],vectors[k][column]);
+      }
+    rows[i]=row;
+    columns[i]=column;
+    if (matrix[column][column] == 0.0)
+      return(MagickFalse);  /* sigularity */
+    scale=1.0/matrix[column][column];
+    matrix[column][column]=1.0;
+    for (j=0; j < (ssize_t) rank; j++)
+      matrix[column][j]*=scale;
+    for (j=0; j < (ssize_t) number_vectors; j++)
+      vectors[j][column]*=scale;
+    for (j=0; j < (ssize_t) rank; j++)
+      if (j != column)
+        {
+          scale=matrix[j][column];
+          matrix[j][column]=0.0;
+          for (k=0; k < (ssize_t) rank; k++)
+            matrix[j][k]-=scale*matrix[column][k];
+          for (k=0; k < (ssize_t) number_vectors; k++)
+            vectors[k][j]-=scale*vectors[k][column];
+        }
+  }
+  for (j=(ssize_t) rank-1; j >= 0; j--)
+    if (columns[j] != rows[j])
+      for (i=0; i < (ssize_t) rank; i++)
+        GaussJordanSwap(matrix[i][rows[j]],matrix[i][columns[j]]);
+  pivots=(ssize_t *) RelinquishMagickMemory(pivots);
+  rows=(ssize_t *) RelinquishMagickMemory(rows);
+  columns=(ssize_t *) RelinquishMagickMemory(columns);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L e a s t S q u a r e s A d d T e r m s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LeastSquaresAddTerms() adds one set of terms and associate results to the
+%  given matrix and vectors for solving using least-squares function fitting.
+%
+%  The format of the AcquireMagickMatrix method is:
+%
+%      void LeastSquaresAddTerms(double **matrix,double **vectors,
+%        const double *terms,const double *results,const size_t rank,
+%        const size_t number_vectors);
+%
+%  A description of each parameter follows:
+%
+%    o matrix: the square matrix to add given terms/results to.
+%
+%    o vectors: the result vectors to add terms/results to.
+%
+%    o terms: the pre-calculated terms (without the unknown coefficent
+%             weights) that forms the equation being added.
+%
+%    o results: the result(s) that should be generated from the given terms
+%               weighted by the yet-to-be-solved coefficents.
+%
+%    o rank: the rank or size of the dimentions of the square matrix.
+%            Also the length of vectors, and number of terms being added.
+%
+%    o number_vectors: Number of result vectors, and number or results being
+%      added.  Also represents the number of separable systems of equations
+%      that is being solved.
+%
+%  Example of use...
+%
+%     2 dimensional Affine Equations (which are separable)
+%         c0*x + c2*y + c4*1 => u
+%         c1*x + c3*y + c5*1 => v
+%
+%     double **matrix = AcquireMagickMatrix(3UL,3UL);
+%     double **vectors = AcquireMagickMatrix(2UL,3UL);
+%     double terms[3], results[2];
+%     ...
+%     for each given x,y -> u,v
+%        terms[0] = x;
+%        terms[1] = y;
+%        terms[2] = 1;
+%        results[0] = u;
+%        results[1] = v;
+%        LeastSquaresAddTerms(matrix,vectors,terms,results,3UL,2UL);
+%     ...
+%     if ( GaussJordanElimination(matrix,vectors,3UL,2UL) ) {
+%       c0 = vectors[0][0];
+%       c2 = vectors[0][1];
+%       c4 = vectors[0][2];
+%       c1 = vectors[1][0];
+%       c3 = vectors[1][1];
+%       c5 = vectors[1][2];
+%     }
+%     else
+%       printf("Matrix unsolvable\n);
+%     RelinquishMagickMatrix(matrix,3UL);
+%     RelinquishMagickMatrix(vectors,2UL);
+%
+*/
+MagickExport void LeastSquaresAddTerms(double **matrix,double **vectors,
+  const double *terms,const double *results,const size_t rank,
+  const size_t number_vectors)
+{
+  register ssize_t
+    i,
+    j;
+
+  for (j=0; j < (ssize_t) rank; j++)
+  {
+    for (i=0; i < (ssize_t) rank; i++)
+      matrix[i][j]+=terms[i]*terms[j];
+    for (i=0; i < (ssize_t) number_vectors; i++)
+      vectors[i][j]+=results[i]*terms[j];
+  }
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e l i n q u i s h M a g i c k M a t r i x                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishMagickMatrix() frees the previously acquired matrix (array of
+%  pointers to arrays of doubles).
+%
+%  The format of the RelinquishMagickMatrix method is:
+%
+%      double **RelinquishMagickMatrix(double **matrix,
+%        const size_t number_rows)
+%
+%  A description of each parameter follows:
+%
+%    o matrix: the matrix to relinquish
+%
+%    o number_rows: the first dimension of the acquired matrix (number of
+%      pointers)
+%
+*/
+MagickExport double **RelinquishMagickMatrix(double **matrix,
+  const size_t number_rows)
+{
+  register ssize_t
+    i;
+
+  if (matrix == (double **) NULL )
+    return(matrix);
+  for (i=0; i < (ssize_t) number_rows; i++)
+     matrix[i]=(double *) RelinquishMagickMemory(matrix[i]);
+  matrix=(double **) RelinquishMagickMemory(matrix);
+  return(matrix);
+}
+
diff --git a/MagickCore/matrix.h b/MagickCore/matrix.h
new file mode 100644
index 0000000..1ec1df7
--- /dev/null
+++ b/MagickCore/matrix.h
@@ -0,0 +1,40 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore graphic resample methods.
+*/
+#ifndef _MAGICKCORE_MATRIX_H
+#define _MAGICKCORE_MATRIX_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport double
+  **AcquireMagickMatrix(const size_t,const size_t),
+  **RelinquishMagickMatrix(double **,const size_t);
+
+extern MagickExport MagickBooleanType
+  GaussJordanElimination(double **,double **,const size_t,const size_t);
+
+extern MagickExport void
+  LeastSquaresAddTerms(double **,double **,const double *,const double *,
+    const size_t, const size_t);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/memory.c b/MagickCore/memory.c
new file mode 100644
index 0000000..9762682
--- /dev/null
+++ b/MagickCore/memory.c
@@ -0,0 +1,993 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                    M   M  EEEEE  M   M   OOO   RRRR   Y   Y                 %
+%                    MM MM  E      MM MM  O   O  R   R   Y Y                  %
+%                    M M M  EEE    M M M  O   O  RRRR     Y                   %
+%                    M   M  E      M   M  O   O  R R      Y                   %
+%                    M   M  EEEEE  M   M   OOO   R  R     Y                   %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Memory Allocation Methods                    %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1998                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Segregate our memory requirements from any program that calls our API.  This
+%  should help reduce the risk of others changing our program state or causing
+%  memory corruption.
+%
+%  Our custom memory allocation manager implements a best-fit allocation policy
+%  using segregated free lists.  It uses a linear distribution of size classes
+%  for lower sizes and a power of two distribution of size classes at higher
+%  sizes.  It is based on the paper, "Fast Memory Allocation using Lazy Fits."
+%  written by Yoo C. Chung.
+%
+%  By default, ANSI memory methods are called (e.g. malloc).  Use the
+%  custom memory allocator by defining MAGICKCORE_EMBEDDABLE_SUPPORT
+%  to allocate memory with private anonymous mapping rather than from the
+%  heap.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+
+/*
+  Define declarations.
+*/
+#define BlockFooter(block,size) \
+  ((size_t *) ((char *) (block)+(size)-2*sizeof(size_t)))
+#define BlockHeader(block)  ((size_t *) (block)-1)
+#define BlockSize  4096
+#define BlockThreshold  1024
+#define AlignedSize  (16*sizeof(void *))
+#define MaxBlockExponent  16
+#define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1)
+#define MaxSegments  1024
+#define MemoryGuard  ((0xdeadbeef << 31)+0xdeafdeed)
+#define NextBlock(block)  ((char *) (block)+SizeOfBlock(block))
+#define NextBlockInList(block)  (*(void **) (block))
+#define PreviousBlock(block)  ((char *) (block)-(*((size_t *) (block)-2)))
+#define PreviousBlockBit  0x01
+#define PreviousBlockInList(block)  (*((void **) (block)+1))
+#define SegmentSize  (2*1024*1024)
+#define SizeMask  (~0x01)
+#define SizeOfBlock(block)  (*BlockHeader(block) & SizeMask)
+
+/*
+  Typedef declarations.
+*/
+typedef struct _DataSegmentInfo
+{
+  void
+    *allocation,
+    *bound;
+
+  MagickBooleanType
+    mapped;
+
+  size_t
+    length;
+
+  struct _DataSegmentInfo
+    *previous,
+    *next;
+} DataSegmentInfo;
+
+typedef struct _MemoryInfo
+{
+  size_t
+    allocation;
+
+  void
+    *blocks[MaxBlocks+1];
+
+  size_t
+    number_segments;
+
+  DataSegmentInfo
+    *segments[MaxSegments],
+    segment_pool[MaxSegments];
+} MemoryInfo;
+
+typedef struct _MagickMemoryMethods
+{
+  AcquireMemoryHandler
+    acquire_memory_handler;
+
+  ResizeMemoryHandler
+    resize_memory_handler;
+
+  DestroyMemoryHandler
+    destroy_memory_handler;
+} MagickMemoryMethods;
+
+
+/*
+  Global declarations.
+*/
+static MagickMemoryMethods
+  memory_methods =
+  {
+    (AcquireMemoryHandler) malloc,
+    (ResizeMemoryHandler) realloc,
+    (DestroyMemoryHandler) free
+  };
+
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+static MemoryInfo
+  memory_info;
+
+static SemaphoreInfo
+  *memory_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile DataSegmentInfo
+  *free_segments = (DataSegmentInfo *) NULL;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  ExpandHeap(size_t);
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e A l i g n e d M e m o r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireAlignedMemory() returns a pointer to a block of memory at least size
+%  bytes whose address is a multiple of 16*sizeof(void *).
+%
+%  The format of the AcquireAlignedMemory method is:
+%
+%      void *AcquireAlignedMemory(const size_t count,const size_t quantum)
+%
+%  A description of each parameter follows:
+%
+%    o count: the number of quantum elements to allocate.
+%
+%    o quantum: the number of bytes in each quantum.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
+{
+  size_t
+    size;
+
+  size=count*quantum;
+  if ((count == 0) || (quantum != (size/count)))
+    {
+      errno=ENOMEM;
+      return((void *) NULL);
+    }
+#if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
+  {
+    void
+      *memory;
+
+    if (posix_memalign(&memory,AlignedSize,MagickMax(size,AlignedSize)) == 0)
+      return(memory);
+  }
+#endif
+  return(malloc(MagickMax(size,AlignedSize)));
+}
+
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e B l o c k                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireBlock() returns a pointer to a block of memory at least size bytes
+%  suitably aligned for any use.
+%
+%  The format of the AcquireBlock method is:
+%
+%      void *AcquireBlock(const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o size: the size of the memory in bytes to allocate.
+%
+*/
+
+static inline size_t AllocationPolicy(size_t size)
+{
+  register size_t
+    blocksize;
+
+  /*
+    The linear distribution.
+  */
+  assert(size != 0);
+  assert(size % (4*sizeof(size_t)) == 0);
+  if (size <= BlockThreshold)
+    return(size/(4*sizeof(size_t)));
+  /*
+    Check for the largest block size.
+  */
+  if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L))))
+    return(MaxBlocks-1L);
+  /*
+    Otherwise use a power of two distribution.
+  */
+  blocksize=BlockThreshold/(4*sizeof(size_t));
+  for ( ; size > BlockThreshold; size/=2)
+    blocksize++;
+  assert(blocksize > (BlockThreshold/(4*sizeof(size_t))));
+  assert(blocksize < (MaxBlocks-1L));
+  return(blocksize);
+}
+
+static inline void InsertFreeBlock(void *block,const size_t i)
+{
+  register void
+    *next,
+    *previous;
+
+  size_t
+    size;
+
+  size=SizeOfBlock(block);
+  previous=(void *) NULL;
+  next=memory_info.blocks[i];
+  while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
+  {
+    previous=next;
+    next=NextBlockInList(next);
+  }
+  PreviousBlockInList(block)=previous;
+  NextBlockInList(block)=next;
+  if (previous != (void *) NULL)
+    NextBlockInList(previous)=block;
+  else
+    memory_info.blocks[i]=block;
+  if (next != (void *) NULL)
+    PreviousBlockInList(next)=block;
+}
+
+static inline void RemoveFreeBlock(void *block,const size_t i)
+{
+  register void
+    *next,
+    *previous;
+
+  next=NextBlockInList(block);
+  previous=PreviousBlockInList(block);
+  if (previous == (void *) NULL)
+    memory_info.blocks[i]=next;
+  else
+    NextBlockInList(previous)=next;
+  if (next != (void *) NULL)
+    PreviousBlockInList(next)=previous;
+}
+
+static void *AcquireBlock(size_t size)
+{
+  register size_t
+    i;
+
+  register void
+    *block;
+
+  /*
+    Find free block.
+  */
+  size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
+  i=AllocationPolicy(size);
+  block=memory_info.blocks[i];
+  while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
+    block=NextBlockInList(block);
+  if (block == (void *) NULL)
+    {
+      i++;
+      while (memory_info.blocks[i] == (void *) NULL)
+        i++;
+      block=memory_info.blocks[i];
+      if (i >= MaxBlocks)
+        return((void *) NULL);
+    }
+  assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0);
+  assert(SizeOfBlock(block) >= size);
+  RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block)));
+  if (SizeOfBlock(block) > size)
+    {
+      size_t
+        blocksize;
+
+      void
+        *next;
+
+      /*
+        Split block.
+      */
+      next=(char *) block+size;
+      blocksize=SizeOfBlock(block)-size;
+      *BlockHeader(next)=blocksize;
+      *BlockFooter(next,blocksize)=blocksize;
+      InsertFreeBlock(next,AllocationPolicy(blocksize));
+      *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask);
+    }
+  assert(size == SizeOfBlock(block));
+  *BlockHeader(NextBlock(block))|=PreviousBlockBit;
+  memory_info.allocation+=size;
+  return(block);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e M a g i c k M e m o r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireMagickMemory() returns a pointer to a block of memory at least size
+%  bytes suitably aligned for any use.
+%
+%  The format of the AcquireMagickMemory method is:
+%
+%      void *AcquireMagickMemory(const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o size: the size of the memory in bytes to allocate.
+%
+*/
+MagickExport void *AcquireMagickMemory(const size_t size)
+{
+  register void
+    *memory;
+
+#if !defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
+#else
+  if (memory_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&memory_semaphore);
+  if (free_segments == (DataSegmentInfo *) NULL)
+    {
+      LockSemaphoreInfo(memory_semaphore);
+      if (free_segments == (DataSegmentInfo *) NULL)
+        {
+          register ssize_t
+            i;
+
+          assert(2*sizeof(size_t) > (size_t) (~SizeMask));
+          (void) ResetMagickMemory(&memory_info,0,sizeof(memory_info));
+          memory_info.allocation=SegmentSize;
+          memory_info.blocks[MaxBlocks]=(void *) (-1);
+          for (i=0; i < MaxSegments; i++)
+          {
+            if (i != 0)
+              memory_info.segment_pool[i].previous=
+                (&memory_info.segment_pool[i-1]);
+            if (i != (MaxSegments-1))
+              memory_info.segment_pool[i].next=(&memory_info.segment_pool[i+1]);
+          }
+          free_segments=(&memory_info.segment_pool[0]);
+        }
+      UnlockSemaphoreInfo(memory_semaphore);
+    }
+  LockSemaphoreInfo(memory_semaphore);
+  memory=AcquireBlock(size == 0 ? 1UL : size);
+  if (memory == (void *) NULL)
+    {
+      if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse)
+        memory=AcquireBlock(size == 0 ? 1UL : size);
+    }
+  UnlockSemaphoreInfo(memory_semaphore);
+#endif
+  return(memory);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e Q u a n t u m M e m o r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireQuantumMemory() returns a pointer to a block of memory at least
+%  count * quantum bytes suitably aligned for any use.
+%
+%  The format of the AcquireQuantumMemory method is:
+%
+%      void *AcquireQuantumMemory(const size_t count,const size_t quantum)
+%
+%  A description of each parameter follows:
+%
+%    o count: the number of quantum elements to allocate.
+%
+%    o quantum: the number of bytes in each quantum.
+%
+*/
+MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
+{
+  size_t
+    size;
+
+  size=count*quantum;
+  if ((count == 0) || (quantum != (size/count)))
+    {
+      errno=ENOMEM;
+      return((void *) NULL);
+    }
+  return(AcquireMagickMemory(size));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o p y M a g i c k M e m o r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CopyMagickMemory() copies size bytes from memory area source to the
+%  destination.  Copying between objects that overlap will take place
+%  correctly.  It returns destination.
+%
+%  The format of the CopyMagickMemory method is:
+%
+%      void *CopyMagickMemory(void *destination,const void *source,
+%        const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o destination: the destination.
+%
+%    o source: the source.
+%
+%    o size: the size of the memory in bytes to allocate.
+%
+*/
+MagickExport void *CopyMagickMemory(void *destination,const void *source,
+  const size_t size)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned char
+    *q;
+
+  assert(destination != (void *) NULL);
+  assert(source != (const void *) NULL);
+  p=(const unsigned char *) source;
+  q=(unsigned char *) destination;
+  if (((q+size) < p) || (q > (p+size)))
+    switch (size)
+    {
+      default: return(memcpy(destination,source,size));
+      case 8: *q++=(*p++);
+      case 7: *q++=(*p++);
+      case 6: *q++=(*p++);
+      case 5: *q++=(*p++);
+      case 4: *q++=(*p++);
+      case 3: *q++=(*p++);
+      case 2: *q++=(*p++);
+      case 1: *q++=(*p++);
+      case 0: return(destination);
+    }
+  return(memmove(destination,source,size));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y M a g i c k M e m o r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMagickMemory() deallocates memory associated with the memory manager.
+%
+%  The format of the DestroyMagickMemory method is:
+%
+%      DestroyMagickMemory(void)
+%
+*/
+MagickExport void DestroyMagickMemory(void)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  register ssize_t
+    i;
+
+  if (memory_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&memory_semaphore);
+  LockSemaphoreInfo(memory_semaphore);
+  UnlockSemaphoreInfo(memory_semaphore);
+  for (i=0; i < (ssize_t) memory_info.number_segments; i++)
+    if (memory_info.segments[i]->mapped == MagickFalse)
+      memory_methods.destroy_memory_handler(
+        memory_info.segments[i]->allocation);
+    else
+      (void) UnmapBlob(memory_info.segments[i]->allocation,
+        memory_info.segments[i]->length);
+  free_segments=(DataSegmentInfo *) NULL;
+  (void) ResetMagickMemory(&memory_info,0,sizeof(memory_info));
+  DestroySemaphoreInfo(&memory_semaphore);
+#endif
+}
+
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   E x p a n d H e a p                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExpandHeap() get more memory from the system.  It returns MagickTrue on
+%  success otherwise MagickFalse.
+%
+%  The format of the ExpandHeap method is:
+%
+%      MagickBooleanType ExpandHeap(size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o size: the size of the memory in bytes we require.
+%
+*/
+static MagickBooleanType ExpandHeap(size_t size)
+{
+  DataSegmentInfo
+    *segment_info;
+
+  MagickBooleanType
+    mapped;
+
+  register ssize_t
+    i;
+
+  register void
+    *block;
+
+  size_t
+    blocksize;
+
+  void
+    *segment;
+
+  blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
+  assert(memory_info.number_segments < MaxSegments);
+  segment=MapBlob(-1,IOMode,0,blocksize);
+  mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
+  if (segment == (void *) NULL)
+    segment=(void *) memory_methods.acquire_memory_handler(blocksize);
+  if (segment == (void *) NULL)
+    return(MagickFalse);
+  segment_info=(DataSegmentInfo *) free_segments;
+  free_segments=segment_info->next;
+  segment_info->mapped=mapped;
+  segment_info->length=blocksize;
+  segment_info->allocation=segment;
+  segment_info->bound=(char *) segment+blocksize;
+  i=(ssize_t) memory_info.number_segments-1;
+  for ( ; (i >= 0) && (memory_info.segments[i]->allocation > segment); i--)
+    memory_info.segments[i+1]=memory_info.segments[i];
+  memory_info.segments[i+1]=segment_info;
+  memory_info.number_segments++;
+  size=blocksize-12*sizeof(size_t);
+  block=(char *) segment_info->allocation+4*sizeof(size_t);
+  *BlockHeader(block)=size | PreviousBlockBit;
+  *BlockFooter(block,size)=size;
+  InsertFreeBlock(block,AllocationPolicy(size));
+  block=NextBlock(block);
+  assert(block < segment_info->bound);
+  *BlockHeader(block)=2*sizeof(size_t);
+  *BlockHeader(NextBlock(block))=PreviousBlockBit;
+  return(MagickTrue);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k M e m o r y M e t h o d s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy
+%  memory.
+%
+%  The format of the GetMagickMemoryMethods() method is:
+%
+%      void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
+%        ResizeMemoryHandler *resize_memory_handler,
+%        DestroyMemoryHandler *destroy_memory_handler)
+%
+%  A description of each parameter follows:
+%
+%    o acquire_memory_handler: method to acquire memory (e.g. malloc).
+%
+%    o resize_memory_handler: method to resize memory (e.g. realloc).
+%
+%    o destroy_memory_handler: method to destroy memory (e.g. free).
+%
+*/
+MagickExport void GetMagickMemoryMethods(
+  AcquireMemoryHandler *acquire_memory_handler,
+  ResizeMemoryHandler *resize_memory_handler,
+  DestroyMemoryHandler *destroy_memory_handler)
+{
+  assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
+  assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
+  assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
+  *acquire_memory_handler=memory_methods.acquire_memory_handler;
+  *resize_memory_handler=memory_methods.resize_memory_handler;
+  *destroy_memory_handler=memory_methods.destroy_memory_handler;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e l i n q u i s h A l i g n e d M e m o r y                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
+%  or reuse.
+%
+%  The format of the RelinquishAlignedMemory method is:
+%
+%      void *RelinquishAlignedMemory(void *memory)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a block of memory to free for reuse.
+%
+*/
+MagickExport void *RelinquishAlignedMemory(void *memory)
+{
+  if (memory == (void *) NULL)
+    return((void *) NULL);
+  free(memory);
+  return((void *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e l i n q u i s h M a g i c k M e m o r y                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory()
+%  or AcquireQuantumMemory() for reuse.
+%
+%  The format of the RelinquishMagickMemory method is:
+%
+%      void *RelinquishMagickMemory(void *memory)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a block of memory to free for reuse.
+%
+*/
+MagickExport void *RelinquishMagickMemory(void *memory)
+{
+  if (memory == (void *) NULL)
+    return((void *) NULL);
+#if !defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  memory_methods.destroy_memory_handler(memory);
+#else
+  assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
+  assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
+  LockSemaphoreInfo(memory_semaphore);
+  if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
+    {
+      void
+        *previous;
+
+      /*
+        Coalesce with previous adjacent block.
+      */
+      previous=PreviousBlock(memory);
+      RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
+      *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
+        (*BlockHeader(previous) & ~SizeMask);
+      memory=previous;
+    }
+  if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
+    {
+      void
+        *next;
+
+      /*
+        Coalesce with next adjacent block.
+      */
+      next=NextBlock(memory);
+      RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
+      *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
+        (*BlockHeader(memory) & ~SizeMask);
+    }
+  *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
+  *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
+  InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
+  UnlockSemaphoreInfo(memory_semaphore);
+#endif
+  return((void *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t M a g i c k M e m o r y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetMagickMemory() fills the first size bytes of the memory area pointed to
+%  by memory with the constant byte c.
+%
+%  The format of the ResetMagickMemory method is:
+%
+%      void *ResetMagickMemory(void *memory,int byte,const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a memory allocation.
+%
+%    o byte: Set the memory to this value.
+%
+%    o size: Size of the memory to reset.
+%
+*/
+MagickExport void *ResetMagickMemory(void *memory,int byte,const size_t size)
+{
+  assert(memory != (void *) NULL);
+  return(memset(memory,byte,size));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s i z e M a g i c k M e m o r y                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResizeMagickMemory() changes the size of the memory and returns a pointer to
+%  the (possibly moved) block.  The contents will be unchanged up to the
+%  lesser of the new and old sizes.
+%
+%  The format of the ResizeMagickMemory method is:
+%
+%      void *ResizeMagickMemory(void *memory,const size_t size)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a memory allocation.
+%
+%    o size: the new size of the allocated memory.
+%
+*/
+
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+static inline void *ResizeBlock(void *block,size_t size)
+{
+  register void
+    *memory;
+
+  if (block == (void *) NULL)
+    return(AcquireBlock(size));
+  memory=AcquireBlock(size);
+  if (memory == (void *) NULL)
+    return((void *) NULL);
+  if (size <= (SizeOfBlock(block)-sizeof(size_t)))
+    (void) memcpy(memory,block,size);
+  else
+    (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
+  memory_info.allocation+=size;
+  return(memory);
+}
+#endif
+
+MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
+{
+  register void
+    *block;
+
+  if (memory == (void *) NULL)
+    return(AcquireMagickMemory(size));
+#if !defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
+  if (block == (void *) NULL)
+    memory=RelinquishMagickMemory(memory);
+#else
+  LockSemaphoreInfo(memory_semaphore);
+  block=ResizeBlock(memory,size == 0 ? 1UL : size);
+  if (block == (void *) NULL)
+    {
+      if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
+        {
+          UnlockSemaphoreInfo(memory_semaphore);
+          memory=RelinquishMagickMemory(memory);
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        }
+      block=ResizeBlock(memory,size == 0 ? 1UL : size);
+      assert(block != (void *) NULL);
+    }
+  UnlockSemaphoreInfo(memory_semaphore);
+  memory=RelinquishMagickMemory(memory);
+#endif
+  return(block);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s i z e Q u a n t u m M e m o r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResizeQuantumMemory() changes the size of the memory and returns a pointer
+%  to the (possibly moved) block.  The contents will be unchanged up to the
+%  lesser of the new and old sizes.
+%
+%  The format of the ResizeQuantumMemory method is:
+%
+%      void *ResizeQuantumMemory(void *memory,const size_t count,
+%        const size_t quantum)
+%
+%  A description of each parameter follows:
+%
+%    o memory: A pointer to a memory allocation.
+%
+%    o count: the number of quantum elements to allocate.
+%
+%    o quantum: the number of bytes in each quantum.
+%
+*/
+MagickExport void *ResizeQuantumMemory(void *memory,const size_t count,
+  const size_t quantum)
+{
+  size_t
+    size;
+
+  size=count*quantum;
+  if ((count == 0) || (quantum != (size/count)))
+    {
+      memory=RelinquishMagickMemory(memory);
+      errno=ENOMEM;
+      return((void *) NULL);
+    }
+  return(ResizeMagickMemory(memory,size));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t M a g i c k M e m o r y M e t h o d s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy
+%  memory.
+%
+%  The format of the SetMagickMemoryMethods() method is:
+%
+%      SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
+%        ResizeMemoryHandler resize_memory_handler,
+%        DestroyMemoryHandler destroy_memory_handler)
+%
+%  A description of each parameter follows:
+%
+%    o acquire_memory_handler: method to acquire memory (e.g. malloc).
+%
+%    o resize_memory_handler: method to resize memory (e.g. realloc).
+%
+%    o destroy_memory_handler: method to destroy memory (e.g. free).
+%
+*/
+MagickExport void SetMagickMemoryMethods(
+  AcquireMemoryHandler acquire_memory_handler,
+  ResizeMemoryHandler resize_memory_handler,
+  DestroyMemoryHandler destroy_memory_handler)
+{
+  /*
+    Set memory methods.
+  */
+  if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
+    memory_methods.acquire_memory_handler=acquire_memory_handler;
+  if (resize_memory_handler != (ResizeMemoryHandler) NULL)
+    memory_methods.resize_memory_handler=resize_memory_handler;
+  if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
+    memory_methods.destroy_memory_handler=destroy_memory_handler;
+}
diff --git a/MagickCore/memory_.h b/MagickCore/memory_.h
new file mode 100644
index 0000000..f807278
--- /dev/null
+++ b/MagickCore/memory_.h
@@ -0,0 +1,52 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore memory methods.
+*/
+#ifndef _MAGICKCORE_MEMORY_H
+#define _MAGICKCORE_MEMORY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef void
+  *(*AcquireMemoryHandler)(size_t),
+  (*DestroyMemoryHandler)(void *),
+  *(*ResizeMemoryHandler)(void *,size_t);
+
+extern MagickExport void
+  *AcquireAlignedMemory(const size_t,const size_t) magick_attribute((malloc)),
+  *AcquireMagickMemory(const size_t) magick_attribute((malloc)),
+  *AcquireQuantumMemory(const size_t,const size_t) magick_attribute((malloc)),
+  *CopyMagickMemory(void *,const void *,const size_t)
+    magick_attribute((nonnull)),
+  DestroyMagickMemory(void),
+  GetMagickMemoryMethods(AcquireMemoryHandler *,ResizeMemoryHandler *,
+    DestroyMemoryHandler *),
+  *RelinquishAlignedMemory(void *),
+  *RelinquishMagickMemory(void *),
+  *ResetMagickMemory(void *,int,const size_t),
+  *ResizeMagickMemory(void *,const size_t) magick_attribute((malloc)),
+  *ResizeQuantumMemory(void *,const size_t,const size_t)
+    magick_attribute((malloc)),
+  SetMagickMemoryMethods(AcquireMemoryHandler,ResizeMemoryHandler,
+    DestroyMemoryHandler);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/methods.h b/MagickCore/methods.h
new file mode 100644
index 0000000..28c9d8b
--- /dev/null
+++ b/MagickCore/methods.h
@@ -0,0 +1,1413 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore API methods prefix.
+
+  nm .libs/libMagickCore.a | grep ' T ' | \
+    awk '{ printf("#define %s  PrependMagickMethod(%s)\n", $3, $3); }' | \
+    sort
+*/
+#ifndef _MAGICKCORE_METHOD_H
+#define _MAGICKCORE_METHOD_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_NAMESPACE_PREFIX)
+
+#if defined(__STDC__)
+#define PrescanMagickPrefix(prefix,method)  prefix ## method
+#else
+#define PrescanMagickPrefix(prefix,method)  prefix(method)
+#endif
+#define EvaluateMagickPrefix(prefix,method)  PrescanMagickPrefix(prefix,method)
+#define PrependMagickMethod(method) \
+  EvaluateMagickPrefix(MAGICKCORE_NAMESPACE_PREFIX,method)
+
+#define AcquireAlignedMemory  PrependMagickMethod(AcquireAlignedMemory)
+#define AcquireCacheViewIndexes  PrependMagickMethod(AcquireCacheViewIndexes)
+#define AcquireCacheViewPixels  PrependMagickMethod(AcquireCacheViewPixels)
+#define AcquireCacheView  PrependMagickMethod(AcquireCacheView)
+#define AcquireDrawInfo  PrependMagickMethod(AcquireDrawInfo)
+#define AcquireExceptionInfo  PrependMagickMethod(AcquireExceptionInfo)
+#define AcquireFxInfo  PrependMagickMethod(AcquireFxInfo)
+#define AcquireImageColormap  PrependMagickMethod(AcquireImageColormap)
+#define AcquireImageInfo  PrependMagickMethod(AcquireImageInfo)
+#define AcquireImagePixels  PrependMagickMethod(AcquireImagePixels)
+#define AcquireImage  PrependMagickMethod(AcquireImage)
+#define AcquireIndexes  PrependMagickMethod(AcquireIndexes)
+#define AcquireKernelBuiltIn  PrependMagickMethod(AcquireKernelBuiltIn)
+#define AcquireKernelInfo  PrependMagickMethod(AcquireKernelInfo)
+#define AcquireMagickMatrix  PrependMagickMethod(AcquireMagickMatrix)
+#define AcquireMagickMemory  PrependMagickMethod(AcquireMagickMemory)
+#define AcquireMagickResource  PrependMagickMethod(AcquireMagickResource)
+#define AcquireMemory  PrependMagickMethod(AcquireMemory)
+#define AcquireNextImage  PrependMagickMethod(AcquireNextImage)
+#define AcquireOneCacheViewPixel  PrependMagickMethod(AcquireOneCacheViewPixel)
+#define AcquireOneCacheViewVirtualPixel  PrependMagickMethod(AcquireOneCacheViewVirtualPixel)
+#define AcquireOneMagickPixel  PrependMagickMethod(AcquireOneMagickPixel)
+#define AcquireOnePixel  PrependMagickMethod(AcquireOnePixel)
+#define AcquireOneVirtualPixel  PrependMagickMethod(AcquireOneVirtualPixel)
+#define AcquirePixelCacheNexus  PrependMagickMethod(AcquirePixelCacheNexus)
+#define AcquirePixelCache  PrependMagickMethod(AcquirePixelCache)
+#define AcquirePixels  PrependMagickMethod(AcquirePixels)
+#define AcquireQuantizeInfo  PrependMagickMethod(AcquireQuantizeInfo)
+#define AcquireQuantumInfo  PrependMagickMethod(AcquireQuantumInfo)
+#define AcquireQuantumMemory  PrependMagickMethod(AcquireQuantumMemory)
+#define AcquireRandomInfo  PrependMagickMethod(AcquireRandomInfo)
+#define AcquireResampleFilter  PrependMagickMethod(AcquireResampleFilter)
+#define AcquireResizeFilter  PrependMagickMethod(AcquireResizeFilter)
+#define AcquireSemaphoreInfo  PrependMagickMethod(AcquireSemaphoreInfo)
+#define AcquireSignatureInfo  PrependMagickMethod(AcquireSignatureInfo)
+#define AcquireStreamInfo  PrependMagickMethod(AcquireStreamInfo)
+#define AcquireStringInfo  PrependMagickMethod(AcquireStringInfo)
+#define AcquireString  PrependMagickMethod(AcquireString)
+#define AcquireTimerInfo  PrependMagickMethod(AcquireTimerInfo)
+#define AcquireTokenInfo  PrependMagickMethod(AcquireTokenInfo)
+#define AcquireUniqueFilename  PrependMagickMethod(AcquireUniqueFilename)
+#define AcquireUniqueFileResource  PrependMagickMethod(AcquireUniqueFileResource)
+#define AcquireUniqueSymbolicLink  PrependMagickMethod(AcquireUniqueSymbolicLink)
+#define AdaptiveBlurImageChannel  PrependMagickMethod(AdaptiveBlurImageChannel)
+#define AdaptiveBlurImage  PrependMagickMethod(AdaptiveBlurImage)
+#define AdaptiveResizeImage  PrependMagickMethod(AdaptiveResizeImage)
+#define AdaptiveSharpenImageChannel  PrependMagickMethod(AdaptiveSharpenImageChannel)
+#define AdaptiveSharpenImage  PrependMagickMethod(AdaptiveSharpenImage)
+#define AdaptiveThresholdImage  PrependMagickMethod(AdaptiveThresholdImage)
+#define AddChildToXMLTree  PrependMagickMethod(AddChildToXMLTree)
+#define AddNoiseImageChannel  PrependMagickMethod(AddNoiseImageChannel)
+#define AddNoiseImage  PrependMagickMethod(AddNoiseImage)
+#define AddPathToXMLTree  PrependMagickMethod(AddPathToXMLTree)
+#define AddValueToSplayTree  PrependMagickMethod(AddValueToSplayTree)
+#define AffineTransformImage  PrependMagickMethod(AffineTransformImage)
+#define AffinityImage  PrependMagickMethod(AffinityImage)
+#define AffinityImages  PrependMagickMethod(AffinityImages)
+#define AllocateImageColormap  PrependMagickMethod(AllocateImageColormap)
+#define AllocateImage  PrependMagickMethod(AllocateImage)
+#define AllocateNextImage  PrependMagickMethod(AllocateNextImage)
+#define AllocateSemaphoreInfo  PrependMagickMethod(AllocateSemaphoreInfo)
+#define AllocateString  PrependMagickMethod(AllocateString)
+#define analyzeImage  PrependMagickMethod(analyzeImage)
+#define AnimateImages  PrependMagickMethod(AnimateImages)
+#define AnnotateImage  PrependMagickMethod(AnnotateImage)
+#define AppendImageFormat  PrependMagickMethod(AppendImageFormat)
+#define AppendImages  PrependMagickMethod(AppendImages)
+#define AppendImageToList  PrependMagickMethod(AppendImageToList)
+#define AppendValueToLinkedList  PrependMagickMethod(AppendValueToLinkedList)
+#define Ascii85Encode  PrependMagickMethod(Ascii85Encode)
+#define Ascii85Flush  PrependMagickMethod(Ascii85Flush)
+#define Ascii85Initialize  PrependMagickMethod(Ascii85Initialize)
+#define AsynchronousResourceComponentTerminus  PrependMagickMethod(AsynchronousResourceComponentTerminus)
+#define AttachBlob  PrependMagickMethod(AttachBlob)
+#define AutoGammaImageChannel  PrependMagickMethod(AutoGammaImageChannel)
+#define AutoGammaImage  PrependMagickMethod(AutoGammaImage)
+#define AutoLevelImageChannel  PrependMagickMethod(AutoLevelImageChannel)
+#define AutoLevelImage  PrependMagickMethod(AutoLevelImage)
+#define AverageImages  PrependMagickMethod(AverageImages)
+#define Base64Decode  PrependMagickMethod(Base64Decode)
+#define Base64Encode  PrependMagickMethod(Base64Encode)
+#define BilevelImageChannel  PrependMagickMethod(BilevelImageChannel)
+#define BilevelImage  PrependMagickMethod(BilevelImage)
+#define BlackThresholdImageChannel  PrependMagickMethod(BlackThresholdImageChannel)
+#define BlackThresholdImage  PrependMagickMethod(BlackThresholdImage)
+#define BlobToFile  PrependMagickMethod(BlobToFile)
+#define BlobToImage  PrependMagickMethod(BlobToImage)
+#define BlueShiftImage  PrependMagickMethod(BlueShiftImage)
+#define BlurImageChannel  PrependMagickMethod(BlurImageChannel)
+#define BlurImage  PrependMagickMethod(BlurImage)
+#define BorderImage  PrependMagickMethod(BorderImage)
+#define BrightnessContrastImageChannel  PrependMagickMethod(BrightnessContrastImageChannel)
+#define BrightnessContrastImage  PrependMagickMethod(BrightnessContrastImage)
+#define CacheComponentGenesis  PrependMagickMethod(CacheComponentGenesis)
+#define CacheComponentTerminus  PrependMagickMethod(CacheComponentTerminus)
+#define CanonicalXMLContent  PrependMagickMethod(CanonicalXMLContent)
+#define CatchException  PrependMagickMethod(CatchException)
+#define CatchImageException  PrependMagickMethod(CatchImageException)
+#define ChannelImage  PrependMagickMethod(ChannelImage)
+#define ChannelThresholdImage  PrependMagickMethod(ChannelThresholdImage)
+#define CharcoalImage  PrependMagickMethod(CharcoalImage)
+#define ChopImage  PrependMagickMethod(ChopImage)
+#define ChopPathComponents  PrependMagickMethod(ChopPathComponents)
+#define ClampImageChannel  PrependMagickMethod(ClampImageChannel)
+#define ClampImage  PrependMagickMethod(ClampImage)
+#define ClearLinkedList  PrependMagickMethod(ClearLinkedList)
+#define ClearMagickException  PrependMagickMethod(ClearMagickException)
+#define ClipImagePath  PrependMagickMethod(ClipImagePath)
+#define ClipImage  PrependMagickMethod(ClipImage)
+#define ClipPathImage  PrependMagickMethod(ClipPathImage)
+#define CloneBlobInfo  PrependMagickMethod(CloneBlobInfo)
+#define CloneCacheView  PrependMagickMethod(CloneCacheView)
+#define CloneDrawInfo  PrependMagickMethod(CloneDrawInfo)
+#define CloneImageArtifacts  PrependMagickMethod(CloneImageArtifacts)
+#define CloneImageAttributes  PrependMagickMethod(CloneImageAttributes)
+#define CloneImageInfo  PrependMagickMethod(CloneImageInfo)
+#define CloneImageList  PrependMagickMethod(CloneImageList)
+#define CloneImageOptions  PrependMagickMethod(CloneImageOptions)
+#define CloneImage  PrependMagickMethod(CloneImage)
+#define CloneImageProfiles  PrependMagickMethod(CloneImageProfiles)
+#define CloneImageProperties  PrependMagickMethod(CloneImageProperties)
+#define CloneImages  PrependMagickMethod(CloneImages)
+#define CloneMemory  PrependMagickMethod(CloneMemory)
+#define CloneMontageInfo  PrependMagickMethod(CloneMontageInfo)
+#define ClonePixelCacheMethods  PrependMagickMethod(ClonePixelCacheMethods)
+#define ClonePixelCache  PrependMagickMethod(ClonePixelCache)
+#define CloneQuantizeInfo  PrependMagickMethod(CloneQuantizeInfo)
+#define CloneSplayTree  PrependMagickMethod(CloneSplayTree)
+#define CloneStringInfo  PrependMagickMethod(CloneStringInfo)
+#define CloneString  PrependMagickMethod(CloneString)
+#define CloseBlob  PrependMagickMethod(CloseBlob)
+#define CloseCacheView  PrependMagickMethod(CloseCacheView)
+#define CloseMagickLog  PrependMagickMethod(CloseMagickLog)
+#define ClutImageChannel  PrependMagickMethod(ClutImageChannel)
+#define ClutImage  PrependMagickMethod(ClutImage)
+#define CoalesceImages  PrependMagickMethod(CoalesceImages)
+#define CoderComponentGenesis  PrependMagickMethod(CoderComponentGenesis)
+#define CoderComponentTerminus  PrependMagickMethod(CoderComponentTerminus)
+#define ColorComponentGenesis  PrependMagickMethod(ColorComponentGenesis)
+#define ColorComponentTerminus  PrependMagickMethod(ColorComponentTerminus)
+#define ColorDecisionListImage  PrependMagickMethod(ColorDecisionListImage)
+#define ColorFloodfillImage  PrependMagickMethod(ColorFloodfillImage)
+#define ColorizeImage  PrependMagickMethod(ColorizeImage)
+#define CombineImages  PrependMagickMethod(CombineImages)
+#define CompareHashmapStringInfo  PrependMagickMethod(CompareHashmapStringInfo)
+#define CompareHashmapString  PrependMagickMethod(CompareHashmapString)
+#define CompareImageChannels  PrependMagickMethod(CompareImageChannels)
+#define CompareImageLayers  PrependMagickMethod(CompareImageLayers)
+#define CompareImages  PrependMagickMethod(CompareImages)
+#define CompareSplayTreeStringInfo  PrependMagickMethod(CompareSplayTreeStringInfo)
+#define CompareSplayTreeString  PrependMagickMethod(CompareSplayTreeString)
+#define CompareStringInfo  PrependMagickMethod(CompareStringInfo)
+#define CompositeImageChannel  PrependMagickMethod(CompositeImageChannel)
+#define CompositeImage  PrependMagickMethod(CompositeImage)
+#define CompositeLayers  PrependMagickMethod(CompositeLayers)
+#define CompressImageColormap  PrependMagickMethod(CompressImageColormap)
+#define ConcatenateColorComponent  PrependMagickMethod(ConcatenateColorComponent)
+#define ConcatenateMagickString  PrependMagickMethod(ConcatenateMagickString)
+#define ConcatenateStringInfo  PrependMagickMethod(ConcatenateStringInfo)
+#define ConcatenateString  PrependMagickMethod(ConcatenateString)
+#define ConfigureComponentGenesis  PrependMagickMethod(ConfigureComponentGenesis)
+#define ConfigureComponentTerminus  PrependMagickMethod(ConfigureComponentTerminus)
+#define ConfigureFileToStringInfo  PrependMagickMethod(ConfigureFileToStringInfo)
+#define ConsolidateCMYKImages  PrependMagickMethod(ConsolidateCMYKImages)
+#define ConstantString  PrependMagickMethod(ConstantString)
+#define ConstituteComponentGenesis  PrependMagickMethod(ConstituteComponentGenesis)
+#define ConstituteComponentTerminus  PrependMagickMethod(ConstituteComponentTerminus)
+#define ConstituteImage  PrependMagickMethod(ConstituteImage)
+#define ContinueTimer  PrependMagickMethod(ContinueTimer)
+#define ContrastImage  PrependMagickMethod(ContrastImage)
+#define ContrastStretchImageChannel  PrependMagickMethod(ContrastStretchImageChannel)
+#define ContrastStretchImage  PrependMagickMethod(ContrastStretchImage)
+#define ConvertHSBToRGB  PrependMagickMethod(ConvertHSBToRGB)
+#define ConvertHSLToRGB  PrependMagickMethod(ConvertHSLToRGB)
+#define ConvertHWBToRGB  PrependMagickMethod(ConvertHWBToRGB)
+#define ConvertRGBToHSB  PrependMagickMethod(ConvertRGBToHSB)
+#define ConvertRGBToHSL  PrependMagickMethod(ConvertRGBToHSL)
+#define ConvertRGBToHWB  PrependMagickMethod(ConvertRGBToHWB)
+#define ConvolveImageChannel  PrependMagickMethod(ConvolveImageChannel)
+#define ConvolveImage  PrependMagickMethod(ConvolveImage)
+#define CopyMagickMemory  PrependMagickMethod(CopyMagickMemory)
+#define CopyMagickString  PrependMagickMethod(CopyMagickString)
+#define CropImage  PrependMagickMethod(CropImage)
+#define CycleColormapImage  PrependMagickMethod(CycleColormapImage)
+#define DecipherImage  PrependMagickMethod(DecipherImage)
+#define DeconstructImages  PrependMagickMethod(DeconstructImages)
+#define DefineImageArtifact  PrependMagickMethod(DefineImageArtifact)
+#define DefineImageOption  PrependMagickMethod(DefineImageOption)
+#define DefineImageProperty  PrependMagickMethod(DefineImageProperty)
+#define DefineImageRegistry  PrependMagickMethod(DefineImageRegistry)
+#define DelegateComponentGenesis  PrependMagickMethod(DelegateComponentGenesis)
+#define DelegateComponentTerminus  PrependMagickMethod(DelegateComponentTerminus)
+#define DeleteImageArtifact  PrependMagickMethod(DeleteImageArtifact)
+#define DeleteImageAttribute  PrependMagickMethod(DeleteImageAttribute)
+#define DeleteImageFromList  PrependMagickMethod(DeleteImageFromList)
+#define DeleteImageList  PrependMagickMethod(DeleteImageList)
+#define DeleteImageOption  PrependMagickMethod(DeleteImageOption)
+#define DeleteImageProfile  PrependMagickMethod(DeleteImageProfile)
+#define DeleteImageProperty  PrependMagickMethod(DeleteImageProperty)
+#define DeleteImageRegistry  PrependMagickMethod(DeleteImageRegistry)
+#define DeleteImages  PrependMagickMethod(DeleteImages)
+#define DeleteMagickRegistry  PrependMagickMethod(DeleteMagickRegistry)
+#define DeleteNodeByValueFromSplayTree  PrependMagickMethod(DeleteNodeByValueFromSplayTree)
+#define DeleteNodeFromSplayTree  PrependMagickMethod(DeleteNodeFromSplayTree)
+#define DescribeImage  PrependMagickMethod(DescribeImage)
+#define DeskewImage  PrependMagickMethod(DeskewImage)
+#define DespeckleImage  PrependMagickMethod(DespeckleImage)
+#define DestroyBlob  PrependMagickMethod(DestroyBlob)
+#define DestroyCacheView  PrependMagickMethod(DestroyCacheView)
+#define DestroyConfigureOptions  PrependMagickMethod(DestroyConfigureOptions)
+#define DestroyDrawInfo  PrependMagickMethod(DestroyDrawInfo)
+#define DestroyExceptionInfo  PrependMagickMethod(DestroyExceptionInfo)
+#define DestroyFxInfo  PrependMagickMethod(DestroyFxInfo)
+#define DestroyHashmap  PrependMagickMethod(DestroyHashmap)
+#define DestroyImageArtifacts  PrependMagickMethod(DestroyImageArtifacts)
+#define DestroyImageAttributes  PrependMagickMethod(DestroyImageAttributes)
+#define DestroyImageInfo  PrependMagickMethod(DestroyImageInfo)
+#define DestroyImageList  PrependMagickMethod(DestroyImageList)
+#define DestroyImageOptions  PrependMagickMethod(DestroyImageOptions)
+#define DestroyImagePixels  PrependMagickMethod(DestroyImagePixels)
+#define DestroyImage  PrependMagickMethod(DestroyImage)
+#define DestroyImageProfiles  PrependMagickMethod(DestroyImageProfiles)
+#define DestroyImageProperties  PrependMagickMethod(DestroyImageProperties)
+#define DestroyImages  PrependMagickMethod(DestroyImages)
+#define DestroyKernel  PrependMagickMethod(DestroyKernel)
+#define DestroyLinkedList  PrependMagickMethod(DestroyLinkedList)
+#define DestroyLocaleOptions  PrependMagickMethod(DestroyLocaleOptions)
+#define DestroyMagickMemory  PrependMagickMethod(DestroyMagickMemory)
+#define DestroyMagick  PrependMagickMethod(DestroyMagick)
+#define DestroyMagickRegistry  PrependMagickMethod(DestroyMagickRegistry)
+#define DestroyMontageInfo  PrependMagickMethod(DestroyMontageInfo)
+#define DestroyPixelCacheNexus  PrependMagickMethod(DestroyPixelCacheNexus)
+#define DestroyPixelCache  PrependMagickMethod(DestroyPixelCache)
+#define DestroyQuantizeInfo  PrependMagickMethod(DestroyQuantizeInfo)
+#define DestroyQuantumInfo  PrependMagickMethod(DestroyQuantumInfo)
+#define DestroyRandomInfo  PrependMagickMethod(DestroyRandomInfo)
+#define DestroyResampleFilter  PrependMagickMethod(DestroyResampleFilter)
+#define DestroyResizeFilter  PrependMagickMethod(DestroyResizeFilter)
+#define DestroySemaphoreInfo  PrependMagickMethod(DestroySemaphoreInfo)
+#define DestroySignatureInfo  PrependMagickMethod(DestroySignatureInfo)
+#define DestroySplayTree  PrependMagickMethod(DestroySplayTree)
+#define DestroyStreamInfo  PrependMagickMethod(DestroyStreamInfo)
+#define DestroyStringInfo  PrependMagickMethod(DestroyStringInfo)
+#define DestroyStringList  PrependMagickMethod(DestroyStringList)
+#define DestroyString  PrependMagickMethod(DestroyString)
+#define DestroyThresholdMap  PrependMagickMethod(DestroyThresholdMap)
+#define DestroyTimerInfo  PrependMagickMethod(DestroyTimerInfo)
+#define DestroyTokenInfo  PrependMagickMethod(DestroyTokenInfo)
+#define DestroyXMLTree  PrependMagickMethod(DestroyXMLTree)
+#define DestroyXResources  PrependMagickMethod(DestroyXResources)
+#define DestroyXWidget  PrependMagickMethod(DestroyXWidget)
+#define DetachBlob  PrependMagickMethod(DetachBlob)
+#define DisassociateImageStream  PrependMagickMethod(DisassociateImageStream)
+#define DispatchImage  PrependMagickMethod(DispatchImage)
+#define DisplayImages  PrependMagickMethod(DisplayImages)
+#define DisposeImages  PrependMagickMethod(DisposeImages)
+#define DistortImage  PrependMagickMethod(DistortImage)
+#define DrawAffineImage  PrependMagickMethod(DrawAffineImage)
+#define DrawClipPath  PrependMagickMethod(DrawClipPath)
+#define DrawGradientImage  PrependMagickMethod(DrawGradientImage)
+#define DrawImage  PrependMagickMethod(DrawImage)
+#define DrawPatternPath  PrependMagickMethod(DrawPatternPath)
+#define DrawPrimitive  PrependMagickMethod(DrawPrimitive)
+#define DuplicateBlob  PrependMagickMethod(DuplicateBlob)
+#define EdgeImage  PrependMagickMethod(EdgeImage)
+#define EmbossImage  PrependMagickMethod(EmbossImage)
+#define EncipherImage  PrependMagickMethod(EncipherImage)
+#define EnhanceImage  PrependMagickMethod(EnhanceImage)
+#define EOFBlob  PrependMagickMethod(EOFBlob)
+#define EqualizeImageChannel  PrependMagickMethod(EqualizeImageChannel)
+#define EqualizeImage  PrependMagickMethod(EqualizeImage)
+#define EscapeString  PrependMagickMethod(EscapeString)
+#define EvaluateImageChannel  PrependMagickMethod(EvaluateImageChannel)
+#define EvaluateImage  PrependMagickMethod(EvaluateImage)
+#define ExcerptImage  PrependMagickMethod(ExcerptImage)
+#define ExpandAffine  PrependMagickMethod(ExpandAffine)
+#define ExpandFilename  PrependMagickMethod(ExpandFilename)
+#define ExpandFilenames  PrependMagickMethod(ExpandFilenames)
+#define ExportImagePixels  PrependMagickMethod(ExportImagePixels)
+#define ExportQuantumPixels  PrependMagickMethod(ExportQuantumPixels)
+#define ExtentImage  PrependMagickMethod(ExtentImage)
+#define ExtractSubimageFromImage  PrependMagickMethod(ExtractSubimageFromImage)
+#define FileToBlob  PrependMagickMethod(FileToBlob)
+#define FileToImage  PrependMagickMethod(FileToImage)
+#define FileToStringInfo  PrependMagickMethod(FileToStringInfo)
+#define FileToString  PrependMagickMethod(FileToString)
+#define FilterImageChannel  PrependMagickMethod(FilterImageChannel)
+#define FilterImage  PrependMagickMethod(FilterImage)
+#define FinalizeSignature  PrependMagickMethod(FinalizeSignature)
+#define FlattenImages  PrependMagickMethod(FlattenImages)
+#define FlipImage  PrependMagickMethod(FlipImage)
+#define FloodfillPaintImage  PrependMagickMethod(FloodfillPaintImage)
+#define FlopImage  PrependMagickMethod(FlopImage)
+#define FormatImageAttributeList  PrependMagickMethod(FormatImageAttributeList)
+#define FormatImageAttribute  PrependMagickMethod(FormatImageAttribute)
+#define FormatImagePropertyList  PrependMagickMethod(FormatImagePropertyList)
+#define FormatImageProperty  PrependMagickMethod(FormatImageProperty)
+#define FormatMagickCaption  PrependMagickMethod(FormatMagickCaption)
+#define FormatMagickSize  PrependMagickMethod(FormatMagickSize)
+#define FormatLocaleStringList  PrependMagickMethod(FormatLocaleStringList)
+#define FormatLocaleString  PrependMagickMethod(FormatLocaleString)
+#define FormatMagickTime  PrependMagickMethod(FormatMagickTime)
+#define FormatStringList  PrependMagickMethod(FormatStringList)
+#define FormatString  PrependMagickMethod(FormatString)
+#define ForwardFourierTransformImage  PrependMagickMethod(ForwardFourierTransformImage)
+#define FrameImage  PrependMagickMethod(FrameImage)
+#define FunctionImageChannel  PrependMagickMethod(FunctionImageChannel)
+#define FunctionImage  PrependMagickMethod(FunctionImage)
+#define FuzzyColorCompare  PrependMagickMethod(FuzzyColorCompare)
+#define FuzzyColorMatch  PrependMagickMethod(FuzzyColorMatch)
+#define FuzzyOpacityCompare  PrependMagickMethod(FuzzyOpacityCompare)
+#define FxEvaluateChannelExpression  PrependMagickMethod(FxEvaluateChannelExpression)
+#define FxEvaluateExpression  PrependMagickMethod(FxEvaluateExpression)
+#define FxImageChannel  PrependMagickMethod(FxImageChannel)
+#define FxImage  PrependMagickMethod(FxImage)
+#define FxPreprocessExpression  PrependMagickMethod(FxPreprocessExpression)
+#define GammaImageChannel  PrependMagickMethod(GammaImageChannel)
+#define GammaImage  PrependMagickMethod(GammaImage)
+#define GaussianBlurImageChannel  PrependMagickMethod(GaussianBlurImageChannel)
+#define GaussianBlurImage  PrependMagickMethod(GaussianBlurImage)
+#define GaussJordanElimination  PrependMagickMethod(GaussJordanElimination)
+#define GenerateDifferentialNoise  PrependMagickMethod(GenerateDifferentialNoise)
+#define GetAffineMatrix  PrependMagickMethod(GetAffineMatrix)
+#define GetAuthenticMetacontent  PrependMagickMethod(GetAuthenticMetacontent)
+#define GetAuthenticPixelCacheNexus  PrependMagickMethod(GetAuthenticPixelCacheNexus)
+#define GetAuthenticPixelQueue  PrependMagickMethod(GetAuthenticPixelQueue)
+#define GetAuthenticPixels  PrependMagickMethod(GetAuthenticPixels)
+#define GetBlobError  PrependMagickMethod(GetBlobError)
+#define GetBlobFileHandle  PrependMagickMethod(GetBlobFileHandle)
+#define GetBlobInfo  PrependMagickMethod(GetBlobInfo)
+#define GetBlobProperties  PrependMagickMethod(GetBlobProperties)
+#define GetBlobSize  PrependMagickMethod(GetBlobSize)
+#define GetBlobStreamData  PrependMagickMethod(GetBlobStreamData)
+#define GetBlobStreamHandler  PrependMagickMethod(GetBlobStreamHandler)
+#define GetCacheViewAuthenticMetacontent  PrependMagickMethod(GetCacheViewAuthenticMetacontent)
+#define GetCacheViewAuthenticPixelQueue  PrependMagickMethod(GetCacheViewAuthenticPixelQueue)
+#define GetCacheViewAuthenticPixels  PrependMagickMethod(GetCacheViewAuthenticPixels)
+#define GetCacheViewColorspace  PrependMagickMethod(GetCacheViewColorspace)
+#define GetCacheViewException  PrependMagickMethod(GetCacheViewException)
+#define GetCacheViewExtent  PrependMagickMethod(GetCacheViewExtent)
+#define GetCacheViewIndexes  PrependMagickMethod(GetCacheViewIndexes)
+#define GetCacheViewPixels  PrependMagickMethod(GetCacheViewPixels)
+#define GetCacheView  PrependMagickMethod(GetCacheView)
+#define GetCacheViewStorageClass  PrependMagickMethod(GetCacheViewStorageClass)
+#define GetCacheViewVirtualMetacontent  PrependMagickMethod(GetCacheViewVirtualMetacontent)
+#define GetCacheViewVirtualPixelQueue  PrependMagickMethod(GetCacheViewVirtualPixelQueue)
+#define GetCacheViewVirtualPixels  PrependMagickMethod(GetCacheViewVirtualPixels)
+#define GetClientName  PrependMagickMethod(GetClientName)
+#define GetClientPath  PrependMagickMethod(GetClientPath)
+#define GetCoderInfoList  PrependMagickMethod(GetCoderInfoList)
+#define GetCoderInfo  PrependMagickMethod(GetCoderInfo)
+#define GetCoderList  PrependMagickMethod(GetCoderList)
+#define GetColorInfoList  PrependMagickMethod(GetColorInfoList)
+#define GetColorInfo  PrependMagickMethod(GetColorInfo)
+#define GetColorList  PrependMagickMethod(GetColorList)
+#define GetColorTuple  PrependMagickMethod(GetColorTuple)
+#define GetConfigureBlob  PrependMagickMethod(GetConfigureBlob)
+#define GetConfigureInfoList  PrependMagickMethod(GetConfigureInfoList)
+#define GetConfigureInfo  PrependMagickMethod(GetConfigureInfo)
+#define GetConfigureList  PrependMagickMethod(GetConfigureList)
+#define GetConfigureOption  PrependMagickMethod(GetConfigureOption)
+#define GetConfigureOptions  PrependMagickMethod(GetConfigureOptions)
+#define GetConfigurePaths  PrependMagickMethod(GetConfigurePaths)
+#define GetConfigureValue  PrependMagickMethod(GetConfigureValue)
+#define GetDelegateCommand  PrependMagickMethod(GetDelegateCommand)
+#define GetDelegateCommands  PrependMagickMethod(GetDelegateCommands)
+#define GetDelegateInfoList  PrependMagickMethod(GetDelegateInfoList)
+#define GetDelegateInfo  PrependMagickMethod(GetDelegateInfo)
+#define GetDelegateList  PrependMagickMethod(GetDelegateList)
+#define GetDelegateMode  PrependMagickMethod(GetDelegateMode)
+#define GetDelegateThreadSupport  PrependMagickMethod(GetDelegateThreadSupport)
+#define GetDrawInfo  PrependMagickMethod(GetDrawInfo)
+#define GetElapsedTime  PrependMagickMethod(GetElapsedTime)
+#define GetEnvironmentValue  PrependMagickMethod(GetEnvironmentValue)
+#define GetExceptionInfo  PrependMagickMethod(GetExceptionInfo)
+#define GetExceptionMessage  PrependMagickMethod(GetExceptionMessage)
+#define GetExecutionPath  PrependMagickMethod(GetExecutionPath)
+#define GetFirstImageInList  PrependMagickMethod(GetFirstImageInList)
+#define GetGeometry  PrependMagickMethod(GetGeometry)
+#define GetImageAlphaChannel  PrependMagickMethod(GetImageAlphaChannel)
+#define GetImageArtifact  PrependMagickMethod(GetImageArtifact)
+#define GetImageAttribute  PrependMagickMethod(GetImageAttribute)
+#define GetImageBoundingBox  PrependMagickMethod(GetImageBoundingBox)
+#define GetImageChannelDepth  PrependMagickMethod(GetImageChannelDepth)
+#define GetImageChannelDistortion  PrependMagickMethod(GetImageChannelDistortion)
+#define GetImageChannelDistortions  PrependMagickMethod(GetImageChannelDistortions)
+#define GetImageChannelExtrema  PrependMagickMethod(GetImageChannelExtrema)
+#define GetImageChannelKurtosis  PrependMagickMethod(GetImageChannelKurtosis)
+#define GetImageChannelMean  PrependMagickMethod(GetImageChannelMean)
+#define GetImageChannelRange  PrependMagickMethod(GetImageChannelRange)
+#define GetImageChannelStatistics  PrependMagickMethod(GetImageChannelStatistics)
+#define GetImageClipMask  PrependMagickMethod(GetImageClipMask)
+#define GetImageClippingPathAttribute  PrependMagickMethod(GetImageClippingPathAttribute)
+#define GetImageDecoder  PrependMagickMethod(GetImageDecoder)
+#define GetImageDepth  PrependMagickMethod(GetImageDepth)
+#define GetImageDistortion  PrependMagickMethod(GetImageDistortion)
+#define GetImageDynamicThreshold  PrependMagickMethod(GetImageDynamicThreshold)
+#define GetImageEncoder  PrependMagickMethod(GetImageEncoder)
+#define GetImageException  PrependMagickMethod(GetImageException)
+#define GetImageExtent  PrependMagickMethod(GetImageExtent)
+#define GetImageExtrema  PrependMagickMethod(GetImageExtrema)
+#define GetImageFromList  PrependMagickMethod(GetImageFromList)
+#define GetImageFromMagickRegistry  PrependMagickMethod(GetImageFromMagickRegistry)
+#define GetImageGeometry  PrependMagickMethod(GetImageGeometry)
+#define GetImageHistogram  PrependMagickMethod(GetImageHistogram)
+#define GetImageIndexInList  PrependMagickMethod(GetImageIndexInList)
+#define GetImageInfoFile  PrependMagickMethod(GetImageInfoFile)
+#define GetImageInfo  PrependMagickMethod(GetImageInfo)
+#define GetImageKurtosis  PrependMagickMethod(GetImageKurtosis)
+#define GetImageListIndex  PrependMagickMethod(GetImageListIndex)
+#define GetImageListLength  PrependMagickMethod(GetImageListLength)
+#define GetImageList  PrependMagickMethod(GetImageList)
+#define GetImageListSize  PrependMagickMethod(GetImageListSize)
+#define GetImageMagick  PrependMagickMethod(GetImageMagick)
+#define GetImageMask  PrependMagickMethod(GetImageMask)
+#define GetImageMean  PrependMagickMethod(GetImageMean)
+#define GetImageOption  PrependMagickMethod(GetImageOption)
+#define GetImagePixelCache  PrependMagickMethod(GetImagePixelCache)
+#define GetImagePixels  PrependMagickMethod(GetImagePixels)
+#define GetImageProfile  PrependMagickMethod(GetImageProfile)
+#define GetImageProperty  PrependMagickMethod(GetImageProperty)
+#define GetImageQuantizeError  PrependMagickMethod(GetImageQuantizeError)
+#define GetImageQuantumDepth  PrependMagickMethod(GetImageQuantumDepth)
+#define GetImageRange  PrependMagickMethod(GetImageRange)
+#define GetImageReferenceCount  PrependMagickMethod(GetImageReferenceCount)
+#define GetImageRegistry  PrependMagickMethod(GetImageRegistry)
+#define GetImageTotalInkDensity  PrependMagickMethod(GetImageTotalInkDensity)
+#define GetImageType  PrependMagickMethod(GetImageType)
+#define GetImageVirtualPixelMethod  PrependMagickMethod(GetImageVirtualPixelMethod)
+#define GetIndexes  PrependMagickMethod(GetIndexes)
+#define GetLastImageInList  PrependMagickMethod(GetLastImageInList)
+#define GetLastValueInLinkedList  PrependMagickMethod(GetLastValueInLinkedList)
+#define GetLocaleExceptionMessage  PrependMagickMethod(GetLocaleExceptionMessage)
+#define GetLocaleInfoList  PrependMagickMethod(GetLocaleInfoList)
+#define GetLocaleInfo_  PrependMagickMethod(GetLocaleInfo_)
+#define GetLocaleList  PrependMagickMethod(GetLocaleList)
+#define GetLocaleMessage  PrependMagickMethod(GetLocaleMessage)
+#define GetLocaleOptions  PrependMagickMethod(GetLocaleOptions)
+#define GetLocaleValue  PrependMagickMethod(GetLocaleValue)
+#define GetLogInfoList  PrependMagickMethod(GetLogInfoList)
+#define GetLogList  PrependMagickMethod(GetLogList)
+#define GetLogName  PrependMagickMethod(GetLogName)
+#define GetMagicInfoList  PrependMagickMethod(GetMagicInfoList)
+#define GetMagicInfo  PrependMagickMethod(GetMagicInfo)
+#define GetMagickAdjoin  PrependMagickMethod(GetMagickAdjoin)
+#define GetMagickBlobSupport  PrependMagickMethod(GetMagickBlobSupport)
+#define GetMagickCopyright  PrependMagickMethod(GetMagickCopyright)
+#define GetMagickDescription  PrependMagickMethod(GetMagickDescription)
+#define GetMagickEndianSupport  PrependMagickMethod(GetMagickEndianSupport)
+#define GetMagickFeatures  PrependMagickMethod(GetMagickFeatures)
+#define GetMagickGeometry  PrependMagickMethod(GetMagickGeometry)
+#define GetMagickHomeURL  PrependMagickMethod(GetMagickHomeURL)
+#define GetMagickInfoList  PrependMagickMethod(GetMagickInfoList)
+#define GetMagickInfo  PrependMagickMethod(GetMagickInfo)
+#define GetMagickList  PrependMagickMethod(GetMagickList)
+#define GetMagickMemoryMethods  PrependMagickMethod(GetMagickMemoryMethods)
+#define GetCommandOptions  PrependMagickMethod(GetCommandOptions)
+#define GetMagickPackageName  PrependMagickMethod(GetMagickPackageName)
+#define GetMagickPageSize  PrependMagickMethod(GetMagickPageSize)
+#define GetPixelInfo  PrependMagickMethod(GetPixelInfo)
+#define GetMagickProperty  PrependMagickMethod(GetMagickProperty)
+#define GetMagickQuantumDepth  PrependMagickMethod(GetMagickQuantumDepth)
+#define GetMagickQuantumRange  PrependMagickMethod(GetMagickQuantumRange)
+#define GetMagickRawSupport  PrependMagickMethod(GetMagickRawSupport)
+#define GetMagickRegistry  PrependMagickMethod(GetMagickRegistry)
+#define GetMagickReleaseDate  PrependMagickMethod(GetMagickReleaseDate)
+#define GetMagickResourceLimit  PrependMagickMethod(GetMagickResourceLimit)
+#define GetMagickResource  PrependMagickMethod(GetMagickResource)
+#define GetMagickSeekableStream  PrependMagickMethod(GetMagickSeekableStream)
+#define GetMagickThreadSupport  PrependMagickMethod(GetMagickThreadSupport)
+#define GetMagickToken  PrependMagickMethod(GetMagickToken)
+#define GetMagickVersion  PrependMagickMethod(GetMagickVersion)
+#define GetMagicList  PrependMagickMethod(GetMagicList)
+#define GetMagicName  PrependMagickMethod(GetMagicName)
+#define GetMimeDescription  PrependMagickMethod(GetMimeDescription)
+#define GetMimeInfoList  PrependMagickMethod(GetMimeInfoList)
+#define GetMimeInfo  PrependMagickMethod(GetMimeInfo)
+#define GetMimeList  PrependMagickMethod(GetMimeList)
+#define GetMimeType  PrependMagickMethod(GetMimeType)
+#define GetMonitorHandler  PrependMagickMethod(GetMonitorHandler)
+#define GetMontageInfo  PrependMagickMethod(GetMontageInfo)
+#define GetMultilineTypeMetrics  PrependMagickMethod(GetMultilineTypeMetrics)
+#define GetNextImageArtifact  PrependMagickMethod(GetNextImageArtifact)
+#define GetNextImageAttribute  PrependMagickMethod(GetNextImageAttribute)
+#define GetNextImageInList  PrependMagickMethod(GetNextImageInList)
+#define GetNextImageOption  PrependMagickMethod(GetNextImageOption)
+#define GetNextImage  PrependMagickMethod(GetNextImage)
+#define GetNextImageProfile  PrependMagickMethod(GetNextImageProfile)
+#define GetNextImageProperty  PrependMagickMethod(GetNextImageProperty)
+#define GetNextImageRegistry  PrependMagickMethod(GetNextImageRegistry)
+#define GetNextKeyInHashmap  PrependMagickMethod(GetNextKeyInHashmap)
+#define GetNextKeyInSplayTree  PrependMagickMethod(GetNextKeyInSplayTree)
+#define GetNextValueInHashmap  PrependMagickMethod(GetNextValueInHashmap)
+#define GetNextValueInLinkedList  PrependMagickMethod(GetNextValueInLinkedList)
+#define GetNextValueInSplayTree  PrependMagickMethod(GetNextValueInSplayTree)
+#define GetNextXMLTreeTag  PrependMagickMethod(GetNextXMLTreeTag)
+#define GetNumberColors  PrependMagickMethod(GetNumberColors)
+#define GetNumberOfElementsInLinkedList  PrependMagickMethod(GetNumberOfElementsInLinkedList)
+#define GetNumberOfEntriesInHashmap  PrependMagickMethod(GetNumberOfEntriesInHashmap)
+#define GetNumberOfNodesInSplayTree  PrependMagickMethod(GetNumberOfNodesInSplayTree)
+#define GetNumberScenes  PrependMagickMethod(GetNumberScenes)
+#define GetOneAuthenticPixel  PrependMagickMethod(GetOneAuthenticPixel)
+#define GetOneCacheViewAuthenticPixel  PrependMagickMethod(GetOneCacheViewAuthenticPixel)
+#define GetOneCacheViewVirtualMethodPixel  PrependMagickMethod(GetOneCacheViewVirtualMethodPixel)
+#define GetOneCacheViewVirtualPixel  PrependMagickMethod(GetOneCacheViewVirtualPixel)
+#define GetOnePixel  PrependMagickMethod(GetOnePixel)
+#define GetOneVirtualMagickPixel  PrependMagickMethod(GetOneVirtualMagickPixel)
+#define GetOneVirtualMethodPixel  PrependMagickMethod(GetOneVirtualMethodPixel)
+#define GetOneVirtualPixel  PrependMagickMethod(GetOneVirtualPixel)
+#define GetOptimalKernelWidth1D  PrependMagickMethod(GetOptimalKernelWidth1D)
+#define GetOptimalKernelWidth2D  PrependMagickMethod(GetOptimalKernelWidth2D)
+#define GetOptimalKernelWidth  PrependMagickMethod(GetOptimalKernelWidth)
+#define GetPageGeometry  PrependMagickMethod(GetPageGeometry)
+#define GetPathAttributes  PrependMagickMethod(GetPathAttributes)
+#define GetPathComponent  PrependMagickMethod(GetPathComponent)
+#define GetPathComponents  PrependMagickMethod(GetPathComponents)
+#define GetPixelCacheColorspace  PrependMagickMethod(GetPixelCacheColorspace)
+#define GetPixelCacheMethods  PrependMagickMethod(GetPixelCacheMethods)
+#define GetPixelCacheNexusExtent  PrependMagickMethod(GetPixelCacheNexusExtent)
+#define GetPixelCacheNexusMetacontent  PrependMagickMethod(GetPixelCacheNexusMetacontent)
+#define GetPixelCacheNexusPixels  PrependMagickMethod(GetPixelCacheNexusPixels)
+#define GetPixelCachePixels  PrependMagickMethod(GetPixelCachePixels)
+#define GetPixelCacheStorageClass  PrependMagickMethod(GetPixelCacheStorageClass)
+#define GetPixelCacheTileSize  PrependMagickMethod(GetPixelCacheTileSize)
+#define GetPixelCacheType  PrependMagickMethod(GetPixelCacheType)
+#define GetPixelCacheVirtualMethod  PrependMagickMethod(GetPixelCacheVirtualMethod)
+#define GetPixels  PrependMagickMethod(GetPixels)
+#define GetPolicyInfoList  PrependMagickMethod(GetPolicyInfoList)
+#define GetPolicyList  PrependMagickMethod(GetPolicyList)
+#define GetPolicyValue  PrependMagickMethod(GetPolicyValue)
+#define GetPreviousImageInList  PrependMagickMethod(GetPreviousImageInList)
+#define GetPreviousImage  PrependMagickMethod(GetPreviousImage)
+#define GetPseudoRandomValue  PrependMagickMethod(GetPseudoRandomValue)
+#define GetQuantizeInfo  PrependMagickMethod(GetQuantizeInfo)
+#define GetQuantumExtent  PrependMagickMethod(GetQuantumExtent)
+#define GetQuantumInfo  PrependMagickMethod(GetQuantumInfo)
+#define GetQuantumPixels  PrependMagickMethod(GetQuantumPixels)
+#define GetQuantumType  PrependMagickMethod(GetQuantumType)
+#define GetRandomKey  PrependMagickMethod(GetRandomKey)
+#define GetRandomValue  PrependMagickMethod(GetRandomValue)
+#define GetResizeFilterSupport  PrependMagickMethod(GetResizeFilterSupport)
+#define GetResizeFilterWeight  PrependMagickMethod(GetResizeFilterWeight)
+#define GetSignatureBlocksize  PrependMagickMethod(GetSignatureBlocksize)
+#define GetSignatureDigest  PrependMagickMethod(GetSignatureDigest)
+#define GetSignatureDigestsize  PrependMagickMethod(GetSignatureDigestsize)
+#define GetStreamInfoClientData  PrependMagickMethod(GetStreamInfoClientData)
+#define GetStringInfoDatum  PrependMagickMethod(GetStringInfoDatum)
+#define GetStringInfoLength  PrependMagickMethod(GetStringInfoLength)
+#define GetStringInfoPath  PrependMagickMethod(GetStringInfoPath)
+#define GetThresholdMapFile  PrependMagickMethod(GetThresholdMapFile)
+#define GetThresholdMap  PrependMagickMethod(GetThresholdMap)
+#define GetTimerInfo  PrependMagickMethod(GetTimerInfo)
+#define GetTypeInfoByFamily  PrependMagickMethod(GetTypeInfoByFamily)
+#define GetTypeInfoList  PrependMagickMethod(GetTypeInfoList)
+#define GetTypeInfo  PrependMagickMethod(GetTypeInfo)
+#define GetTypeList  PrependMagickMethod(GetTypeList)
+#define GetTypeMetrics  PrependMagickMethod(GetTypeMetrics)
+#define GetUserTime  PrependMagickMethod(GetUserTime)
+#define GetValueFromHashmap  PrependMagickMethod(GetValueFromHashmap)
+#define GetValueFromLinkedList  PrependMagickMethod(GetValueFromLinkedList)
+#define GetValueFromSplayTree  PrependMagickMethod(GetValueFromSplayTree)
+#define GetVirtualMetacontentFromNexus  PrependMagickMethod(GetVirtualMetacontentFromNexus)
+#define GetVirtualMetacontent  PrependMagickMethod(GetVirtualMetacontent)
+#define GetVirtualPixelQueue  PrependMagickMethod(GetVirtualPixelQueue)
+#define GetVirtualPixelsFromNexus  PrependMagickMethod(GetVirtualPixelsFromNexus)
+#define GetVirtualPixelsNexus  PrependMagickMethod(GetVirtualPixelsNexus)
+#define GetVirtualPixels  PrependMagickMethod(GetVirtualPixels)
+#define GetXMLTreeAttribute  PrependMagickMethod(GetXMLTreeAttribute)
+#define GetXMLTreeAttributes  PrependMagickMethod(GetXMLTreeAttributes)
+#define GetXMLTreeChild  PrependMagickMethod(GetXMLTreeChild)
+#define GetXMLTreeContent  PrependMagickMethod(GetXMLTreeContent)
+#define GetXMLTreeOrdered  PrependMagickMethod(GetXMLTreeOrdered)
+#define GetXMLTreePath  PrependMagickMethod(GetXMLTreePath)
+#define GetXMLTreeProcessingInstructions  PrependMagickMethod(GetXMLTreeProcessingInstructions)
+#define GetXMLTreeSibling  PrependMagickMethod(GetXMLTreeSibling)
+#define GetXMLTreeTag  PrependMagickMethod(GetXMLTreeTag)
+#define GlobExpression  PrependMagickMethod(GlobExpression)
+#define GradientImage  PrependMagickMethod(GradientImage)
+#define GravityAdjustGeometry  PrependMagickMethod(GravityAdjustGeometry)
+#define HaldClutImageChannel  PrependMagickMethod(HaldClutImageChannel)
+#define HaldClutImage  PrependMagickMethod(HaldClutImage)
+#define HashPointerType  PrependMagickMethod(HashPointerType)
+#define HashStringInfoType  PrependMagickMethod(HashStringInfoType)
+#define HashStringType  PrependMagickMethod(HashStringType)
+#define HSLTransform  PrependMagickMethod(HSLTransform)
+#define HuffmanDecodeImage  PrependMagickMethod(HuffmanDecodeImage)
+#define HuffmanEncodeImage  PrependMagickMethod(HuffmanEncodeImage)
+#define IdentifyImage  PrependMagickMethod(IdentifyImage)
+#define IdentityAffine  PrependMagickMethod(IdentityAffine)
+#define ImageListToArray  PrependMagickMethod(ImageListToArray)
+#define ImagesToBlob  PrependMagickMethod(ImagesToBlob)
+#define ImageToBlob  PrependMagickMethod(ImageToBlob)
+#define ImageToFile  PrependMagickMethod(ImageToFile)
+#define ImplodeImage  PrependMagickMethod(ImplodeImage)
+#define ImportImagePixels  PrependMagickMethod(ImportImagePixels)
+#define ImportQuantumPixels  PrependMagickMethod(ImportQuantumPixels)
+#define increase  PrependMagickMethod(increase)
+#define InheritException  PrependMagickMethod(InheritException)
+#define InitializeMagick  PrependMagickMethod(InitializeMagick)
+#define InitializeSignature  PrependMagickMethod(InitializeSignature)
+#define InjectImageBlob  PrependMagickMethod(InjectImageBlob)
+#define InsertImageInList  PrependMagickMethod(InsertImageInList)
+#define InsertTagIntoXMLTree  PrependMagickMethod(InsertTagIntoXMLTree)
+#define InsertValueInLinkedList  PrependMagickMethod(InsertValueInLinkedList)
+#define InsertValueInSortedLinkedList  PrependMagickMethod(InsertValueInSortedLinkedList)
+#define InterpolatePixelColor  PrependMagickMethod(InterpolatePixelColor)
+#define InterpretImageAttributes  PrependMagickMethod(InterpretImageAttributes)
+#define InterpretImageFilename  PrependMagickMethod(InterpretImageFilename)
+#define InterpretImageProperties  PrependMagickMethod(InterpretImageProperties)
+#define InverseFourierTransformImage  PrependMagickMethod(InverseFourierTransformImage)
+#define InvokeDelegate  PrependMagickMethod(InvokeDelegate)
+#define InvokeDynamicImageFilter  PrependMagickMethod(InvokeDynamicImageFilter)
+#define IsBlobExempt  PrependMagickMethod(IsBlobExempt)
+#define IsBlobSeekable  PrependMagickMethod(IsBlobSeekable)
+#define IsBlobTemporary  PrependMagickMethod(IsBlobTemporary)
+#define IsFuzzyEquivalencePixelPacket  PrependMagickMethod(IsFuzzyEquivalencePixelPacket)
+#define IsEventLogging  PrependMagickMethod(IsEventLogging)
+#define IsGeometry  PrependMagickMethod(IsGeometry)
+#define IsGlob  PrependMagickMethod(IsGlob)
+#define IsImageGray  PrependMagickMethod(IsImageGray)
+#define IsHashmapEmpty  PrependMagickMethod(IsHashmapEmpty)
+#define IsHighDynamicRangeImage  PrependMagickMethod(IsHighDynamicRangeImage)
+#define IsHistogramImage  PrependMagickMethod(IsHistogramImage)
+#define IsImageObject  PrependMagickMethod(IsImageObject)
+#define IsImagesEqual  PrependMagickMethod(IsImagesEqual)
+#define IsEquivalentImage  PrependMagickMethod(IsEquivalentImage)
+#define IsLinkedListEmpty  PrependMagickMethod(IsLinkedListEmpty)
+#define IsFuzzyEquivalencePixelInfo  PrependMagickMethod(IsFuzzyEquivalencePixelInfo)
+#define IsMagickConflict  PrependMagickMethod(IsMagickConflict)
+#define IsMagickInstantiated  PrependMagickMethod(IsMagickInstantiated)
+#define IsCommandOption  PrependMagickMethod(IsCommandOption)
+#define IsMagickTrue  PrependMagickMethod(IsMagickTrue)
+#define IsImageMonochrome  PrependMagickMethod(IsImageMonochrome)
+#define IsEquivalentAlpha  PrependMagickMethod(IsEquivalentAlpha)
+#define IsImageOpaque  PrependMagickMethod(IsImageOpaque)
+#define IsPaletteImage  PrependMagickMethod(IsPaletteImage)
+#define IsPathAccessible  PrependMagickMethod(IsPathAccessible)
+#define IsRightsAuthorized  PrependMagickMethod(IsRightsAuthorized)
+#define IsSceneGeometry  PrependMagickMethod(IsSceneGeometry)
+#define IsSubimage  PrependMagickMethod(IsSubimage)
+#define IsTaintImage  PrependMagickMethod(IsTaintImage)
+#define KernelNormalize  PrependMagickMethod(KernelNormalize)
+#define KernelPrint  PrependMagickMethod(KernelPrint)
+#define KernelRotate  PrependMagickMethod(KernelRotate)
+#define LeastSquaresAddTerms  PrependMagickMethod(LeastSquaresAddTerms)
+#define LevelColorsImageChannel  PrependMagickMethod(LevelColorsImageChannel)
+#define LevelColorsImage  PrependMagickMethod(LevelColorsImage)
+#define LevelImageChannel  PrependMagickMethod(LevelImageChannel)
+#define LevelImageColors  PrependMagickMethod(LevelImageColors)
+#define LevelImage  PrependMagickMethod(LevelImage)
+#define LevelizeImageChannel  PrependMagickMethod(LevelizeImageChannel)
+#define LevelizeImage  PrependMagickMethod(LevelizeImage)
+#define LiberateMemory  PrependMagickMethod(LiberateMemory)
+#define LiberateSemaphoreInfo  PrependMagickMethod(LiberateSemaphoreInfo)
+#define LinearStretchImage  PrependMagickMethod(LinearStretchImage)
+#define LinkedListToArray  PrependMagickMethod(LinkedListToArray)
+#define LiquidRescaleImage  PrependMagickMethod(LiquidRescaleImage)
+#define ListCoderInfo  PrependMagickMethod(ListCoderInfo)
+#define ListColorInfo  PrependMagickMethod(ListColorInfo)
+#define ListConfigureInfo  PrependMagickMethod(ListConfigureInfo)
+#define ListDelegateInfo  PrependMagickMethod(ListDelegateInfo)
+#define ListFiles  PrependMagickMethod(ListFiles)
+#define ListLocaleInfo  PrependMagickMethod(ListLocaleInfo)
+#define ListLogInfo  PrependMagickMethod(ListLogInfo)
+#define ListMagicInfo  PrependMagickMethod(ListMagicInfo)
+#define ListMagickInfo  PrependMagickMethod(ListMagickInfo)
+#define ListCommandOptions  PrependMagickMethod(ListCommandOptions)
+#define ListMagickResourceInfo  PrependMagickMethod(ListMagickResourceInfo)
+#define ListMimeInfo  PrependMagickMethod(ListMimeInfo)
+#define ListModuleInfo  PrependMagickMethod(ListModuleInfo)
+#define ListPolicyInfo  PrependMagickMethod(ListPolicyInfo)
+#define ListThresholdMapFile  PrependMagickMethod(ListThresholdMapFile)
+#define ListThresholdMaps  PrependMagickMethod(ListThresholdMaps)
+#define ListTypeInfo  PrependMagickMethod(ListTypeInfo)
+#define LoadFontConfigFonts  PrependMagickMethod(LoadFontConfigFonts)
+#define LoadMimeLists  PrependMagickMethod(LoadMimeLists)
+#define LocaleCompare  PrependMagickMethod(LocaleCompare)
+#define LocaleComponentGenesis  PrependMagickMethod(LocaleComponentGenesis)
+#define LocaleComponentTerminus  PrependMagickMethod(LocaleComponentTerminus)
+#define LocaleLower  PrependMagickMethod(LocaleLower)
+#define LocaleNCompare  PrependMagickMethod(LocaleNCompare)
+#define LocaleUpper  PrependMagickMethod(LocaleUpper)
+#define LockSemaphoreInfo  PrependMagickMethod(LockSemaphoreInfo)
+#define LogComponentGenesis  PrependMagickMethod(LogComponentGenesis)
+#define LogComponentTerminus  PrependMagickMethod(LogComponentTerminus)
+#define LogMagickEventList  PrependMagickMethod(LogMagickEventList)
+#define LogMagickEvent  PrependMagickMethod(LogMagickEvent)
+#define LZWEncodeImage  PrependMagickMethod(LZWEncodeImage)
+#define MagicComponentGenesis  PrependMagickMethod(MagicComponentGenesis)
+#define MagicComponentTerminus  PrependMagickMethod(MagicComponentTerminus)
+#define MagickComponentGenesis  PrependMagickMethod(MagickComponentGenesis)
+#define MagickComponentTerminus  PrependMagickMethod(MagickComponentTerminus)
+#define MagickCoreGenesis  PrependMagickMethod(MagickCoreGenesis)
+#define MagickCoreTerminus  PrependMagickMethod(MagickCoreTerminus)
+#define MagickCreateThreadKey  PrependMagickMethod(MagickCreateThreadKey)
+#define MagickDeleteThreadKey  PrependMagickMethod(MagickDeleteThreadKey)
+#define MagickError  PrependMagickMethod(MagickError)
+#define MagickFatalError  PrependMagickMethod(MagickFatalError)
+#define MagickGetThreadValue  PrependMagickMethod(MagickGetThreadValue)
+#define MagickIncarnate  PrependMagickMethod(MagickIncarnate)
+#define MagickMonitor  PrependMagickMethod(MagickMonitor)
+#define CommandOptionToMnemonic  PrependMagickMethod(CommandOptionToMnemonic)
+#define MagickSetThreadValue  PrependMagickMethod(MagickSetThreadValue)
+#define MagickToMime  PrependMagickMethod(MagickToMime)
+#define MagickWarning  PrependMagickMethod(MagickWarning)
+#define MagnifyImage  PrependMagickMethod(MagnifyImage)
+#define MapBlob  PrependMagickMethod(MapBlob)
+#define MapImage  PrependMagickMethod(MapImage)
+#define MapImages  PrependMagickMethod(MapImages)
+#define MatteFloodfillImage  PrependMagickMethod(MatteFloodfillImage)
+#define MedianFilterImage  PrependMagickMethod(MedianFilterImage)
+#define MergeImageLayers  PrependMagickMethod(MergeImageLayers)
+#define MimeComponentGenesis  PrependMagickMethod(MimeComponentGenesis)
+#define MimeComponentTerminus  PrependMagickMethod(MimeComponentTerminus)
+#define MinifyImage  PrependMagickMethod(MinifyImage)
+#define MinMaxStretchImage  PrependMagickMethod(MinMaxStretchImage)
+#define ModifyImage  PrependMagickMethod(ModifyImage)
+#define ModulateImage  PrependMagickMethod(ModulateImage)
+#define MontageImageList  PrependMagickMethod(MontageImageList)
+#define MontageImages  PrependMagickMethod(MontageImages)
+#define MorphImages  PrependMagickMethod(MorphImages)
+#define MorphologyImage  PrependMagickMethod(MorphologyImage)
+#define MosaicImages  PrependMagickMethod(MosaicImages)
+#define MotionBlurImageChannel  PrependMagickMethod(MotionBlurImageChannel)
+#define MotionBlurImage  PrependMagickMethod(MotionBlurImage)
+#define MSBOrderLong  PrependMagickMethod(MSBOrderLong)
+#define MSBOrderShort  PrependMagickMethod(MSBOrderShort)
+#define MultilineCensus  PrependMagickMethod(MultilineCensus)
+#define NegateImageChannel  PrependMagickMethod(NegateImageChannel)
+#define NegateImage  PrependMagickMethod(NegateImage)
+#define NewHashmap  PrependMagickMethod(NewHashmap)
+#define NewImageList  PrependMagickMethod(NewImageList)
+#define NewLinkedList  PrependMagickMethod(NewLinkedList)
+#define NewMagickImage  PrependMagickMethod(NewMagickImage)
+#define NewSplayTree  PrependMagickMethod(NewSplayTree)
+#define NewXMLTree  PrependMagickMethod(NewXMLTree)
+#define NewXMLTreeTag  PrependMagickMethod(NewXMLTreeTag)
+#define NormalizeImageChannel  PrependMagickMethod(NormalizeImageChannel)
+#define NormalizeImage  PrependMagickMethod(NormalizeImage)
+#define OilPaintImage  PrependMagickMethod(OilPaintImage)
+#define OpaqueImage  PrependMagickMethod(OpaqueImage)
+#define OpaquePaintImageChannel  PrependMagickMethod(OpaquePaintImageChannel)
+#define OpaquePaintImage  PrependMagickMethod(OpaquePaintImage)
+#define OpenBlob  PrependMagickMethod(OpenBlob)
+#define OpenCacheView  PrependMagickMethod(OpenCacheView)
+#define OpenMagickStream  PrependMagickMethod(OpenMagickStream)
+#define OpenStream  PrependMagickMethod(OpenStream)
+#define OptimizeImageLayers  PrependMagickMethod(OptimizeImageLayers)
+#define OptimizeImageTransparency  PrependMagickMethod(OptimizeImageTransparency)
+#define OptimizePlusImageLayers  PrependMagickMethod(OptimizePlusImageLayers)
+#define OrderedDitherImageChannel  PrependMagickMethod(OrderedDitherImageChannel)
+#define OrderedDitherImage  PrependMagickMethod(OrderedDitherImage)
+#define OrderedPosterizeImageChannel  PrependMagickMethod(OrderedPosterizeImageChannel)
+#define OrderedPosterizeImage  PrependMagickMethod(OrderedPosterizeImage)
+#define PackbitsEncodeImage  PrependMagickMethod(PackbitsEncodeImage)
+#define PaintFloodfillImage  PrependMagickMethod(PaintFloodfillImage)
+#define PaintOpaqueImageChannel  PrependMagickMethod(PaintOpaqueImageChannel)
+#define PaintOpaqueImage  PrependMagickMethod(PaintOpaqueImage)
+#define PaintTransparentImage  PrependMagickMethod(PaintTransparentImage)
+#define ParseAbsoluteGeometry  PrependMagickMethod(ParseAbsoluteGeometry)
+#define ParseAffineGeometry  PrependMagickMethod(ParseAffineGeometry)
+#define ParseChannelOption  PrependMagickMethod(ParseChannelOption)
+#define ParseGeometry  PrependMagickMethod(ParseGeometry)
+#define ParseGravityGeometry  PrependMagickMethod(ParseGravityGeometry)
+#define ParseImageGeometry  PrependMagickMethod(ParseImageGeometry)
+#define ParseCommandOption  PrependMagickMethod(ParseCommandOption)
+#define ParseMetaGeometry  PrependMagickMethod(ParseMetaGeometry)
+#define ParsePageGeometry  PrependMagickMethod(ParsePageGeometry)
+#define ParseRegionGeometry  PrependMagickMethod(ParseRegionGeometry)
+#define ParseSizeGeometry  PrependMagickMethod(ParseSizeGeometry)
+#define PasskeyDecipherImage  PrependMagickMethod(PasskeyDecipherImage)
+#define PasskeyEncipherImage  PrependMagickMethod(PasskeyEncipherImage)
+#define PersistPixelCache  PrependMagickMethod(PersistPixelCache)
+#define PingBlob  PrependMagickMethod(PingBlob)
+#define PingImage  PrependMagickMethod(PingImage)
+#define PingImages  PrependMagickMethod(PingImages)
+#define PlasmaImage  PrependMagickMethod(PlasmaImage)
+#define PlasmaImageProxy  PrependMagickMethod(PlasmaImageProxy)
+#define PolaroidImage  PrependMagickMethod(PolaroidImage)
+#define PolicyComponentGenesis  PrependMagickMethod(PolicyComponentGenesis)
+#define PolicyComponentTerminus  PrependMagickMethod(PolicyComponentTerminus)
+#define PopImageList  PrependMagickMethod(PopImageList)
+#define PopImagePixels  PrependMagickMethod(PopImagePixels)
+#define PosterizeImage  PrependMagickMethod(PosterizeImage)
+#define PostscriptGeometry  PrependMagickMethod(PostscriptGeometry)
+#define PrependImageToList  PrependMagickMethod(PrependImageToList)
+#define PreviewImage  PrependMagickMethod(PreviewImage)
+#define PrintStringInfo  PrependMagickMethod(PrintStringInfo)
+#define process_message  PrependMagickMethod(process_message)
+#define ProfileImage  PrependMagickMethod(ProfileImage)
+#define PruneTagFromXMLTree  PrependMagickMethod(PruneTagFromXMLTree)
+#define PushImageList  PrependMagickMethod(PushImageList)
+#define PushImagePixels  PrependMagickMethod(PushImagePixels)
+#define PutEntryInHashmap  PrependMagickMethod(PutEntryInHashmap)
+#define QuantizationError  PrependMagickMethod(QuantizationError)
+#define QuantizeImage  PrependMagickMethod(QuantizeImage)
+#define QuantizeImages  PrependMagickMethod(QuantizeImages)
+#define QueryColorDatabase  PrependMagickMethod(QueryColorDatabase)
+#define QueryColorname  PrependMagickMethod(QueryColorname)
+#define QueryMagickColorname  PrependMagickMethod(QueryMagickColorname)
+#define QueryMagickColor  PrependMagickMethod(QueryMagickColor)
+#define QueueAuthenticNexus  PrependMagickMethod(QueueAuthenticNexus)
+#define QueueAuthenticPixels  PrependMagickMethod(QueueAuthenticPixels)
+#define QueueCacheViewAuthenticPixels  PrependMagickMethod(QueueCacheViewAuthenticPixels)
+#define RadialBlurImageChannel  PrependMagickMethod(RadialBlurImageChannel)
+#define RadialBlurImage  PrependMagickMethod(RadialBlurImage)
+#define RaiseImage  PrependMagickMethod(RaiseImage)
+#define RandomChannelThresholdImage  PrependMagickMethod(RandomChannelThresholdImage)
+#define RandomComponentGenesis  PrependMagickMethod(RandomComponentGenesis)
+#define RandomComponentTerminus  PrependMagickMethod(RandomComponentTerminus)
+#define RandomThresholdImageChannel  PrependMagickMethod(RandomThresholdImageChannel)
+#define RandomThresholdImage  PrependMagickMethod(RandomThresholdImage)
+#define ReacquireMemory  PrependMagickMethod(ReacquireMemory)
+#define ReadBlobByte  PrependMagickMethod(ReadBlobByte)
+#define ReadBlobDouble  PrependMagickMethod(ReadBlobDouble)
+#define ReadBlobFloat  PrependMagickMethod(ReadBlobFloat)
+#define ReadBlobLongLong  PrependMagickMethod(ReadBlobLongLong)
+#define ReadBlobLong  PrependMagickMethod(ReadBlobLong)
+#define ReadBlobLSBLong  PrependMagickMethod(ReadBlobLSBLong)
+#define ReadBlobLSBShort  PrependMagickMethod(ReadBlobLSBShort)
+#define ReadBlobMSBLong  PrependMagickMethod(ReadBlobMSBLong)
+#define ReadBlobMSBShort  PrependMagickMethod(ReadBlobMSBShort)
+#define ReadBlob  PrependMagickMethod(ReadBlob)
+#define ReadBlobShort  PrependMagickMethod(ReadBlobShort)
+#define ReadBlobString  PrependMagickMethod(ReadBlobString)
+#define ReadImage  PrependMagickMethod(ReadImage)
+#define ReadImages  PrependMagickMethod(ReadImages)
+#define ReadInlineImage  PrependMagickMethod(ReadInlineImage)
+#define ReadStream  PrependMagickMethod(ReadStream)
+#define RecolorImage  PrependMagickMethod(RecolorImage)
+#define ReduceNoiseImage  PrependMagickMethod(ReduceNoiseImage)
+#define ReferenceBlob  PrependMagickMethod(ReferenceBlob)
+#define ReferenceImage  PrependMagickMethod(ReferenceImage)
+#define ReferencePixelCache  PrependMagickMethod(ReferencePixelCache)
+#define RegisterARTImage  PrependMagickMethod(RegisterARTImage)
+#define RegisterAVSImage  PrependMagickMethod(RegisterAVSImage)
+#define RegisterBMPImage  PrependMagickMethod(RegisterBMPImage)
+#define RegisterBRAILLEImage  PrependMagickMethod(RegisterBRAILLEImage)
+#define RegisterCALSImage  PrependMagickMethod(RegisterCALSImage)
+#define RegisterCAPTIONImage  PrependMagickMethod(RegisterCAPTIONImage)
+#define RegisterCINImage  PrependMagickMethod(RegisterCINImage)
+#define RegisterCIPImage  PrependMagickMethod(RegisterCIPImage)
+#define RegisterCLIPImage  PrependMagickMethod(RegisterCLIPImage)
+#define RegisterCMYKImage  PrependMagickMethod(RegisterCMYKImage)
+#define RegisterCUTImage  PrependMagickMethod(RegisterCUTImage)
+#define RegisterDCMImage  PrependMagickMethod(RegisterDCMImage)
+#define RegisterDDSImage  PrependMagickMethod(RegisterDDSImage)
+#define RegisterDIBImage  PrependMagickMethod(RegisterDIBImage)
+#define RegisterDJVUImage  PrependMagickMethod(RegisterDJVUImage)
+#define RegisterDNGImage  PrependMagickMethod(RegisterDNGImage)
+#define RegisterDOTImage  PrependMagickMethod(RegisterDOTImage)
+#define RegisterDPXImage  PrependMagickMethod(RegisterDPXImage)
+#define RegisterEPTImage  PrependMagickMethod(RegisterEPTImage)
+#define RegisterFAXImage  PrependMagickMethod(RegisterFAXImage)
+#define RegisterFITSImage  PrependMagickMethod(RegisterFITSImage)
+#define RegisterGIFImage  PrependMagickMethod(RegisterGIFImage)
+#define RegisterGRADIENTImage  PrependMagickMethod(RegisterGRADIENTImage)
+#define RegisterGRAYImage  PrependMagickMethod(RegisterGRAYImage)
+#define RegisterHALDImage  PrependMagickMethod(RegisterHALDImage)
+#define RegisterHISTOGRAMImage  PrependMagickMethod(RegisterHISTOGRAMImage)
+#define RegisterHRZImage  PrependMagickMethod(RegisterHRZImage)
+#define RegisterHTMLImage  PrependMagickMethod(RegisterHTMLImage)
+#define RegisterICONImage  PrependMagickMethod(RegisterICONImage)
+#define RegisterINFOImage  PrependMagickMethod(RegisterINFOImage)
+#define RegisterINLINEImage  PrependMagickMethod(RegisterINLINEImage)
+#define RegisterIPLImage  PrependMagickMethod(RegisterIPLImage)
+#define RegisterJP2Image  PrependMagickMethod(RegisterJP2Image)
+#define RegisterJPEGImage  PrependMagickMethod(RegisterJPEGImage)
+#define RegisterLABELImage  PrependMagickMethod(RegisterLABELImage)
+#define RegisterMCPImage  PrependMagickMethod(RegisterMACImage)
+#define RegisterMAGICKImage  PrependMagickMethod(RegisterMAGICKImage)
+#define RegisterMagickInfo  PrependMagickMethod(RegisterMagickInfo)
+#define RegisterMAPImage  PrependMagickMethod(RegisterMAPImage)
+#define RegisterMATImage  PrependMagickMethod(RegisterMATImage)
+#define RegisterMATTEImage  PrependMagickMethod(RegisterMATTEImage)
+#define RegisterMETAImage  PrependMagickMethod(RegisterMETAImage)
+#define RegisterMIFFImage  PrependMagickMethod(RegisterMIFFImage)
+#define RegisterMONOImage  PrependMagickMethod(RegisterMONOImage)
+#define RegisterMPCImage  PrependMagickMethod(RegisterMPCImage)
+#define RegisterMPEGImage  PrependMagickMethod(RegisterMPEGImage)
+#define RegisterMPRImage  PrependMagickMethod(RegisterMPRImage)
+#define RegisterMSLImage  PrependMagickMethod(RegisterMSLImage)
+#define RegisterMTVImage  PrependMagickMethod(RegisterMTVImage)
+#define RegisterMVGImage  PrependMagickMethod(RegisterMVGImage)
+#define RegisterNULLImage  PrependMagickMethod(RegisterNULLImage)
+#define RegisterOTBImage  PrependMagickMethod(RegisterOTBImage)
+#define RegisterPALMImage  PrependMagickMethod(RegisterPALMImage)
+#define RegisterPATTERNImage  PrependMagickMethod(RegisterPATTERNImage)
+#define RegisterPCDImage  PrependMagickMethod(RegisterPCDImage)
+#define RegisterPCLImage  PrependMagickMethod(RegisterPCLImage)
+#define RegisterPCXImage  PrependMagickMethod(RegisterPCXImage)
+#define RegisterPDBImage  PrependMagickMethod(RegisterPDBImage)
+#define RegisterPDFImage  PrependMagickMethod(RegisterPDFImage)
+#define RegisterPICTImage  PrependMagickMethod(RegisterPICTImage)
+#define RegisterPIXImage  PrependMagickMethod(RegisterPIXImage)
+#define RegisterPLASMAImage  PrependMagickMethod(RegisterPLASMAImage)
+#define RegisterPNGImage  PrependMagickMethod(RegisterPNGImage)
+#define RegisterPNMImage  PrependMagickMethod(RegisterPNMImage)
+#define RegisterPREVIEWImage  PrependMagickMethod(RegisterPREVIEWImage)
+#define RegisterPS2Image  PrependMagickMethod(RegisterPS2Image)
+#define RegisterPS3Image  PrependMagickMethod(RegisterPS3Image)
+#define RegisterPSDImage  PrependMagickMethod(RegisterPSDImage)
+#define RegisterPSImage  PrependMagickMethod(RegisterPSImage)
+#define RegisterPWPImage  PrependMagickMethod(RegisterPWPImage)
+#define RegisterRAWImage  PrependMagickMethod(RegisterRAWImage)
+#define RegisterRGBImage  PrependMagickMethod(RegisterRGBImage)
+#define RegisterRLAImage  PrependMagickMethod(RegisterRLAImage)
+#define RegisterRLEImage  PrependMagickMethod(RegisterRLEImage)
+#define RegisterSCRImage  PrependMagickMethod(RegisterSCRImage)
+#define RegisterSCTImage  PrependMagickMethod(RegisterSCTImage)
+#define RegisterSFWImage  PrependMagickMethod(RegisterSFWImage)
+#define RegisterSGIImage  PrependMagickMethod(RegisterSGIImage)
+#define RegisterStaticModules  PrependMagickMethod(RegisterStaticModules)
+#define RegisterSTEGANOImage  PrependMagickMethod(RegisterSTEGANOImage)
+#define RegisterSUNImage  PrependMagickMethod(RegisterSUNImage)
+#define RegisterSVGImage  PrependMagickMethod(RegisterSVGImage)
+#define RegisterTGAImage  PrependMagickMethod(RegisterTGAImage)
+#define RegisterTHUMBNAILImage  PrependMagickMethod(RegisterTHUMBNAILImage)
+#define RegisterTIFFImage  PrependMagickMethod(RegisterTIFFImage)
+#define RegisterTILEImage  PrependMagickMethod(RegisterTILEImage)
+#define RegisterTIMImage  PrependMagickMethod(RegisterTIMImage)
+#define RegisterTTFImage  PrependMagickMethod(RegisterTTFImage)
+#define RegisterTXTImage  PrependMagickMethod(RegisterTXTImage)
+#define RegisterUILImage  PrependMagickMethod(RegisterUILImage)
+#define RegisterURLImage  PrependMagickMethod(RegisterURLImage)
+#define RegisterUYVYImage  PrependMagickMethod(RegisterUYVYImage)
+#define RegisterVICARImage  PrependMagickMethod(RegisterVICARImage)
+#define RegisterVIDImage  PrependMagickMethod(RegisterVIDImage)
+#define RegisterVIFFImage  PrependMagickMethod(RegisterVIFFImage)
+#define RegisterWBMPImage  PrependMagickMethod(RegisterWBMPImage)
+#define RegisterWMFImage  PrependMagickMethod(RegisterWMFImage)
+#define RegisterWPGImage  PrependMagickMethod(RegisterWPGImage)
+#define RegisterXBMImage  PrependMagickMethod(RegisterXBMImage)
+#define RegisterXCFImage  PrependMagickMethod(RegisterXCFImage)
+#define RegisterXCImage  PrependMagickMethod(RegisterXCImage)
+#define RegisterXImage  PrependMagickMethod(RegisterXImage)
+#define RegisterXPMImage  PrependMagickMethod(RegisterXPMImage)
+#define RegisterXPSImage  PrependMagickMethod(RegisterXPSImage)
+#define RegisterXWDImage  PrependMagickMethod(RegisterXWDImage)
+#define RegisterYCBCRImage  PrependMagickMethod(RegisterYCBCRImage)
+#define RegisterYUVImage  PrependMagickMethod(RegisterYUVImage)
+#define RegistryComponentGenesis  PrependMagickMethod(RegistryComponentGenesis)
+#define RegistryComponentTerminus  PrependMagickMethod(RegistryComponentTerminus)
+#define RelinquishAlignedMemory  PrependMagickMethod(RelinquishAlignedMemory)
+#define RelinquishMagickMatrix  PrependMagickMethod(RelinquishMagickMatrix)
+#define RelinquishMagickMemory  PrependMagickMethod(RelinquishMagickMemory)
+#define RelinquishMagickResource  PrependMagickMethod(RelinquishMagickResource)
+#define RelinquishSemaphoreInfo  PrependMagickMethod(RelinquishSemaphoreInfo)
+#define RelinquishUniqueFileResource  PrependMagickMethod(RelinquishUniqueFileResource)
+#define RemapImage  PrependMagickMethod(RemapImage)
+#define RemapImages  PrependMagickMethod(RemapImages)
+#define RemoteDisplayCommand  PrependMagickMethod(RemoteDisplayCommand)
+#define RemoveDuplicateLayers  PrependMagickMethod(RemoveDuplicateLayers)
+#define RemoveElementByValueFromLinkedList  PrependMagickMethod(RemoveElementByValueFromLinkedList)
+#define RemoveElementFromLinkedList  PrependMagickMethod(RemoveElementFromLinkedList)
+#define RemoveEntryFromHashmap  PrependMagickMethod(RemoveEntryFromHashmap)
+#define RemoveFirstImageFromList  PrependMagickMethod(RemoveFirstImageFromList)
+#define RemoveImageArtifact  PrependMagickMethod(RemoveImageArtifact)
+#define RemoveImageFromList  PrependMagickMethod(RemoveImageFromList)
+#define RemoveImageOption  PrependMagickMethod(RemoveImageOption)
+#define RemoveImageProfile  PrependMagickMethod(RemoveImageProfile)
+#define RemoveImageProperty  PrependMagickMethod(RemoveImageProperty)
+#define RemoveImageRegistry  PrependMagickMethod(RemoveImageRegistry)
+#define RemoveLastElementFromLinkedList  PrependMagickMethod(RemoveLastElementFromLinkedList)
+#define RemoveLastImageFromList  PrependMagickMethod(RemoveLastImageFromList)
+#define RemoveNodeByValueFromSplayTree  PrependMagickMethod(RemoveNodeByValueFromSplayTree)
+#define RemoveNodeFromSplayTree  PrependMagickMethod(RemoveNodeFromSplayTree)
+#define RemoveZeroDelayLayers  PrependMagickMethod(RemoveZeroDelayLayers)
+#define ReplaceImageInList  PrependMagickMethod(ReplaceImageInList)
+#define ResampleImage  PrependMagickMethod(ResampleImage)
+#define ResamplePixelColor  PrependMagickMethod(ResamplePixelColor)
+#define ResetHashmapIterator  PrependMagickMethod(ResetHashmapIterator)
+#define ResetImageArtifactIterator  PrependMagickMethod(ResetImageArtifactIterator)
+#define ResetImageAttributeIterator  PrependMagickMethod(ResetImageAttributeIterator)
+#define ResetImageOptionIterator  PrependMagickMethod(ResetImageOptionIterator)
+#define ResetImageOptions  PrependMagickMethod(ResetImageOptions)
+#define ResetImagePage  PrependMagickMethod(ResetImagePage)
+#define ResetImageProfileIterator  PrependMagickMethod(ResetImageProfileIterator)
+#define ResetImagePropertyIterator  PrependMagickMethod(ResetImagePropertyIterator)
+#define ResetImageRegistryIterator  PrependMagickMethod(ResetImageRegistryIterator)
+#define ResetLinkedListIterator  PrependMagickMethod(ResetLinkedListIterator)
+#define ResetMagickMemory  PrependMagickMethod(ResetMagickMemory)
+#define ResetSplayTreeIterator  PrependMagickMethod(ResetSplayTreeIterator)
+#define ResetSplayTree  PrependMagickMethod(ResetSplayTree)
+#define ResetStringInfo  PrependMagickMethod(ResetStringInfo)
+#define ResetTimer  PrependMagickMethod(ResetTimer)
+#define ResizeImage  PrependMagickMethod(ResizeImage)
+#define ResizeMagickMemory  PrependMagickMethod(ResizeMagickMemory)
+#define ResizeQuantumMemory  PrependMagickMethod(ResizeQuantumMemory)
+#define ResourceComponentGenesis  PrependMagickMethod(ResourceComponentGenesis)
+#define ResourceComponentTerminus  PrependMagickMethod(ResourceComponentTerminus)
+#define ReverseImageList  PrependMagickMethod(ReverseImageList)
+#define RGBTransformImage  PrependMagickMethod(RGBTransformImage)
+#define RollImage  PrependMagickMethod(RollImage)
+#define RotateImage  PrependMagickMethod(RotateImage)
+#define SampleImage  PrependMagickMethod(SampleImage)
+#define ScaleImage  PrependMagickMethod(ScaleImage)
+#define ScaleResampleFilter  PrependMagickMethod(ScaleResampleFilter)
+#define SeedPseudoRandomGenerator  PrependMagickMethod(SeedPseudoRandomGenerator)
+#define SeekBlob  PrependMagickMethod(SeekBlob)
+#define SegmentImage  PrependMagickMethod(SegmentImage)
+#define SelectiveBlurImageChannel  PrependMagickMethod(SelectiveBlurImageChannel)
+#define SelectiveBlurImage  PrependMagickMethod(SelectiveBlurImage)
+#define SemaphoreComponentGenesis  PrependMagickMethod(SemaphoreComponentGenesis)
+#define SemaphoreComponentTerminus  PrependMagickMethod(SemaphoreComponentTerminus)
+#define SeparateImageChannel  PrependMagickMethod(SeparateImageChannel)
+#define SeparateImages  PrependMagickMethod(SeparateImages)
+#define SepiaToneImage  PrependMagickMethod(SepiaToneImage)
+#define SetBlobExempt  PrependMagickMethod(SetBlobExempt)
+#define SetBlobExtent  PrependMagickMethod(SetBlobExtent)
+#define SetCacheThreshold  PrependMagickMethod(SetCacheThreshold)
+#define SetCacheViewPixels  PrependMagickMethod(SetCacheViewPixels)
+#define SetCacheViewStorageClass  PrependMagickMethod(SetCacheViewStorageClass)
+#define SetCacheViewVirtualPixelMethod  PrependMagickMethod(SetCacheViewVirtualPixelMethod)
+#define SetClientName  PrependMagickMethod(SetClientName)
+#define SetClientPath  PrependMagickMethod(SetClientPath)
+#define SetErrorHandler  PrependMagickMethod(SetErrorHandler)
+#define SetExceptionInfo  PrependMagickMethod(SetExceptionInfo)
+#define SetFatalErrorHandler  PrependMagickMethod(SetFatalErrorHandler)
+#define SetGeometryInfo  PrependMagickMethod(SetGeometryInfo)
+#define SetGeometry  PrependMagickMethod(SetGeometry)
+#define SetHeaderFromIPL  PrependMagickMethod(SetHeaderFromIPL)
+#define SetImageAlphaChannel  PrependMagickMethod(SetImageAlphaChannel)
+#define SetImageArtifact  PrependMagickMethod(SetImageArtifact)
+#define SetImageAttribute  PrependMagickMethod(SetImageAttribute)
+#define SetImageBackgroundColor  PrependMagickMethod(SetImageBackgroundColor)
+#define SetImageChannelDepth  PrependMagickMethod(SetImageChannelDepth)
+#define SetImageClipMask  PrependMagickMethod(SetImageClipMask)
+#define SetImageColorspace  PrependMagickMethod(SetImageColorspace)
+#define SetImageDepth  PrependMagickMethod(SetImageDepth)
+#define SetImageExtent  PrependMagickMethod(SetImageExtent)
+#define SetImageInfoBlob  PrependMagickMethod(SetImageInfoBlob)
+#define SetImageInfoFile  PrependMagickMethod(SetImageInfoFile)
+#define SetImageInfo  PrependMagickMethod(SetImageInfo)
+#define SetImageInfoProgressMonitor  PrependMagickMethod(SetImageInfoProgressMonitor)
+#define SetImageList  PrependMagickMethod(SetImageList)
+#define SetImageMask  PrependMagickMethod(SetImageMask)
+#define SetImageOpacity  PrependMagickMethod(SetImageOpacity)
+#define SetImageOption  PrependMagickMethod(SetImageOption)
+#define SetImagePixels  PrependMagickMethod(SetImagePixels)
+#define SetImage  PrependMagickMethod(SetImage)
+#define SetImageProfile  PrependMagickMethod(SetImageProfile)
+#define SetImageProgressMonitor  PrependMagickMethod(SetImageProgressMonitor)
+#define SetImageProperty  PrependMagickMethod(SetImageProperty)
+#define SetImageRegistry  PrependMagickMethod(SetImageRegistry)
+#define SetImageStorageClass  PrependMagickMethod(SetImageStorageClass)
+#define SetImageType  PrependMagickMethod(SetImageType)
+#define SetImageVirtualPixelMethod  PrependMagickMethod(SetImageVirtualPixelMethod)
+#define SetLogEventMask  PrependMagickMethod(SetLogEventMask)
+#define SetLogFormat  PrependMagickMethod(SetLogFormat)
+#define SetLogName  PrependMagickMethod(SetLogName)
+#define SetMagickInfo  PrependMagickMethod(SetMagickInfo)
+#define SetMagickMemoryMethods  PrependMagickMethod(SetMagickMemoryMethods)
+#define SetMagickRegistry  PrependMagickMethod(SetMagickRegistry)
+#define SetMagickResourceLimit  PrependMagickMethod(SetMagickResourceLimit)
+#define SetMonitorHandler  PrependMagickMethod(SetMonitorHandler)
+#define SetPixelCacheMethods  PrependMagickMethod(SetPixelCacheMethods)
+#define SetPixelCacheVirtualMethod  PrependMagickMethod(SetPixelCacheVirtualMethod)
+#define SetQuantumAlphaType  PrependMagickMethod(SetQuantumAlphaType)
+#define SetQuantumDepth  PrependMagickMethod(SetQuantumDepth)
+#define SetQuantumFormat  PrependMagickMethod(SetQuantumFormat)
+#define SetQuantumImageType  PrependMagickMethod(SetQuantumImageType)
+#define SetQuantumMinIsWhite  PrependMagickMethod(SetQuantumMinIsWhite)
+#define SetQuantumPack  PrependMagickMethod(SetQuantumPack)
+#define SetQuantumPad  PrependMagickMethod(SetQuantumPad)
+#define SetQuantumQuantum  PrependMagickMethod(SetQuantumQuantum)
+#define SetQuantumScale  PrependMagickMethod(SetQuantumScale)
+#define SetRandomKey  PrependMagickMethod(SetRandomKey)
+#define SetRandomTrueRandom  PrependMagickMethod(SetRandomTrueRandom)
+#define SetResampleFilterInterpolateMethod  PrependMagickMethod(SetResampleFilterInterpolateMethod)
+#define SetResampleFilter  PrependMagickMethod(SetResampleFilter)
+#define SetResampleFilterVirtualPixelMethod  PrependMagickMethod(SetResampleFilterVirtualPixelMethod)
+#define SetResizeFilterSupport  PrependMagickMethod(SetResizeFilterSupport)
+#define SetSignatureDigest  PrependMagickMethod(SetSignatureDigest)
+#define SetStreamInfoClientData  PrependMagickMethod(SetStreamInfoClientData)
+#define SetStreamInfoMap  PrependMagickMethod(SetStreamInfoMap)
+#define SetStreamInfoStorageType  PrependMagickMethod(SetStreamInfoStorageType)
+#define SetStringInfoDatum  PrependMagickMethod(SetStringInfoDatum)
+#define SetStringInfoLength  PrependMagickMethod(SetStringInfoLength)
+#define SetStringInfoPath  PrependMagickMethod(SetStringInfoPath)
+#define SetStringInfo  PrependMagickMethod(SetStringInfo)
+#define SetWarningHandler  PrependMagickMethod(SetWarningHandler)
+#define SetXMLTreeAttribute  PrependMagickMethod(SetXMLTreeAttribute)
+#define SetXMLTreeContent  PrependMagickMethod(SetXMLTreeContent)
+#define ShadeImage  PrependMagickMethod(ShadeImage)
+#define ShadowImage  PrependMagickMethod(ShadowImage)
+#define SharpenImageChannel  PrependMagickMethod(SharpenImageChannel)
+#define SharpenImage  PrependMagickMethod(SharpenImage)
+#define ShaveImage  PrependMagickMethod(ShaveImage)
+#define ShearImage  PrependMagickMethod(ShearImage)
+#define ShiftImageList  PrependMagickMethod(ShiftImageList)
+#define SigmoidalContrastImageChannel  PrependMagickMethod(SigmoidalContrastImageChannel)
+#define SigmoidalContrastImage  PrependMagickMethod(SigmoidalContrastImage)
+#define SignatureImage  PrependMagickMethod(SignatureImage)
+#define SimilarityImage  PrependMagickMethod(SimilarityImage)
+#define SizeBlob  PrependMagickMethod(SizeBlob)
+#define SketchImage  PrependMagickMethod(SketchImage)
+#define SolarizeImage  PrependMagickMethod(SolarizeImage)
+#define SortColormapByIntensity  PrependMagickMethod(SortColormapByIntensity)
+#define SparseColorImage  PrependMagickMethod(SparseColorImage)
+#define SpliceImageIntoList  PrependMagickMethod(SpliceImageIntoList)
+#define SpliceImageList  PrependMagickMethod(SpliceImageList)
+#define SpliceImage  PrependMagickMethod(SpliceImage)
+#define SplitImageList  PrependMagickMethod(SplitImageList)
+#define SplitStringInfo  PrependMagickMethod(SplitStringInfo)
+#define SpreadImage  PrependMagickMethod(SpreadImage)
+#define StartTimer  PrependMagickMethod(StartTimer)
+#define SteganoImage  PrependMagickMethod(SteganoImage)
+#define StereoAnaglyphImage  PrependMagickMethod(StereoAnaglyphImage)
+#define StereoImage  PrependMagickMethod(StereoImage)
+#define StreamImage  PrependMagickMethod(StreamImage)
+#define StringInfoToHexString  PrependMagickMethod(StringInfoToHexString)
+#define StringInfoToString  PrependMagickMethod(StringInfoToString)
+#define StringToArgv  PrependMagickMethod(StringToArgv)
+#define StringToken  PrependMagickMethod(StringToken)
+#define StringToList  PrependMagickMethod(StringToList)
+#define StringToStringInfo  PrependMagickMethod(StringToStringInfo)
+#define StripImage  PrependMagickMethod(StripImage)
+#define Strip  PrependMagickMethod(Strip)
+#define StripString  PrependMagickMethod(StripString)
+#define SubstituteString  PrependMagickMethod(SubstituteString)
+#define SwirlImage  PrependMagickMethod(SwirlImage)
+#define SyncAuthenticPixelCacheNexus  PrependMagickMethod(SyncAuthenticPixelCacheNexus)
+#define SyncAuthenticPixels  PrependMagickMethod(SyncAuthenticPixels)
+#define SyncCacheViewAuthenticPixels  PrependMagickMethod(SyncCacheViewAuthenticPixels)
+#define SyncCacheViewPixels  PrependMagickMethod(SyncCacheViewPixels)
+#define SyncCacheView  PrependMagickMethod(SyncCacheView)
+#define SyncImageList  PrependMagickMethod(SyncImageList)
+#define SyncImagePixels  PrependMagickMethod(SyncImagePixels)
+#define SyncImage  PrependMagickMethod(SyncImage)
+#define SyncImageProfiles  PrependMagickMethod(SyncImageProfiles)
+#define SyncImageSettings  PrependMagickMethod(SyncImageSettings)
+#define SyncImagesSettings  PrependMagickMethod(SyncImagesSettings)
+#define SyncNextImageInList  PrependMagickMethod(SyncNextImageInList)
+#define SystemCommand  PrependMagickMethod(SystemCommand)
+#define TellBlob  PrependMagickMethod(TellBlob)
+#define TemporaryFilename  PrependMagickMethod(TemporaryFilename)
+#define TextureImage  PrependMagickMethod(TextureImage)
+#define ThresholdImageChannel  PrependMagickMethod(ThresholdImageChannel)
+#define ThresholdImage  PrependMagickMethod(ThresholdImage)
+#define ThrowException  PrependMagickMethod(ThrowException)
+#define ThrowMagickExceptionList  PrependMagickMethod(ThrowMagickExceptionList)
+#define ThrowMagickException  PrependMagickMethod(ThrowMagickException)
+#define ThumbnailImage  PrependMagickMethod(ThumbnailImage)
+#define TintImage  PrependMagickMethod(TintImage)
+#define Tokenizer  PrependMagickMethod(Tokenizer)
+#define TransformColorspace  PrependMagickMethod(TransformColorspace)
+#define TransformHSL  PrependMagickMethod(TransformHSL)
+#define TransformImageColorspace  PrependMagickMethod(TransformImageColorspace)
+#define TransformImage  PrependMagickMethod(TransformImage)
+#define TransformImages  PrependMagickMethod(TransformImages)
+#define TransformRGBImage  PrependMagickMethod(TransformRGBImage)
+#define TranslateText  PrependMagickMethod(TranslateText)
+#define TransparentImage  PrependMagickMethod(TransparentImage)
+#define TransparentPaintImageChroma  PrependMagickMethod(TransparentPaintImageChroma)
+#define TransparentPaintImage  PrependMagickMethod(TransparentPaintImage)
+#define TransposeImage  PrependMagickMethod(TransposeImage)
+#define TransverseImage  PrependMagickMethod(TransverseImage)
+#define TrimImage  PrependMagickMethod(TrimImage)
+#define TypeComponentGenesis  PrependMagickMethod(TypeComponentGenesis)
+#define TypeComponentTerminus  PrependMagickMethod(TypeComponentTerminus)
+#define UniqueImageColors  PrependMagickMethod(UniqueImageColors)
+#define UnlockSemaphoreInfo  PrependMagickMethod(UnlockSemaphoreInfo)
+#define UnmapBlob  PrependMagickMethod(UnmapBlob)
+#define UnregisterARTImage  PrependMagickMethod(UnregisterARTImage)
+#define UnregisterAVSImage  PrependMagickMethod(UnregisterAVSImage)
+#define UnregisterBMPImage  PrependMagickMethod(UnregisterBMPImage)
+#define UnregisterBRAILLEImage  PrependMagickMethod(UnregisterBRAILLEImage)
+#define UnregisterCALSImage  PrependMagickMethod(UnregisterCALSImage)
+#define UnregisterCAPTIONImage  PrependMagickMethod(UnregisterCAPTIONImage)
+#define UnregisterCINImage  PrependMagickMethod(UnregisterCINImage)
+#define UnregisterCIPImage  PrependMagickMethod(UnregisterCIPImage)
+#define UnregisterCLIPImage  PrependMagickMethod(UnregisterCLIPImage)
+#define UnregisterCMYKImage  PrependMagickMethod(UnregisterCMYKImage)
+#define UnregisterCUTImage  PrependMagickMethod(UnregisterCUTImage)
+#define UnregisterDCMImage  PrependMagickMethod(UnregisterDCMImage)
+#define UnregisterDDSImage  PrependMagickMethod(UnregisterDDSImage)
+#define UnregisterDIBImage  PrependMagickMethod(UnregisterDIBImage)
+#define UnregisterDJVUImage  PrependMagickMethod(UnregisterDJVUImage)
+#define UnregisterDNGImage  PrependMagickMethod(UnregisterDNGImage)
+#define UnregisterDOTImage  PrependMagickMethod(UnregisterDOTImage)
+#define UnregisterDPXImage  PrependMagickMethod(UnregisterDPXImage)
+#define UnregisterEPTImage  PrependMagickMethod(UnregisterEPTImage)
+#define UnregisterFAXImage  PrependMagickMethod(UnregisterFAXImage)
+#define UnregisterFITSImage  PrependMagickMethod(UnregisterFITSImage)
+#define UnregisterGIFImage  PrependMagickMethod(UnregisterGIFImage)
+#define UnregisterGRADIENTImage  PrependMagickMethod(UnregisterGRADIENTImage)
+#define UnregisterGRAYImage  PrependMagickMethod(UnregisterGRAYImage)
+#define UnregisterHALDImage  PrependMagickMethod(UnregisterHALDImage)
+#define UnregisterHISTOGRAMImage  PrependMagickMethod(UnregisterHISTOGRAMImage)
+#define UnregisterHRZImage  PrependMagickMethod(UnregisterHRZImage)
+#define UnregisterHTMLImage  PrependMagickMethod(UnregisterHTMLImage)
+#define UnregisterICONImage  PrependMagickMethod(UnregisterICONImage)
+#define UnregisterINFOImage  PrependMagickMethod(UnregisterINFOImage)
+#define UnregisterINLINEImage  PrependMagickMethod(UnregisterINLINEImage)
+#define UnregisterIPLImage  PrependMagickMethod(UnregisterIPLImage)
+#define UnregisterJP2Image  PrependMagickMethod(UnregisterJP2Image)
+#define UnregisterJPEGImage  PrependMagickMethod(UnregisterJPEGImage)
+#define UnregisterLABELImage  PrependMagickMethod(UnregisterLABELImage)
+#define UnregisterMACImage  PrependMagickMethod(UnregisterMACImage)
+#define UnregisterMAGICKImage  PrependMagickMethod(UnregisterMAGICKImage)
+#define UnregisterMagickInfo  PrependMagickMethod(UnregisterMagickInfo)
+#define UnregisterMAPImage  PrependMagickMethod(UnregisterMAPImage)
+#define UnregisterMATImage  PrependMagickMethod(UnregisterMATImage)
+#define UnregisterMATTEImage  PrependMagickMethod(UnregisterMATTEImage)
+#define UnregisterMETAImage  PrependMagickMethod(UnregisterMETAImage)
+#define UnregisterMIFFImage  PrependMagickMethod(UnregisterMIFFImage)
+#define UnregisterMONOImage  PrependMagickMethod(UnregisterMONOImage)
+#define UnregisterMPCImage  PrependMagickMethod(UnregisterMPCImage)
+#define UnregisterMPEGImage  PrependMagickMethod(UnregisterMPEGImage)
+#define UnregisterMPRImage  PrependMagickMethod(UnregisterMPRImage)
+#define UnregisterMSLImage  PrependMagickMethod(UnregisterMSLImage)
+#define UnregisterMTVImage  PrependMagickMethod(UnregisterMTVImage)
+#define UnregisterMVGImage  PrependMagickMethod(UnregisterMVGImage)
+#define UnregisterNULLImage  PrependMagickMethod(UnregisterNULLImage)
+#define UnregisterOTBImage  PrependMagickMethod(UnregisterOTBImage)
+#define UnregisterPALMImage  PrependMagickMethod(UnregisterPALMImage)
+#define UnregisterPATTERNImage  PrependMagickMethod(UnregisterPATTERNImage)
+#define UnregisterPCDImage  PrependMagickMethod(UnregisterPCDImage)
+#define UnregisterPCLImage  PrependMagickMethod(UnregisterPCLImage)
+#define UnregisterPCXImage  PrependMagickMethod(UnregisterPCXImage)
+#define UnregisterPDBImage  PrependMagickMethod(UnregisterPDBImage)
+#define UnregisterPDFImage  PrependMagickMethod(UnregisterPDFImage)
+#define UnregisterPICTImage  PrependMagickMethod(UnregisterPICTImage)
+#define UnregisterPIXImage  PrependMagickMethod(UnregisterPIXImage)
+#define UnregisterPLASMAImage  PrependMagickMethod(UnregisterPLASMAImage)
+#define UnregisterPNGImage  PrependMagickMethod(UnregisterPNGImage)
+#define UnregisterPNMImage  PrependMagickMethod(UnregisterPNMImage)
+#define UnregisterPREVIEWImage  PrependMagickMethod(UnregisterPREVIEWImage)
+#define UnregisterPS2Image  PrependMagickMethod(UnregisterPS2Image)
+#define UnregisterPS3Image  PrependMagickMethod(UnregisterPS3Image)
+#define UnregisterPSDImage  PrependMagickMethod(UnregisterPSDImage)
+#define UnregisterPSImage  PrependMagickMethod(UnregisterPSImage)
+#define UnregisterPWPImage  PrependMagickMethod(UnregisterPWPImage)
+#define UnregisterRAWImage  PrependMagickMethod(UnregisterRAWImage)
+#define UnregisterRGBImage  PrependMagickMethod(UnregisterRGBImage)
+#define UnregisterRLAImage  PrependMagickMethod(UnregisterRLAImage)
+#define UnregisterRLEImage  PrependMagickMethod(UnregisterRLEImage)
+#define UnregisterSCRImage  PrependMagickMethod(UnregisterSCRImage)
+#define UnregisterSCTImage  PrependMagickMethod(UnregisterSCTImage)
+#define UnregisterSFWImage  PrependMagickMethod(UnregisterSFWImage)
+#define UnregisterSGIImage  PrependMagickMethod(UnregisterSGIImage)
+#define UnregisterStaticModules  PrependMagickMethod(UnregisterStaticModules)
+#define UnregisterSTEGANOImage  PrependMagickMethod(UnregisterSTEGANOImage)
+#define UnregisterSUNImage  PrependMagickMethod(UnregisterSUNImage)
+#define UnregisterSVGImage  PrependMagickMethod(UnregisterSVGImage)
+#define UnregisterTGAImage  PrependMagickMethod(UnregisterTGAImage)
+#define UnregisterTHUMBNAILImage  PrependMagickMethod(UnregisterTHUMBNAILImage)
+#define UnregisterTIFFImage  PrependMagickMethod(UnregisterTIFFImage)
+#define UnregisterTILEImage  PrependMagickMethod(UnregisterTILEImage)
+#define UnregisterTIMImage  PrependMagickMethod(UnregisterTIMImage)
+#define UnregisterTTFImage  PrependMagickMethod(UnregisterTTFImage)
+#define UnregisterTXTImage  PrependMagickMethod(UnregisterTXTImage)
+#define UnregisterUILImage  PrependMagickMethod(UnregisterUILImage)
+#define UnregisterURLImage  PrependMagickMethod(UnregisterURLImage)
+#define UnregisterUYVYImage  PrependMagickMethod(UnregisterUYVYImage)
+#define UnregisterVICARImage  PrependMagickMethod(UnregisterVICARImage)
+#define UnregisterVIDImage  PrependMagickMethod(UnregisterVIDImage)
+#define UnregisterVIFFImage  PrependMagickMethod(UnregisterVIFFImage)
+#define UnregisterWBMPImage  PrependMagickMethod(UnregisterWBMPImage)
+#define UnregisterWMFImage  PrependMagickMethod(UnregisterWMFImage)
+#define UnregisterWPGImage  PrependMagickMethod(UnregisterWPGImage)
+#define UnregisterXBMImage  PrependMagickMethod(UnregisterXBMImage)
+#define UnregisterXCFImage  PrependMagickMethod(UnregisterXCFImage)
+#define UnregisterXCImage  PrependMagickMethod(UnregisterXCImage)
+#define UnregisterXImage  PrependMagickMethod(UnregisterXImage)
+#define UnregisterXPMImage  PrependMagickMethod(UnregisterXPMImage)
+#define UnregisterXPSImage  PrependMagickMethod(UnregisterXPSImage)
+#define UnregisterXWDImage  PrependMagickMethod(UnregisterXWDImage)
+#define UnregisterYCBCRImage  PrependMagickMethod(UnregisterYCBCRImage)
+#define UnregisterYUVImage  PrependMagickMethod(UnregisterYUVImage)
+#define UnsharpMaskImageChannel  PrependMagickMethod(UnsharpMaskImageChannel)
+#define UnsharpMaskImage  PrependMagickMethod(UnsharpMaskImage)
+#define UnshiftImageList  PrependMagickMethod(UnshiftImageList)
+#define UpdateSignature  PrependMagickMethod(UpdateSignature)
+#define ValidateColormapIndex  PrependMagickMethod(ValidateColormapIndex)
+#define VignetteImage  PrependMagickMethod(VignetteImage)
+#define WaveImage  PrependMagickMethod(WaveImage)
+#define WhiteThresholdImageChannel  PrependMagickMethod(WhiteThresholdImageChannel)
+#define WhiteThresholdImage  PrependMagickMethod(WhiteThresholdImage)
+#define WriteBlobByte  PrependMagickMethod(WriteBlobByte)
+#define WriteBlobFloat  PrependMagickMethod(WriteBlobFloat)
+#define WriteBlobLong  PrependMagickMethod(WriteBlobLong)
+#define WriteBlobLSBLong  PrependMagickMethod(WriteBlobLSBLong)
+#define WriteBlobLSBShort  PrependMagickMethod(WriteBlobLSBShort)
+#define WriteBlobMSBLong  PrependMagickMethod(WriteBlobMSBLong)
+#define WriteBlobMSBShort  PrependMagickMethod(WriteBlobMSBShort)
+#define WriteBlob  PrependMagickMethod(WriteBlob)
+#define WriteBlobShort  PrependMagickMethod(WriteBlobShort)
+#define WriteBlobString  PrependMagickMethod(WriteBlobString)
+#define WriteImage  PrependMagickMethod(WriteImage)
+#define WriteImages  PrependMagickMethod(WriteImages)
+#define WriteStream  PrependMagickMethod(WriteStream)
+#define XAnimateBackgroundImage  PrependMagickMethod(XAnimateBackgroundImage)
+#define XAnimateImages  PrependMagickMethod(XAnimateImages)
+#define XAnnotateImage  PrependMagickMethod(XAnnotateImage)
+#define XBestFont  PrependMagickMethod(XBestFont)
+#define XBestIconSize  PrependMagickMethod(XBestIconSize)
+#define XBestPixel  PrependMagickMethod(XBestPixel)
+#define XBestVisualInfo  PrependMagickMethod(XBestVisualInfo)
+#define XCheckDefineCursor  PrependMagickMethod(XCheckDefineCursor)
+#define XCheckRefreshWindows  PrependMagickMethod(XCheckRefreshWindows)
+#define XClientMessage  PrependMagickMethod(XClientMessage)
+#define XColorBrowserWidget  PrependMagickMethod(XColorBrowserWidget)
+#define XCommandWidget  PrependMagickMethod(XCommandWidget)
+#define XComponentGenesis  PrependMagickMethod(XComponentGenesis)
+#define XComponentTerminus  PrependMagickMethod(XComponentTerminus)
+#define XConfigureImageColormap  PrependMagickMethod(XConfigureImageColormap)
+#define XConfirmWidget  PrependMagickMethod(XConfirmWidget)
+#define XConstrainWindowPosition  PrependMagickMethod(XConstrainWindowPosition)
+#define XDelay  PrependMagickMethod(XDelay)
+#define XDestroyResourceInfo  PrependMagickMethod(XDestroyResourceInfo)
+#define XDestroyWindowColors  PrependMagickMethod(XDestroyWindowColors)
+#define XDialogWidget  PrependMagickMethod(XDialogWidget)
+#define XDisplayBackgroundImage  PrependMagickMethod(XDisplayBackgroundImage)
+#define XDisplayImageInfo  PrependMagickMethod(XDisplayImageInfo)
+#define XDisplayImage  PrependMagickMethod(XDisplayImage)
+#define XDrawImage  PrependMagickMethod(XDrawImage)
+#define XError  PrependMagickMethod(XError)
+#define XFileBrowserWidget  PrependMagickMethod(XFileBrowserWidget)
+#define XFontBrowserWidget  PrependMagickMethod(XFontBrowserWidget)
+#define XFreeResources  PrependMagickMethod(XFreeResources)
+#define XFreeStandardColormap  PrependMagickMethod(XFreeStandardColormap)
+#define XGetAnnotateInfo  PrependMagickMethod(XGetAnnotateInfo)
+#define XGetImportInfo  PrependMagickMethod(XGetImportInfo)
+#define XGetMapInfo  PrependMagickMethod(XGetMapInfo)
+#define XGetPixelInfo  PrependMagickMethod(XGetPixelInfo)
+#define XGetResourceClass  PrependMagickMethod(XGetResourceClass)
+#define XGetResourceDatabase  PrependMagickMethod(XGetResourceDatabase)
+#define XGetResourceInfo  PrependMagickMethod(XGetResourceInfo)
+#define XGetResourceInstance  PrependMagickMethod(XGetResourceInstance)
+#define XGetScreenDensity  PrependMagickMethod(XGetScreenDensity)
+#define XGetWindowColor  PrependMagickMethod(XGetWindowColor)
+#define XGetWindowInfo  PrependMagickMethod(XGetWindowInfo)
+#define XHighlightEllipse  PrependMagickMethod(XHighlightEllipse)
+#define XHighlightLine  PrependMagickMethod(XHighlightLine)
+#define XHighlightRectangle  PrependMagickMethod(XHighlightRectangle)
+#define XImportImage  PrependMagickMethod(XImportImage)
+#define XInfoWidget  PrependMagickMethod(XInfoWidget)
+#define XInitializeWindows  PrependMagickMethod(XInitializeWindows)
+#define XListBrowserWidget  PrependMagickMethod(XListBrowserWidget)
+#define XMagickProgressMonitor  PrependMagickMethod(XMagickProgressMonitor)
+#define XMakeCursor  PrependMagickMethod(XMakeCursor)
+#define XMakeImage  PrependMagickMethod(XMakeImage)
+#define XMakeMagnifyImage  PrependMagickMethod(XMakeMagnifyImage)
+#define XMakeStandardColormap  PrependMagickMethod(XMakeStandardColormap)
+#define XMakeWindow  PrependMagickMethod(XMakeWindow)
+#define XMenuWidget  PrependMagickMethod(XMenuWidget)
+#define XMLTreeInfoToXML  PrependMagickMethod(XMLTreeInfoToXML)
+#define XNoticeWidget  PrependMagickMethod(XNoticeWidget)
+#define XPreferencesWidget  PrependMagickMethod(XPreferencesWidget)
+#define XProgressMonitorWidget  PrependMagickMethod(XProgressMonitorWidget)
+#define XQueryColorDatabase  PrependMagickMethod(XQueryColorDatabase)
+#define XQueryPosition  PrependMagickMethod(XQueryPosition)
+#define XRefreshWindow  PrependMagickMethod(XRefreshWindow)
+#define XRemoteCommand  PrependMagickMethod(XRemoteCommand)
+#define XRetainWindowColors  PrependMagickMethod(XRetainWindowColors)
+#define XSetCursorState  PrependMagickMethod(XSetCursorState)
+#define XSetWindows  PrependMagickMethod(XSetWindows)
+#define XTextViewWidget  PrependMagickMethod(XTextViewWidget)
+#define XUserPreferences  PrependMagickMethod(XUserPreferences)
+#define XWarning  PrependMagickMethod(XWarning)
+#define XWindowByID  PrependMagickMethod(XWindowByID)
+#define XWindowByName  PrependMagickMethod(XWindowByName)
+#define XWindowByProperty  PrependMagickMethod(XWindowByProperty)
+#define ZLIBEncodeImage  PrependMagickMethod(ZLIBEncodeImage)
+#define ZoomImage  PrependMagickMethod(ZoomImage)
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/mime-private.h b/MagickCore/mime-private.h
new file mode 100644
index 0000000..31c2e1b
--- /dev/null
+++ b/MagickCore/mime-private.h
@@ -0,0 +1,38 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  The ImageMagick mime private methods.
+*/
+#ifndef _MAGICK_MIME_PRIVATE_H
+#define _MAGICK_MIME_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedData,
+  StringData,
+  ByteData,
+  ShortData,
+  LongData
+} DataType;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/mime.c b/MagickCore/mime.c
new file mode 100644
index 0000000..bc29e30
--- /dev/null
+++ b/MagickCore/mime.c
@@ -0,0 +1,1110 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                        M   M  IIIII  M   M  EEEEE                           %
+%                        MM MM    I    MM MM  E                               %
+%                        M M M    I    M M M  EEE                             %
+%                        M   M    I    M   M  E                               %
+%                        M   M  IIIII  M   M  EEEEE                           %
+%                                                                             %
+%                                                                             %
+%                          MagickCore Mime Methods                            %
+%                                                                             %
+%                              Software Design                                %
+%                                 July 2000                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/MagicksToolkit/script/license.php             %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/mime.h"
+#include "MagickCore/mime-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define MimeFilename  "mime.xml"
+
+/*
+  Typedef declaration.
+*/
+struct _MimeInfo
+{
+  char
+    *path,
+    *type,
+    *description,
+    *pattern;
+
+  ssize_t
+    priority;
+
+  MagickOffsetType
+    offset;
+
+  size_t
+    extent;
+
+  DataType
+    data_type;
+
+  ssize_t
+    mask,
+    value;
+
+  EndianType
+    endian;
+
+  size_t
+    length;
+
+  unsigned char
+    *magic;
+
+  MagickBooleanType
+    stealth;
+
+  size_t
+    signature;
+};
+
+/*
+  Static declarations.
+*/
+static const char
+  *MimeMap = (char *)
+    "<?xml version=\"1.0\"?>"
+    "<mimemap>"
+    "</mimemap>";
+
+static LinkedListInfo
+  *mime_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *mime_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_mime = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeMimeList(ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M i m e I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMimeInfo() attempts to classify the content to identify which mime type
+%  is associated with the content, if any.
+%
+%  The format of the GetMimeInfo method is:
+%
+%      const MimeInfo *GetMimeInfo(const char *filename,
+%        const unsigned char *magic,const size_t length,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename:  If we cannot not classify the string, we attempt to classify
+%      based on the filename (e.g. *.pdf returns application/pdf).
+%
+%    o magic: A binary string generally representing the first few characters
+%      of the image file or blob.
+%
+%    o length: the length of the binary signature.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const MimeInfo *GetMimeInfo(const char *filename,
+  const unsigned char *magic,const size_t length,ExceptionInfo *exception)
+{
+  const MimeInfo
+    *mime_info;
+
+  EndianType
+    endian;
+
+  register const MimeInfo
+    *p;
+
+  register const unsigned char
+    *q;
+
+  register ssize_t
+    i;
+
+  size_t
+    lsb_first;
+
+  ssize_t
+    value;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((mime_list == (LinkedListInfo *) NULL) ||
+      (instantiate_mime == MagickFalse))
+    if (InitializeMimeList(exception) == MagickFalse)
+      return((const MimeInfo *) NULL);
+  if ((mime_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(mime_list) != MagickFalse))
+    return((const MimeInfo *) NULL);
+  if ((magic == (const unsigned char *) NULL) || (length == 0))
+    return((const MimeInfo *) GetValueFromLinkedList(mime_list,0));
+  if (length == 0)
+    return((const MimeInfo *) NULL);
+  /*
+    Search for mime tag.
+  */
+  mime_info=(const MimeInfo *) NULL;
+  lsb_first=1;
+  LockSemaphoreInfo(mime_semaphore);
+  ResetLinkedListIterator(mime_list);
+  p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+  while (p != (const MimeInfo *) NULL)
+  {
+    assert(p->offset >= 0);
+    if (mime_info != (const MimeInfo *) NULL)
+      if (p->priority > mime_info->priority)
+        {
+          p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+          continue;
+        }
+    if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
+      {
+        if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
+          mime_info=p;
+        p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+        continue;
+      }
+    switch (p->data_type)
+    {
+      case ByteData:
+      {
+        if ((size_t) (p->offset+4) > length)
+          break;
+        q=magic+p->offset;
+        value=(ssize_t) (*q++);
+        if (p->mask == 0)
+          {
+            if (p->value == value)
+              mime_info=p;
+          }
+        else
+          {
+            if ((p->value & p->mask) == value)
+              mime_info=p;
+          }
+        break;
+      }
+      case ShortData:
+      {
+        if ((size_t) (p->offset+4) > length)
+          break;
+        q=magic+p->offset;
+        endian=p->endian;
+        if (p->endian == UndefinedEndian)
+          endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
+        if (endian == LSBEndian)
+          {
+            value=(ssize_t) (*q++);
+            value|=(*q++) << 8;
+          }
+        else
+          {
+            value=(ssize_t) (*q++) << 8;
+            value|=(*q++);
+          }
+        if (p->mask == 0)
+          {
+            if (p->value == value)
+              mime_info=p;
+          }
+        else
+          {
+            if ((p->value & p->mask) == value)
+              mime_info=p;
+          }
+        break;
+      }
+      case LongData:
+      {
+        if ((size_t) (p->offset+4) > length)
+          break;
+        q=magic+p->offset;
+        endian=p->endian;
+        if (p->endian == UndefinedEndian)
+          endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
+        if (endian == LSBEndian)
+          {
+            value=(ssize_t) (*q++);
+            value|=(*q++) << 8;
+            value|=(*q++) << 16;
+            value|=(*q++) << 24;
+          }
+        else
+          {
+            value=(ssize_t) (*q++) << 24;
+            value|=(*q++) << 16;
+            value|=(*q++) << 8;
+            value|=(*q++);
+          }
+        if (p->mask == 0)
+          {
+            if (p->value == value)
+              mime_info=p;
+          }
+        else
+          {
+            if ((p->value & p->mask) == value)
+              mime_info=p;
+          }
+        break;
+      }
+      case StringData:
+      default:
+      {
+        for (i=0; i <= (ssize_t) p->extent; i++)
+        {
+          if ((size_t) (p->offset+i+p->length) > length)
+            break;
+          if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
+            {
+              mime_info=p;
+              break;
+            }
+        }
+        break;
+      }
+    }
+    p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+  }
+  if (p != (const MimeInfo *) NULL)
+    (void) InsertValueInLinkedList(mime_list,0,
+      RemoveElementByValueFromLinkedList(mime_list,p));
+  UnlockSemaphoreInfo(mime_semaphore);
+  return(mime_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M i m e I n f o L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMimeInfoList() returns any image aliases that match the specified
+%  pattern.
+%
+%  The magic of the GetMimeInfoList function is:
+%
+%      const MimeInfo **GetMimeInfoList(const char *pattern,
+%        size_t *number_aliases,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_aliases:  This integer returns the number of magics in the
+%      list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int MimeInfoCompare(const void *x,const void *y)
+{
+  const MimeInfo
+    **p,
+    **q;
+
+  p=(const MimeInfo **) x,
+  q=(const MimeInfo **) y;
+  if (strcasecmp((*p)->path,(*q)->path) == 0)
+    return(strcasecmp((*p)->type,(*q)->type));
+  return(strcasecmp((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
+  size_t *number_aliases,ExceptionInfo *exception)
+{
+  const MimeInfo
+    **aliases;
+
+  register const MimeInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate mime list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (size_t *) NULL);
+  *number_aliases=0;
+  p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
+  if (p == (const MimeInfo *) NULL)
+    return((const MimeInfo **) NULL);
+  aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
+  if (aliases == (const MimeInfo **) NULL)
+    return((const MimeInfo **) NULL);
+  /*
+    Generate mime list.
+  */
+  LockSemaphoreInfo(mime_semaphore);
+  ResetLinkedListIterator(mime_list);
+  p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+  for (i=0; p != (const MimeInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
+      aliases[i++]=p;
+    p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+  }
+  UnlockSemaphoreInfo(mime_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
+  aliases[i]=(MimeInfo *) NULL;
+  *number_aliases=(size_t) i;
+  return(aliases);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M i m e L i s t                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMimeList() returns any image format alias that matches the specified
+%  pattern.
+%
+%  The format of the GetMimeList function is:
+%
+%      char **GetMimeList(const char *pattern,size_t *number_aliases,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_aliases:  This integer returns the number of image format aliases
+%      in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int MimeCompare(const void *x,const void *y)
+{
+  register char
+    *p,
+    *q;
+
+  p=(char *) x;
+  q=(char *) y;
+  return(strcasecmp(p,q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetMimeList(const char *pattern,
+  size_t *number_aliases,ExceptionInfo *exception)
+{
+  char
+    **aliases;
+
+  register const MimeInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate configure list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_aliases != (size_t *) NULL);
+  *number_aliases=0;
+  p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
+  if (p == (const MimeInfo *) NULL)
+    return((char **) NULL);
+  aliases=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
+  if (aliases == (char **) NULL)
+    return((char **) NULL);
+  LockSemaphoreInfo(mime_semaphore);
+  ResetLinkedListIterator(mime_list);
+  p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+  for (i=0; p != (const MimeInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
+      aliases[i++]=ConstantString(p->type);
+    p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
+  }
+  UnlockSemaphoreInfo(mime_semaphore);
+  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
+  aliases[i]=(char *) NULL;
+  *number_aliases=(size_t) i;
+  return(aliases);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M i m e D e s c r i p t i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMimeDescription() returns the mime type description.
+%
+%  The format of the GetMimeDescription method is:
+%
+%      const char *GetMimeDescription(const MimeInfo *mime_info)
+%
+%  A description of each parameter follows:
+%
+%    o mime_info:  The magic info.
+%
+*/
+MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(mime_info != (MimeInfo *) NULL);
+  assert(mime_info->signature == MagickSignature);
+  return(mime_info->description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M i m e T y p e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMimeType() returns the mime type.
+%
+%  The format of the GetMimeType method is:
+%
+%      const char *GetMimeType(const MimeInfo *mime_info)
+%
+%  A description of each parameter follows:
+%
+%    o mime_info:  The magic info.
+%
+*/
+MagickExport const char *GetMimeType(const MimeInfo *mime_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(mime_info != (MimeInfo *) NULL);
+  assert(mime_info->signature == MagickSignature);
+  return(mime_info->type);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e M i m e L i s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeMimeList() initializes the mime list.
+%
+%  The format of the InitializeMimeList method is:
+%
+%      MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
+{
+  if ((mime_list == (LinkedListInfo *) NULL) &&
+      (instantiate_mime == MagickFalse))
+    {
+      if (mime_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&mime_semaphore);
+      LockSemaphoreInfo(mime_semaphore);
+      if ((mime_list == (LinkedListInfo *) NULL) &&
+          (instantiate_mime == MagickFalse))
+        {
+          (void) LoadMimeLists(MimeFilename,exception);
+          instantiate_mime=MagickTrue;
+        }
+      UnlockSemaphoreInfo(mime_semaphore);
+    }
+  return(mime_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t M i m e I n f o                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListMimeInfo() lists the magic info to a file.
+%
+%  The format of the ListMimeInfo method is:
+%
+%      MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
+{
+  const char
+    *path;
+
+  const MimeInfo
+    **mime_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_aliases;
+
+  ssize_t
+    j;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  mime_info=GetMimeInfoList("*",&number_aliases,exception);
+  if (mime_info == (const MimeInfo **) NULL)
+    return(MagickFalse);
+  j=0;
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_aliases; i++)
+  {
+    if (mime_info[i]->stealth != MagickFalse)
+      continue;
+    if ((path == (const char *) NULL) ||
+        (strcasecmp(path,mime_info[i]->path) != 0))
+      {
+        if (mime_info[i]->path != (char *) NULL)
+          (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
+        (void) FormatLocaleFile(file,"Type                   Description\n");
+        (void) FormatLocaleFile(file,
+          "-------------------------------------------------"
+          "------------------------------\n");
+      }
+    path=mime_info[i]->path;
+    (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
+    if (strlen(mime_info[i]->type) <= 25)
+      {
+        for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
+          (void) FormatLocaleFile(file," ");
+      }
+    else
+      {
+        (void) FormatLocaleFile(file,"\n");
+        for (j=0; j <= 27; j++)
+          (void) FormatLocaleFile(file," ");
+      }
+    if (mime_info[i]->description != (char *) NULL)
+      (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d M i m e L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadMimeList() loads the magic configuration file which provides a mapping
+%  between magic attributes and a magic name.
+%
+%  The format of the LoadMimeList method is:
+%
+%      MagickBooleanType LoadMimeList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The mime list in XML format.
+%
+%    o filename:  The mime list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadMimeList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  const char
+    *attribute;
+
+  MimeInfo
+    *mime_info = (MimeInfo *) NULL;
+
+  MagickBooleanType
+    status;
+
+  XMLTreeInfo
+    *mime,
+    *mime_map,
+    *include;
+
+  /*
+    Load the mime map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading mime map \"%s\" ...",filename);
+  if (xml == (const char *) NULL)
+    return(MagickFalse);
+  if (mime_list == (LinkedListInfo *) NULL)
+    {
+      mime_list=NewLinkedList(0);
+      if (mime_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  mime_map=NewXMLTree(xml,exception);
+  if (mime_map == (XMLTreeInfo *) NULL)
+    return(MagickFalse);
+  status=MagickTrue;
+  include=GetXMLTreeChild(mime_map,"include");
+  while (include != (XMLTreeInfo *) NULL)
+  {
+    /*
+      Process include element.
+    */
+    attribute=GetXMLTreeAttribute(include,"file");
+    if (attribute != (const char *) NULL)
+      {
+        if (depth > 200)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
+        else
+          {
+            char
+              path[MaxTextExtent],
+              *xml;
+
+            GetPathComponent(filename,HeadPath,path);
+            if (*path != '\0')
+              (void) ConcatenateMagickString(path,DirectorySeparator,
+                MaxTextExtent);
+            if (*attribute == *DirectorySeparator)
+              (void) CopyMagickString(path,attribute,MaxTextExtent);
+            else
+              (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
+            xml=FileToString(path,~0,exception);
+            if (xml != (char *) NULL)
+              {
+                status=LoadMimeList(xml,path,depth+1,exception);
+                xml=DestroyString(xml);
+              }
+          }
+      }
+    include=GetNextXMLTreeTag(include);
+  }
+  mime=GetXMLTreeChild(mime_map,"mime");
+  while (mime != (XMLTreeInfo *) NULL)
+  {
+    const char
+      *attribute;
+
+    /*
+      Process mime element.
+    */
+    mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
+    if (mime_info == (MimeInfo *) NULL)
+      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+    (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
+    mime_info->path=ConstantString(filename);
+    mime_info->signature=MagickSignature;
+    attribute=GetXMLTreeAttribute(mime,"data-type");
+    if (attribute != (const char *) NULL)
+      mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
+        MagickTrue,attribute);
+    attribute=GetXMLTreeAttribute(mime,"description");
+    if (attribute != (const char *) NULL)
+      mime_info->description=ConstantString(attribute);
+    attribute=GetXMLTreeAttribute(mime,"endian");
+    if (attribute != (const char *) NULL)
+      mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
+        MagickTrue,attribute);
+    attribute=GetXMLTreeAttribute(mime,"magic");
+    if (attribute != (const char *) NULL)
+      {
+        char
+          *token;
+
+        const char
+          *p;
+
+        register unsigned char
+          *q;
+
+        token=AcquireString(attribute);
+        (void) SubstituteString((char **) &token,"&lt;","<");
+        (void) SubstituteString((char **) &token,"&amp;","&");
+        (void) SubstituteString((char **) &token,"&quot;","\"");
+        mime_info->magic=(unsigned char *) AcquireString(token);
+        q=mime_info->magic;
+        for (p=token; *p != '\0'; )
+        {
+          if (*p == '\\')
+            {
+              p++;
+              if (isdigit((int) ((unsigned char) *p)) != 0)
+                {
+                  char
+                    *end;
+
+                  *q++=(unsigned char) strtol(p,&end,8);
+                  p+=(end-p);
+                  mime_info->length++;
+                  continue;
+                }
+              switch (*p)
+              {
+                case 'b': *q='\b'; break;
+                case 'f': *q='\f'; break;
+                case 'n': *q='\n'; break;
+                case 'r': *q='\r'; break;
+                case 't': *q='\t'; break;
+                case 'v': *q='\v'; break;
+                case 'a': *q='a'; break;
+                case '?': *q='\?'; break;
+                default: *q=(unsigned char) (*p); break;
+              }
+              p++;
+              q++;
+              mime_info->length++;
+              continue;
+            }
+          *q++=(unsigned char) (*p++);
+          mime_info->length++;
+        }
+        token=DestroyString(token);
+        if (mime_info->data_type != StringData)
+          mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
+            (char **) NULL,0);
+      }
+    attribute=GetXMLTreeAttribute(mime,"mask");
+    if (attribute != (const char *) NULL)
+      mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
+    attribute=GetXMLTreeAttribute(mime,"offset");
+    if (attribute != (const char *) NULL)
+      {
+        char
+          *c;
+
+        mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
+        if (*c == ':')
+          mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
+      }
+    attribute=GetXMLTreeAttribute(mime,"pattern");
+    if (attribute != (const char *) NULL)
+      mime_info->pattern=ConstantString(attribute);
+    attribute=GetXMLTreeAttribute(mime,"priority");
+    if (attribute != (const char *) NULL)
+      mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
+    attribute=GetXMLTreeAttribute(mime,"stealth");
+    if (attribute != (const char *) NULL)
+      mime_info->stealth=IsMagickTrue(attribute);
+    attribute=GetXMLTreeAttribute(mime,"type");
+    if (attribute != (const char *) NULL)
+      mime_info->type=ConstantString(attribute);
+    status=AppendValueToLinkedList(mime_list,mime_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
+    mime=GetNextXMLTreeTag(mime);
+  }
+  mime_map=DestroyXMLTree(mime_map);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d M i m e L i s t s                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadMimeList() loads one or more magic configuration file which provides a
+%  mapping between magic attributes and a magic name.
+%
+%  The format of the LoadMimeLists method is:
+%
+%      MagickBooleanType LoadMimeLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType LoadMimeLists(const char *filename,
+  ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadMimeList(MimeMap,"built-in",0,exception));
+#else
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  status=MagickFalse;
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadMimeList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  if ((mime_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(mime_list) != MagickFalse))
+    status|=LoadMimeList(MimeMap,"built-in",0,exception);
+  else
+    ClearMagickException(exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  M a g i c k T o M i m e                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickToMime() returns the officially registered (or de facto) MIME
+%  media-type corresponding to a magick string.  If there is no registered
+%  media-type, then the string "image/x-magick" (all lower case) is returned.
+%  The returned string must be deallocated by the user.
+%
+%  The format of the MagickToMime method is:
+%
+%      char *MagickToMime(const char *magick)
+%
+%  A description of each parameter follows.
+%
+%   o  magick:  ImageMagick format specification "magick" tag.
+%
+*/
+MagickExport char *MagickToMime(const char *magick)
+{
+  char
+    filename[MaxTextExtent],
+    media[MaxTextExtent];
+
+  const MimeInfo
+    *mime_info;
+
+  ExceptionInfo
+    *exception;
+
+  (void) FormatLocaleString(filename,MaxTextExtent,"file.%s",magick);
+  LocaleLower(filename);
+  exception=AcquireExceptionInfo();
+  mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (mime_info != (const MimeInfo *) NULL)
+    return(ConstantString(GetMimeType(mime_info)));
+  (void) FormatLocaleString(media,MaxTextExtent,"image/x-%s",magick);
+  LocaleLower(media+8);
+  return(ConstantString(media));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M i m e C o m p o n e n t G e n e s i s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MimeComponentGenesis() instantiates the mime component.
+%
+%  The format of the MimeComponentGenesis method is:
+%
+%      MagickBooleanType MimeComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType MimeComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&mime_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M i m e C o m p o n e n t T e r m i n u s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MimeComponentTerminus() destroys the mime component.
+%
+%  The format of the MimeComponentTerminus method is:
+%
+%      MimeComponentTerminus(void)
+%
+*/
+
+static void *DestroyMimeElement(void *mime_info)
+{
+  register MimeInfo
+    *p;
+
+  p=(MimeInfo *) mime_info;
+  if (p->magic != (unsigned char *) NULL)
+    p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
+  if (p->pattern != (char *) NULL)
+    p->pattern=DestroyString(p->pattern);
+  if (p->description != (char *) NULL)
+    p->description=DestroyString(p->description);
+  if (p->type != (char *) NULL)
+    p->type=DestroyString(p->type);
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  p=(MimeInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void MimeComponentTerminus(void)
+{
+  if (mime_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&mime_semaphore);
+  LockSemaphoreInfo(mime_semaphore);
+  if (mime_list != (LinkedListInfo *) NULL)
+    mime_list=DestroyLinkedList(mime_list,DestroyMimeElement);
+  instantiate_mime=MagickFalse;
+  UnlockSemaphoreInfo(mime_semaphore);
+  DestroySemaphoreInfo(&mime_semaphore);
+}
diff --git a/MagickCore/mime.h b/MagickCore/mime.h
new file mode 100644
index 0000000..f2247da
--- /dev/null
+++ b/MagickCore/mime.h
@@ -0,0 +1,52 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  The ImageMagick mime methods.
+*/
+#ifndef _MIME_MIME_H
+#define _MIME_MIME_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _MimeInfo
+  MimeInfo;
+
+extern MagickExport char
+  **GetMimeList(const char *,size_t *,ExceptionInfo *),
+  *MagickToMime(const char *);
+
+extern MagickExport const char
+  *GetMimeDescription(const MimeInfo *),
+  *GetMimeType(const MimeInfo *);
+
+extern MagickExport MagickBooleanType
+  ListMimeInfo(FILE *,ExceptionInfo *),
+  LoadMimeLists(const char *,ExceptionInfo *),
+  MimeComponentGenesis(void);
+
+extern MagickExport const MimeInfo
+  *GetMimeInfo(const char *,const unsigned char *,const size_t,ExceptionInfo *),
+  **GetMimeInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport void
+  MimeComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/module.c b/MagickCore/module.c
new file mode 100644
index 0000000..5b1b688
--- /dev/null
+++ b/MagickCore/module.c
@@ -0,0 +1,1680 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  M   M   OOO   DDDD   U   U  L      EEEEE                   %
+%                  MM MM  O   O  D   D  U   U  L      E                       %
+%                  M M M  O   O  D   D  U   U  L      EEE                     %
+%                  M   M  O   O  D   D  U   U  L      E                       %
+%                  M   M   OOO   DDDD    UUU   LLLLL  EEEEE                   %
+%                                                                             %
+%                                                                             %
+%                          MagickCore Module Methods                          %
+%                                                                             %
+%                              Software Design                                %
+%                              Bob Friesenhahn                                %
+%                                March 2000                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/coder.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/static.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+#include "ltdl.h"
+typedef lt_dlhandle ModuleHandle;
+#else
+typedef void *ModuleHandle;
+#endif
+
+/*
+  Define declarations.
+*/
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+#  define ModuleGlobExpression "*.la"
+#else
+#  if defined(_DEBUG)
+#    define ModuleGlobExpression "IM_MOD_DB_*.dll"
+#  else
+#    define ModuleGlobExpression "IM_MOD_RL_*.dll"
+#  endif
+#endif
+
+/*
+  Global declarations.
+*/
+static SemaphoreInfo
+  *module_semaphore = (SemaphoreInfo *) NULL;
+
+static SplayTreeInfo
+  *module_list = (SplayTreeInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_module = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static const ModuleInfo
+  *RegisterModule(const ModuleInfo *,ExceptionInfo *);
+
+static MagickBooleanType
+  GetMagickModulePath(const char *,MagickModuleType,char *,ExceptionInfo *),
+  UnregisterModule(const ModuleInfo *,ExceptionInfo *);
+
+static void
+  TagToCoderModuleName(const char *,char *),
+  TagToFilterModuleName(const char *,char *),
+  TagToModuleName(const char *,const char *,char *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e M o d u l e I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireModuleInfo() allocates the ModuleInfo structure.
+%
+%  The format of the AcquireModuleInfo method is:
+%
+%      ModuleInfo *AcquireModuleInfo(const char *path,const char *tag)
+%
+%  A description of each parameter follows:
+%
+%    o path: the path associated with the tag.
+%
+%    o tag: a character string that represents the image format we are
+%      looking for.
+%
+*/
+MagickExport ModuleInfo *AcquireModuleInfo(const char *path,const char *tag)
+{
+  ModuleInfo
+    *module_info;
+
+  module_info=(ModuleInfo *) AcquireMagickMemory(sizeof(*module_info));
+  if (module_info == (ModuleInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(module_info,0,sizeof(*module_info));
+  if (path != (const char *) NULL)
+    module_info->path=ConstantString(path);
+  if (tag != (const char *) NULL)
+    module_info->tag=ConstantString(tag);
+  module_info->timestamp=time(0);
+  module_info->signature=MagickSignature;
+  return(module_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y M o d u l e L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyModuleList() unregisters any previously loaded modules and exits
+%  the module loaded environment.
+%
+%  The format of the DestroyModuleList module is:
+%
+%      void DestroyModuleList(void)
+%
+*/
+MagickExport void DestroyModuleList(void)
+{
+  /*
+    Destroy magick modules.
+  */
+  LockSemaphoreInfo(module_semaphore);
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+  if (module_list != (SplayTreeInfo *) NULL)
+    module_list=DestroySplayTree(module_list);
+  if (instantiate_module != MagickFalse)
+    {
+#if !defined(MAGICKCORE_JP2_DELEGATE)
+      (void) lt_dlexit();  /* Jasper has an errant atexit() handler */
+#endif
+      instantiate_module=MagickFalse;
+    }
+#endif
+  UnlockSemaphoreInfo(module_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M o d u l e I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetModuleInfo() returns a pointer to a ModuleInfo structure that matches the
+%  specified tag.  If tag is NULL, the head of the module list is returned. If
+%  no modules are loaded, or the requested module is not found, NULL is
+%  returned.
+%
+%  The format of the GetModuleInfo module is:
+%
+%      ModuleInfo *GetModuleInfo(const char *tag,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o tag: a character string that represents the image format we are
+%      looking for.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ModuleInfo *GetModuleInfo(const char *tag,ExceptionInfo *exception)
+{
+  if ((module_list == (SplayTreeInfo *) NULL) ||
+      (instantiate_module == MagickFalse))
+    if (InitializeModuleList(exception) == MagickFalse)
+      return((ModuleInfo *) NULL);
+  if ((module_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(module_list) == 0))
+    return((ModuleInfo *) NULL);
+  if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
+    {
+      ModuleInfo
+        *p;
+
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+      if (LocaleCompare(tag,"*") == 0)
+        (void) OpenModules(exception);
+#endif
+      LockSemaphoreInfo(module_semaphore);
+      ResetSplayTreeIterator(module_list);
+      p=(ModuleInfo *) GetNextValueInSplayTree(module_list);
+      UnlockSemaphoreInfo(module_semaphore);
+      return(p);
+    }
+  return((ModuleInfo *) GetValueFromSplayTree(module_list,tag));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M o d u l e I n f o L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetModuleInfoList() returns any modules that match the specified pattern.
+%
+%  The format of the GetModuleInfoList function is:
+%
+%      const ModuleInfo **GetModuleInfoList(const char *pattern,
+%        size_t *number_modules,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_modules:  This integer returns the number of modules in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int ModuleInfoCompare(const void *x,const void *y)
+{
+  const ModuleInfo
+    **p,
+    **q;
+
+  p=(const ModuleInfo **) x,
+  q=(const ModuleInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->tag,(*q)->tag));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const ModuleInfo **GetModuleInfoList(const char *pattern,
+  size_t *number_modules,ExceptionInfo *exception)
+{
+  const ModuleInfo
+    **modules;
+
+  register const ModuleInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate module list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_modules != (size_t *) NULL);
+  *number_modules=0;
+  p=GetModuleInfo("*",exception);
+  if (p == (const ModuleInfo *) NULL)
+    return((const ModuleInfo **) NULL);
+  modules=(const ModuleInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(module_list)+1UL,sizeof(*modules));
+  if (modules == (const ModuleInfo **) NULL)
+    return((const ModuleInfo **) NULL);
+  /*
+    Generate module list.
+  */
+  LockSemaphoreInfo(module_semaphore);
+  ResetSplayTreeIterator(module_list);
+  p=(const ModuleInfo *) GetNextValueInSplayTree(module_list);
+  for (i=0; p != (const ModuleInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->tag,pattern,MagickFalse) != MagickFalse))
+      modules[i++]=p;
+    p=(const ModuleInfo *) GetNextValueInSplayTree(module_list);
+  }
+  UnlockSemaphoreInfo(module_semaphore);
+  qsort((void *) modules,(size_t) i,sizeof(*modules),ModuleInfoCompare);
+  modules[i]=(ModuleInfo *) NULL;
+  *number_modules=(size_t) i;
+  return(modules);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M o d u l e L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetModuleList() returns any image format modules that match the specified
+%  pattern.
+%
+%  The format of the GetModuleList function is:
+%
+%      char **GetModuleList(const char *pattern,const MagickModuleType type,
+%        size_t *number_modules,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o type: choose from MagickImageCoderModule or MagickImageFilterModule.
+%
+%    o number_modules:  This integer returns the number of modules in the
+%      list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int ModuleCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+   p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
+  struct dirent **result)
+{
+#if defined(MAGICKCORE_HAVE_READDIR_R)
+  return(readdir_r(directory,entry,result));
+#else
+  (void) entry;
+  errno=0;
+  *result=readdir(directory);
+  return(errno);
+#endif
+}
+
+MagickExport char **GetModuleList(const char *pattern,
+  const MagickModuleType type,size_t *number_modules,ExceptionInfo *exception)
+{
+  char
+    **modules,
+    filename[MaxTextExtent],
+    module_path[MaxTextExtent],
+    path[MaxTextExtent];
+
+  DIR
+    *directory;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    max_entries;
+
+  struct dirent
+    *buffer,
+    *entry;
+
+  /*
+    Locate all modules in the image coder or filter path.
+  */
+  switch (type)
+  {
+    case MagickImageCoderModule:
+    default:
+    {
+      TagToCoderModuleName("magick",filename);
+      status=GetMagickModulePath(filename,MagickImageCoderModule,module_path,
+        exception);
+      break;
+    }
+    case MagickImageFilterModule:
+    {
+      TagToFilterModuleName("analyze",filename);
+      status=GetMagickModulePath(filename,MagickImageFilterModule,module_path,
+        exception);
+      break;
+    }
+  }
+  if (status == MagickFalse)
+    return((char **) NULL);
+  GetPathComponent(module_path,HeadPath,path);
+  max_entries=255;
+  modules=(char **) AcquireQuantumMemory((size_t) max_entries+1UL,
+    sizeof(*modules));
+  if (modules == (char **) NULL)
+    return((char **) NULL);
+  *modules=(char *) NULL;
+  directory=opendir(path);
+  if (directory == (DIR *) NULL)
+    {
+      modules=(char **) RelinquishMagickMemory(modules);
+      return((char **) NULL);
+    }
+  buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
+    FILENAME_MAX+1);
+  if (buffer == (struct dirent *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  i=0;
+  while ((MagickReadDirectory(directory,buffer,&entry) == 0) &&
+         (entry != (struct dirent *) NULL))
+  {
+    status=GlobExpression(entry->d_name,ModuleGlobExpression,MagickFalse);
+    if (status == MagickFalse)
+      continue;
+    if (GlobExpression(entry->d_name,pattern,MagickFalse) == MagickFalse)
+      continue;
+    if (i >= (ssize_t) max_entries)
+      {
+        modules=(char **) NULL;
+        if (~max_entries > max_entries)
+          modules=(char **) ResizeQuantumMemory(modules,(size_t)
+            (max_entries << 1),sizeof(*modules));
+        max_entries<<=1;
+        if (modules == (char **) NULL)
+          break;
+      }
+    /*
+      Add new module name to list.
+    */
+    modules[i]=AcquireString((char *) NULL);
+    GetPathComponent(entry->d_name,BasePath,modules[i]);
+    if (LocaleNCompare("IM_MOD_",modules[i],7) == 0)
+      {
+        (void) CopyMagickString(modules[i],modules[i]+10,MaxTextExtent);
+        modules[i][strlen(modules[i])-1]='\0';
+      }
+    i++;
+  }
+  buffer=(struct dirent *) RelinquishMagickMemory(buffer);
+  (void) closedir(directory);
+  if (modules == (char **) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ConfigureError,
+        "MemoryAllocationFailed","`%s'",pattern);
+      return((char **) NULL);
+    }
+  qsort((void *) modules,(size_t) i,sizeof(*modules),ModuleCompare);
+  modules[i]=(char *) NULL;
+  *number_modules=(size_t) i;
+  return(modules);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t M a g i c k M o d u l e P a t h                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickModulePath() finds a module with the specified module type and
+%  filename.
+%
+%  The format of the GetMagickModulePath module is:
+%
+%      MagickBooleanType GetMagickModulePath(const char *filename,
+%        MagickModuleType module_type,char *path,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the module file name.
+%
+%    o module_type: the module type: MagickImageCoderModule or
+%      MagickImageFilterModule.
+%
+%    o path: the path associated with the filename.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType GetMagickModulePath(const char *filename,
+  MagickModuleType module_type,char *path,ExceptionInfo *exception)
+{
+  char
+    *module_path;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(path != (char *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  (void) CopyMagickString(path,filename,MaxTextExtent);
+  module_path=(char *) NULL;
+  switch (module_type)
+  {
+    case MagickImageCoderModule:
+    default:
+    {
+      (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+        "Searching for coder module file \"%s\" ...",filename);
+      module_path=GetEnvironmentValue("MAGICK_CODER_MODULE_PATH");
+#if defined(MAGICKCORE_CODER_PATH)
+      if (module_path == (char *) NULL)
+        module_path=AcquireString(MAGICKCORE_CODER_PATH);
+#endif
+      break;
+    }
+    case MagickImageFilterModule:
+    {
+      (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+        "Searching for filter module file \"%s\" ...",filename);
+      module_path=GetEnvironmentValue("MAGICK_CODER_FILTER_PATH");
+#if defined(MAGICKCORE_FILTER_PATH)
+      if (module_path == (char *) NULL)
+        module_path=AcquireString(MAGICKCORE_FILTER_PATH);
+#endif
+      break;
+    }
+  }
+  if (module_path != (char *) NULL)
+    {
+      register char
+        *p,
+        *q;
+
+      for (p=module_path-1; p != (char *) NULL; )
+      {
+        (void) CopyMagickString(path,p+1,MaxTextExtent);
+        q=strchr(path,DirectoryListSeparator);
+        if (q != (char *) NULL)
+          *q='\0';
+        q=path+strlen(path)-1;
+        if ((q >= path) && (*q != *DirectorySeparator))
+          (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent);
+        (void) ConcatenateMagickString(path,filename,MaxTextExtent);
+        if (IsPathAccessible(path) != MagickFalse)
+          {
+            module_path=DestroyString(module_path);
+            return(MagickTrue);
+          }
+        p=strchr(p+1,DirectoryListSeparator);
+      }
+      module_path=DestroyString(module_path);
+    }
+#if defined(MAGICKCORE_INSTALLED_SUPPORT)
+  else
+#if defined(MAGICKCORE_CODER_PATH)
+    {
+      const char
+        *directory;
+
+      /*
+        Search hard coded paths.
+      */
+      switch (module_type)
+      {
+        case MagickImageCoderModule:
+        default:
+        {
+          directory=MAGICKCORE_CODER_PATH;
+          break;
+        }
+        case MagickImageFilterModule:
+        {
+          directory=MAGICKCORE_FILTER_PATH;
+          break;
+        }
+      }
+      (void) FormatLocaleString(path,MaxTextExtent,"%s%s",directory,filename);
+      if (IsPathAccessible(path) == MagickFalse)
+        {
+          ThrowFileException(exception,ConfigureWarning,
+            "UnableToOpenModuleFile",path);
+          return(MagickFalse);
+        }
+      return(MagickTrue);
+    }
+#else
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+    {
+      const char
+        *registery_key;
+
+      unsigned char
+        *key_value;
+
+      /*
+        Locate path via registry key.
+      */
+      switch (module_type)
+      {
+        case MagickImageCoderModule:
+        default:
+        {
+          registery_key="CoderModulesPath";
+          break;
+        }
+        case MagickImageFilterModule:
+        {
+          registery_key="FilterModulesPath";
+          break;
+        }
+      }
+      key_value=NTRegistryKeyLookup(registery_key);
+      if (key_value == (unsigned char *) NULL)
+        {
+          ThrowMagickException(exception,GetMagickModule(),ConfigureError,
+            "RegistryKeyLookupFailed","`%s'",registery_key);
+          return(MagickFalse);
+        }
+      (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",(char *) key_value,
+        DirectorySeparator,filename);
+      key_value=(unsigned char *) RelinquishMagickMemory(key_value);
+      if (IsPathAccessible(path) == MagickFalse)
+        {
+          ThrowFileException(exception,ConfigureWarning,
+            "UnableToOpenModuleFile",path);
+          return(MagickFalse);
+        }
+      return(MagickTrue);
+    }
+#endif
+#endif
+#if !defined(MAGICKCORE_CODER_PATH) && !defined(MAGICKCORE_WINDOWS_SUPPORT)
+# error MAGICKCORE_CODER_PATH or MAGICKCORE_WINDOWS_SUPPORT must be defined when MAGICKCORE_INSTALLED_SUPPORT is defined
+#endif
+#else
+  {
+    char
+      *home;
+
+    home=GetEnvironmentValue("MAGICK_HOME");
+    if (home != (char *) NULL)
+      {
+        /*
+          Search MAGICK_HOME.
+        */
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",home,
+          DirectorySeparator,filename);
+#else
+        const char
+          *directory;
+
+        switch (module_type)
+        {
+          case MagickImageCoderModule:
+          default:
+          {
+            directory=MAGICKCORE_CODER_RELATIVE_PATH;
+            break;
+          }
+          case MagickImageFilterModule:
+          {
+            directory=MAGICKCORE_FILTER_RELATIVE_PATH;
+            break;
+          }
+        }
+        (void) FormatLocaleString(path,MaxTextExtent,"%s/lib/%s/%s",home,
+          directory,filename);
+#endif
+        home=DestroyString(home);
+        if (IsPathAccessible(path) != MagickFalse)
+          return(MagickTrue);
+      }
+  }
+  if (*GetClientPath() != '\0')
+    {
+      /*
+        Search based on executable directory.
+      */
+#if !defined(MAGICKCORE_POSIX_SUPPORT)
+      (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",GetClientPath(),
+        DirectorySeparator,filename);
+#else
+      char
+        prefix[MaxTextExtent];
+
+      const char
+        *directory;
+
+      switch (module_type)
+      {
+        case MagickImageCoderModule:
+        default:
+        {
+          directory="modules";
+          break;
+        }
+        case MagickImageFilterModule:
+        {
+          directory="filters";
+          break;
+        }
+      }
+      (void) CopyMagickString(prefix,GetClientPath(),MaxTextExtent);
+      ChopPathComponents(prefix,1);
+      (void) FormatLocaleString(path,MaxTextExtent,
+        "%s/lib/%s/modules-Q%d/%s/%s",prefix,MAGICKCORE_LIBRARY_RELATIVE_PATH,
+        MAGICKCORE_QUANTUM_DEPTH,directory,filename);
+#endif
+      if (IsPathAccessible(path) != MagickFalse)
+        return(MagickTrue);
+    }
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    /*
+      Search module path.
+    */
+    if ((NTGetModulePath("CORE_RL_magick_.dll",path) != MagickFalse) ||
+        (NTGetModulePath("CORE_DB_magick_.dll",path) != MagickFalse) ||
+        (NTGetModulePath("Magick.dll",path) != MagickFalse))
+      {
+        (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent);
+        (void) ConcatenateMagickString(path,filename,MaxTextExtent);
+        if (IsPathAccessible(path) != MagickFalse)
+          return(MagickTrue);
+      }
+  }
+#endif
+  {
+    char
+      *home;
+
+    home=GetEnvironmentValue("HOME");
+    if (home == (char *) NULL)
+      home=GetEnvironmentValue("USERPROFILE");
+    if (home != (char *) NULL)
+      {
+        /*
+          Search $HOME/.magick.
+        */
+        (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick%s%s",home,
+          DirectorySeparator,DirectorySeparator,filename);
+        home=DestroyString(home);
+        if (IsPathAccessible(path) != MagickFalse)
+          return(MagickTrue);
+      }
+  }
+  /*
+    Search current directory.
+  */
+  if (IsPathAccessible(path) != MagickFalse)
+    return(MagickTrue);
+  if (exception->severity < ConfigureError)
+    ThrowFileException(exception,ConfigureWarning,"UnableToOpenModuleFile",
+      path);
+  return(MagickFalse);
+#endif
+  return(MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n i t i a l i z e M o d u l e L i s t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeModuleList() initializes the module loader.
+%
+%  The format of the InitializeModuleList() method is:
+%
+%      InitializeModuleList(Exceptioninfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void *DestroyModuleNode(void *module_info)
+{
+  ExceptionInfo
+    *exception;
+
+  register ModuleInfo
+    *p;
+
+  exception=AcquireExceptionInfo();
+  p=(ModuleInfo *) module_info;
+  if (UnregisterModule(p,exception) == MagickFalse)
+    CatchException(exception);
+  if (p->tag != (char *) NULL)
+    p->tag=DestroyString(p->tag);
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  exception=DestroyExceptionInfo(exception);
+  return(RelinquishMagickMemory(p));
+}
+
+MagickExport MagickBooleanType InitializeModuleList(
+  ExceptionInfo *magick_unused(exception))
+{
+  if ((module_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_module == MagickFalse))
+    {
+      if (module_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&module_semaphore);
+      LockSemaphoreInfo(module_semaphore);
+      if ((module_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_module == MagickFalse))
+        {
+          MagickBooleanType
+            status;
+
+          ModuleInfo
+            *module_info;
+
+          module_list=NewSplayTree(CompareSplayTreeString,
+            (void *(*)(void *)) NULL,DestroyModuleNode);
+          if (module_list == (SplayTreeInfo *) NULL)
+            ThrowFatalException(ResourceLimitFatalError,
+              "MemoryAllocationFailed");
+          module_info=AcquireModuleInfo((const char *) NULL,"[boot-strap]");
+          module_info->stealth=MagickTrue;
+          status=AddValueToSplayTree(module_list,module_info->tag,module_info);
+          if (status == MagickFalse)
+            ThrowFatalException(ResourceLimitFatalError,
+              "MemoryAllocationFailed");
+          if (lt_dlinit() != 0)
+            ThrowFatalException(ModuleFatalError,
+              "UnableToInitializeModuleLoader");
+          instantiate_module=MagickTrue;
+        }
+      UnlockSemaphoreInfo(module_semaphore);
+    }
+  return(module_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n v o k e D y n a m i c I m a g e F i l t e r                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InvokeDynamicImageFilter() invokes a dynamic image filter.
+%
+%  The format of the InvokeDynamicImageFilter module is:
+%
+%      MagickBooleanType InvokeDynamicImageFilter(const char *tag,Image **image,
+%        const int argc,const char **argv,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o tag: a character string that represents the name of the particular
+%      module.
+%
+%    o image: the image.
+%
+%    o argc: a pointer to an integer describing the number of elements in the
+%      argument vector.
+%
+%    o argv: a pointer to a text array containing the command line arguments.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType InvokeDynamicImageFilter(const char *tag,
+  Image **images,const int argc,const char **argv,ExceptionInfo *exception)
+{
+  char
+    name[MaxTextExtent],
+    path[MaxTextExtent];
+
+  ImageFilterHandler
+    *image_filter;
+
+  MagickBooleanType
+    status;
+
+  ModuleHandle
+    handle;
+
+  PolicyRights
+    rights;
+
+  /*
+    Find the module.
+  */
+  assert(images != (Image **) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+#if !defined(MAGICKCORE_BUILD_MODULES)
+  {
+    MagickBooleanType
+      status;
+
+    status=InvokeStaticImageFilter(tag,images,argc,argv,exception);
+    if (status != MagickFalse)
+      return(status);
+  }
+#endif
+  rights=ReadPolicyRights;
+  if (IsRightsAuthorized(FilterPolicyDomain,rights,tag) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",tag);
+      return(MagickFalse);
+    }
+  TagToFilterModuleName(tag,name);
+  status=GetMagickModulePath(name,MagickImageFilterModule,path,exception);
+  if (status == MagickFalse)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToLoadModule","`%s': %s",name,path);
+      return(MagickFalse);
+    }
+  /*
+    Open the module.
+  */
+  handle=(ModuleHandle) lt_dlopen(path);
+  if (handle == (ModuleHandle) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToLoadModule","`%s': %s",name,lt_dlerror());
+      return(MagickFalse);
+    }
+  /*
+    Locate the module.
+  */
+#if !defined(MAGICKCORE_NAMESPACE_PREFIX)
+  (void) FormatLocaleString(name,MaxTextExtent,"%sImage",tag);
+#else
+  (void) FormatLocaleString(name,MaxTextExtent,"%s%sImage",
+    MAGICKCORE_NAMESPACE_PREFIX,tag);
+#endif
+  /*
+    Execute the module.
+  */
+  ClearMagickException(exception);
+  image_filter=(ImageFilterHandler *) lt_dlsym(handle,name);
+  if (image_filter == (ImageFilterHandler *) NULL)
+    (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+      "UnableToLoadModule","`%s': %s",name,lt_dlerror());
+  else
+    {
+      size_t
+        signature;
+
+      if ((*images)->debug != MagickFalse)
+        (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+          "Invoking \"%s\" dynamic image filter",tag);
+      signature=image_filter(images,argc,argv,exception);
+      if ((*images)->debug != MagickFalse)
+        (void) LogMagickEvent(ModuleEvent,GetMagickModule(),"\"%s\" completes",
+          tag);
+      if (signature != MagickImageFilterSignature)
+        (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+          "ImageFilterSignatureMismatch","`%s': %8lx != %8lx",tag,
+          (unsigned long) signature,(unsigned long) MagickImageFilterSignature);
+    }
+  /*
+    Close the module.
+  */
+  if (lt_dlclose(handle) != 0)
+    (void) ThrowMagickException(exception,GetMagickModule(),ModuleWarning,
+      "UnableToCloseModule","`%s': %s",name,lt_dlerror());
+  return(exception->severity < ErrorException ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t M o d u l e I n f o                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListModuleInfo() lists the module info to a file.
+%
+%  The format of the ListModuleInfo module is:
+%
+%      MagickBooleanType ListModuleInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListModuleInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  char
+    filename[MaxTextExtent],
+    module_path[MaxTextExtent],
+    **modules,
+    path[MaxTextExtent];
+
+  register ssize_t
+    i;
+
+  size_t
+    number_modules;
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  /*
+    List image coders.
+  */
+  modules=GetModuleList("*",MagickImageCoderModule,&number_modules,exception);
+  if (modules == (char **) NULL)
+    return(MagickFalse);
+  TagToCoderModuleName("magick",filename);
+  (void) GetMagickModulePath(filename,MagickImageCoderModule,module_path,
+    exception);
+  GetPathComponent(module_path,HeadPath,path);
+  (void) FormatLocaleFile(file,"\nPath: %s\n\n",path);
+  (void) FormatLocaleFile(file,"Image Coder\n");
+  (void) FormatLocaleFile(file,
+    "-------------------------------------------------"
+    "------------------------------\n");
+  for (i=0; i < (ssize_t) number_modules; i++)
+  {
+    (void) FormatLocaleFile(file,"%s",modules[i]);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  /*
+    Relinquish resources.
+  */
+  for (i=0; i < (ssize_t) number_modules; i++)
+    modules[i]=DestroyString(modules[i]);
+  modules=(char **) RelinquishMagickMemory(modules);
+  /*
+    List image filters.
+  */
+  modules=GetModuleList("*",MagickImageFilterModule,&number_modules,exception);
+  if (modules == (char **) NULL)
+    return(MagickFalse);
+  TagToFilterModuleName("analyze",filename);
+  (void) GetMagickModulePath(filename,MagickImageFilterModule,module_path,
+    exception);
+  GetPathComponent(module_path,HeadPath,path);
+  (void) FormatLocaleFile(file,"\nPath: %s\n\n",path);
+  (void) FormatLocaleFile(file,"Image Filter\n");
+  (void) FormatLocaleFile(file,
+    "-------------------------------------------------"
+    "------------------------------\n");
+  for (i=0; i < (ssize_t) number_modules; i++)
+  {
+    (void) FormatLocaleFile(file,"%s",modules[i]);
+    (void) FormatLocaleFile(file,"\n");
+  }
+  (void) fflush(file);
+  /*
+    Relinquish resources.
+  */
+  for (i=0; i < (ssize_t) number_modules; i++)
+    modules[i]=DestroyString(modules[i]);
+  modules=(char **) RelinquishMagickMemory(modules);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M o d u l e C o m p o n e n t G e n e s i s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ModuleComponentGenesis() instantiates the module component.
+%
+%  The format of the ModuleComponentGenesis method is:
+%
+%      MagickBooleanType ModuleComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType ModuleComponentGenesis(void)
+{
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  AcquireSemaphoreInfo(&module_semaphore);
+  exception=AcquireExceptionInfo();
+  status=InitializeModuleList(exception);
+  exception=DestroyExceptionInfo(exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   M o d u l e C o m p o n e n t T e r m i n u s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ModuleComponentTerminus() destroys the module component.
+%
+%  The format of the ModuleComponentTerminus method is:
+%
+%      ModuleComponentTerminus(void)
+%
+*/
+MagickExport void ModuleComponentTerminus(void)
+{
+  if (module_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&module_semaphore);
+  DestroyModuleList();
+  DestroySemaphoreInfo(&module_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   O p e n M o d u l e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenModule() loads a module, and invokes its registration module.  It
+%  returns MagickTrue on success, and MagickFalse if there is an error.
+%
+%  The format of the OpenModule module is:
+%
+%      MagickBooleanType OpenModule(const char *module,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o module: a character string that indicates the module to load.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType OpenModule(const char *module,
+  ExceptionInfo *exception)
+{
+  char
+    filename[MaxTextExtent],
+    module_name[MaxTextExtent],
+    name[MaxTextExtent],
+    path[MaxTextExtent];
+
+  MagickBooleanType
+    status;
+
+  ModuleHandle
+    handle;
+
+  ModuleInfo
+    *module_info;
+
+  register const CoderInfo
+    *p;
+
+  size_t
+    signature;
+
+  /*
+    Assign module name from alias.
+  */
+  assert(module != (const char *) NULL);
+  module_info=(ModuleInfo *) GetModuleInfo(module,exception);
+  if (module_info != (ModuleInfo *) NULL)
+    return(MagickTrue);
+  (void) CopyMagickString(module_name,module,MaxTextExtent);
+  p=GetCoderInfo(module,exception);
+  if (p != (CoderInfo *) NULL)
+    (void) CopyMagickString(module_name,p->name,MaxTextExtent);
+  if (GetValueFromSplayTree(module_list,module_name) != (void *) NULL)
+    return(MagickTrue);  /* module already opened, return */
+  /*
+    Locate module.
+  */
+  handle=(ModuleHandle) NULL;
+  TagToCoderModuleName(module_name,filename);
+  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+    "Searching for module \"%s\" using filename \"%s\"",module_name,filename);
+  *path='\0';
+  status=GetMagickModulePath(filename,MagickImageCoderModule,path,exception);
+  if (status == MagickFalse)
+    return(MagickFalse);
+  /*
+    Load module
+  */
+  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+    "Opening module at path \"%s\"",path);
+  handle=(ModuleHandle) lt_dlopen(path);
+  if (handle == (ModuleHandle) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToLoadModule","`%s': %s",path,lt_dlerror());
+      return(MagickFalse);
+    }
+  /*
+    Register module.
+  */
+  module_info=AcquireModuleInfo(path,module_name);
+  module_info->handle=handle;
+  if (RegisterModule(module_info,exception) == (ModuleInfo *) NULL)
+    return(MagickFalse);
+  /*
+    Define RegisterFORMATImage method.
+  */
+  TagToModuleName(module_name,"Register%sImage",name);
+  module_info->register_module=(size_t (*)(void)) lt_dlsym(handle,name);
+  if (module_info->register_module == (size_t (*)(void)) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToRegisterImageFormat","`%s': %s",module_name,lt_dlerror());
+      return(MagickFalse);
+    }
+  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+    "Method \"%s\" in module \"%s\" at address %p",name,module_name,
+    (void *) module_info->register_module);
+  /*
+    Define UnregisterFORMATImage method.
+  */
+  TagToModuleName(module_name,"Unregister%sImage",name);
+  module_info->unregister_module=(void (*)(void)) lt_dlsym(handle,name);
+  if (module_info->unregister_module == (void (*)(void)) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToRegisterImageFormat","`%s': %s",module_name,lt_dlerror());
+      return(MagickFalse);
+    }
+  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
+    "Method \"%s\" in module \"%s\" at address %p",name,module_name,
+    (void *) module_info->unregister_module);
+  signature=module_info->register_module();
+  if (signature != MagickImageCoderSignature)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "ImageCoderSignatureMismatch","`%s': %8lx != %8lx",module_name,
+        (unsigned long) signature,(unsigned long) MagickImageCoderSignature);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   O p e n M o d u l e s                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenModules() loads all available modules.
+%
+%  The format of the OpenModules module is:
+%
+%      MagickBooleanType OpenModules(ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType OpenModules(ExceptionInfo *exception)
+{
+  char
+    **modules;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_modules;
+
+  /*
+    Load all modules.
+  */
+  (void) GetMagickInfo((char *) NULL,exception);
+  number_modules=0;
+  modules=GetModuleList("*",MagickImageCoderModule,&number_modules,exception);
+  if (modules == (char **) NULL)
+    return(MagickFalse);
+  for (i=0; i < (ssize_t) number_modules; i++)
+    (void) OpenModule(modules[i],exception);
+  /*
+    Relinquish resources.
+  */
+  for (i=0; i < (ssize_t) number_modules; i++)
+    modules[i]=DestroyString(modules[i]);
+  modules=(char **) RelinquishMagickMemory(modules);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e g i s t e r M o d u l e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RegisterModule() adds an entry to the module list.  It returns a pointer to
+%  the registered entry on success.
+%
+%  The format of the RegisterModule module is:
+%
+%      ModuleInfo *RegisterModule(const ModuleInfo *module_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o info: a pointer to the registered entry is returned.
+%
+%    o module_info: a pointer to the ModuleInfo structure to register.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static const ModuleInfo *RegisterModule(const ModuleInfo *module_info,
+  ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  assert(module_info != (ModuleInfo *) NULL);
+  assert(module_info->signature == MagickSignature);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",module_info->tag);
+  if (module_list == (SplayTreeInfo *) NULL)
+    return((const ModuleInfo *) NULL);
+  status=AddValueToSplayTree(module_list,module_info->tag,module_info);
+  if (status == MagickFalse)
+    (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
+      "MemoryAllocationFailed","`%s'",module_info->tag);
+  return(module_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  T a g T o C o d e r M o d u l e N a m e                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TagToCoderModuleName() munges a module tag and obtains the filename of the
+%  corresponding module.
+%
+%  The format of the TagToCoderModuleName module is:
+%
+%      char *TagToCoderModuleName(const char *tag,char *name)
+%
+%  A description of each parameter follows:
+%
+%    o tag: a character string representing the module tag.
+%
+%    o name: return the module name here.
+%
+*/
+static void TagToCoderModuleName(const char *tag,char *name)
+{
+  assert(tag != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tag);
+  assert(name != (char *) NULL);
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+  (void) FormatLocaleString(name,MaxTextExtent,"%s.la",tag);
+  (void) LocaleLower(name);
+#else
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  if (LocaleNCompare("IM_MOD_",tag,7) == 0)
+    (void) CopyMagickString(name,tag,MaxTextExtent);
+  else
+    {
+#if defined(_DEBUG)
+      (void) FormatLocaleString(name,MaxTextExtent,"IM_MOD_DB_%s_.dll",tag);
+#else
+      (void) FormatLocaleString(name,MaxTextExtent,"IM_MOD_RL_%s_.dll",tag);
+#endif
+    }
+#endif
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  T a g T o F i l t e r M o d u l e N a m e                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TagToFilterModuleName() munges a module tag and returns the filename of the
+%  corresponding filter module.
+%
+%  The format of the TagToFilterModuleName module is:
+%
+%      void TagToFilterModuleName(const char *tag,char name)
+%
+%  A description of each parameter follows:
+%
+%    o tag: a character string representing the module tag.
+%
+%    o name: return the filter name here.
+%
+*/
+static void TagToFilterModuleName(const char *tag,char *name)
+{
+  assert(tag != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tag);
+  assert(name != (char *) NULL);
+#if !defined(MAGICKCORE_LTDL_DELEGATE)
+  (void) FormatLocaleString(name,MaxTextExtent,"%s.dll",tag);
+#else
+  (void) FormatLocaleString(name,MaxTextExtent,"%s.la",tag);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T a g T o M o d u l e N a m e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TagToModuleName() munges the module tag name and returns an upper-case tag
+%  name as the input string, and a user-provided format.
+%
+%  The format of the TagToModuleName module is:
+%
+%      TagToModuleName(const char *tag,const char *format,char *module)
+%
+%  A description of each parameter follows:
+%
+%    o tag: the module tag.
+%
+%    o format: a sprintf-compatible format string containing %s where the
+%      upper-case tag name is to be inserted.
+%
+%    o module: pointer to a destination buffer for the formatted result.
+%
+*/
+static void TagToModuleName(const char *tag,const char *format,char *module)
+{
+  char
+    name[MaxTextExtent];
+
+  assert(tag != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tag);
+  assert(format != (const char *) NULL);
+  assert(module != (char *) NULL);
+  (void) CopyMagickString(name,tag,MaxTextExtent);
+  LocaleUpper(name);
+#if !defined(MAGICKCORE_NAMESPACE_PREFIX)
+  (void) FormatLocaleString(module,MaxTextExtent,format,name);
+#else
+  {
+    char
+      prefix_format[MaxTextExtent];
+
+    (void) FormatLocaleString(prefix_format,MaxTextExtent,"%s%s",
+      MAGICKCORE_NAMESPACE_PREFIX,format);
+    (void) FormatLocaleString(module,MaxTextExtent,prefix_format,name);
+  }
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   U n r e g i s t e r M o d u l e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnregisterModule() unloads a module, and invokes its de-registration module.
+%  Returns MagickTrue on success, and MagickFalse if there is an error.
+%
+%  The format of the UnregisterModule module is:
+%
+%      MagickBooleanType UnregisterModule(const ModuleInfo *module_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o module_info: the module info.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType UnregisterModule(const ModuleInfo *module_info,
+  ExceptionInfo *exception)
+{
+  /*
+    Locate and execute UnregisterFORMATImage module.
+  */
+  assert(module_info != (const ModuleInfo *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",module_info->tag);
+  assert(exception != (ExceptionInfo *) NULL);
+  if (module_info->unregister_module == NULL)
+    return(MagickTrue);
+  module_info->unregister_module();
+  if (lt_dlclose((ModuleHandle) module_info->handle) != 0)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleWarning,
+        "UnableToCloseModule","`%s': %s",module_info->tag,lt_dlerror());
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+#else
+MagickExport MagickBooleanType ListModuleInfo(FILE *magick_unused(file),
+  ExceptionInfo *magick_unused(exception))
+{
+  return(MagickTrue);
+}
+
+MagickExport MagickBooleanType InvokeDynamicImageFilter(const char *tag,
+  Image **image,const int argc,const char **argv,ExceptionInfo *exception)
+{
+  PolicyRights
+    rights;
+
+  assert(image != (Image **) NULL);
+  assert((*image)->signature == MagickSignature);
+  if ((*image)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
+  rights=ReadPolicyRights;
+  if (IsRightsAuthorized(FilterPolicyDomain,rights,tag) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",tag);
+      return(MagickFalse);
+    }
+#if defined(MAGICKCORE_BUILD_MODULES)
+  (void) tag;
+  (void) argc;
+  (void) argv;
+  (void) exception;
+#else
+  {
+    extern size_t
+      analyzeImage(Image **,const int,const char **,ExceptionInfo *);
+
+    ImageFilterHandler
+      *image_filter;
+
+    image_filter=(ImageFilterHandler *) NULL;
+    if (LocaleCompare("analyze",tag) == 0)
+      image_filter=(ImageFilterHandler *) analyzeImage;
+    if (image_filter == (ImageFilterHandler *) NULL)
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToLoadModule","`%s'",tag);
+    else
+      {
+        size_t
+          signature;
+
+        if ((*image)->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "Invoking \"%s\" static image filter",tag);
+        signature=image_filter(image,argc,argv,exception);
+        if ((*image)->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"\"%s\" completes",
+            tag);
+        if (signature != MagickImageFilterSignature)
+          {
+            (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+              "ImageFilterSignatureMismatch","`%s': %8lx != %8lx",tag,
+              (unsigned long) signature,(unsigned long)
+              MagickImageFilterSignature);
+            return(MagickFalse);
+          }
+      }
+  }
+#endif
+  return(MagickTrue);
+}
+#endif
diff --git a/MagickCore/module.h b/MagickCore/module.h
new file mode 100644
index 0000000..1f64f11
--- /dev/null
+++ b/MagickCore/module.h
@@ -0,0 +1,93 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore module methods.
+*/
+#ifndef _MAGICKCORE_MODULE_H
+#define _MAGICKCORE_MODULE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <time.h>
+#include "MagickCore/version.h"
+
+#define MagickImageCoderSignature  ((size_t) \
+  (((MagickLibVersion) << 8) | MAGICKCORE_QUANTUM_DEPTH))
+#define MagickImageFilterSignature  ((size_t) \
+  (((MagickLibVersion) << 8) | MAGICKCORE_QUANTUM_DEPTH))
+
+typedef enum
+{
+  MagickImageCoderModule,
+  MagickImageFilterModule
+} MagickModuleType;
+
+typedef struct _ModuleInfo
+{
+  char
+    *path,
+    *tag;
+
+  void
+    *handle,
+    (*unregister_module)(void);
+
+  size_t
+    (*register_module)(void);
+
+  time_t
+    timestamp;
+
+  MagickBooleanType
+    stealth;
+
+  size_t
+    signature;
+} ModuleInfo;
+
+typedef ModuleExport size_t
+  ImageFilterHandler(Image **,const int,const char **,ExceptionInfo *);
+
+extern MagickExport char
+  **GetModuleList(const char *,const MagickModuleType,size_t *,ExceptionInfo *);
+
+extern MagickExport const ModuleInfo
+  **GetModuleInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  InitializeModuleList(ExceptionInfo *),
+  InvokeDynamicImageFilter(const char *,Image **,const int,const char **,
+    ExceptionInfo *),
+  ListModuleInfo(FILE *,ExceptionInfo *),
+  ModuleComponentGenesis(void),
+  OpenModule(const char *,ExceptionInfo *),
+  OpenModules(ExceptionInfo *);
+
+extern MagickExport ModuleInfo
+  *GetModuleInfo(const char *,ExceptionInfo *);
+
+extern MagickExport void
+  DestroyModuleList(void),
+  ModuleComponentTerminus(void),
+  RegisterStaticModules(void),
+  UnregisterStaticModules(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/monitor-private.h b/MagickCore/monitor-private.h
new file mode 100644
index 0000000..7eaf99e
--- /dev/null
+++ b/MagickCore/monitor-private.h
@@ -0,0 +1,43 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  The ImageMagick progress monitor private methods.
+*/
+#ifndef _MAGICK_MONITOR_PRIVATE_H
+#define _MAGICK_MONITOR_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/image.h>
+
+static inline MagickBooleanType SetImageProgress(const Image *image,
+  const char *tag,const MagickOffsetType offset,const MagickSizeType extent)
+{
+  char
+    message[MaxTextExtent];
+
+  if (image->progress_monitor == (MagickProgressMonitor) NULL)
+    return(MagickTrue);
+  (void) FormatLocaleString(message,MaxTextExtent,"%s/%s",tag,image->filename);
+  return(image->progress_monitor(message,offset,extent,image->client_data));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/monitor.c b/MagickCore/monitor.c
new file mode 100644
index 0000000..20c4840
--- /dev/null
+++ b/MagickCore/monitor.c
@@ -0,0 +1,145 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               M   M   OOO   N   N  IIIII  TTTTT   OOO   RRRR                %
+%               MM MM  O   O  NN  N    I      T    O   O  R   R               %
+%               M M M  O   O  N N N    I      T    O   O  RRRR                %
+%               M   M  O   O  N  NN    I      T    O   O  R R                 %
+%               M   M   OOO   N   N  IIIII    T     OOO   R  R                %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Progress Monitor Methods                     %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               December 1995                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/image.h"
+#include "MagickCore/log.h"
+#include "MagickCore/monitor.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e P r o g r e s s M o n i t o r                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageProgressMonitor() sets the image progress monitor to the specified
+%  method and returns the previous progress monitor if any.  The progress
+%  monitor method looks like this:
+%
+%    MagickBooleanType MagickProgressMonitor(const char *text,
+%      const MagickOffsetType offset,const MagickSizeType extent,
+%      void *client_data)
+%
+%  If the progress monitor returns MagickFalse, the current operation is
+%  interrupted.
+%
+%  The format of the SetImageProgressMonitor method is:
+%
+%      MagickProgressMonitor SetImageProgressMonitor(Image *image,
+%        const MagickProgressMonitor progress_monitor,void *client_data)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o progress_monitor: Specifies a pointer to a method to monitor progress of
+%      an image operation.
+%
+%    o client_data: Specifies a pointer to any client data.
+%
+*/
+MagickExport MagickProgressMonitor SetImageProgressMonitor(Image *image,
+  const MagickProgressMonitor progress_monitor,void *client_data)
+{
+  MagickProgressMonitor
+    previous_monitor;
+
+  previous_monitor=image->progress_monitor;
+  image->progress_monitor=progress_monitor;
+  image->client_data=client_data;
+  return(previous_monitor);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e I n f o P r o g r e s s M o n i t o r                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageInfoProgressMonitor() sets the image_info progress monitor to the
+%  specified method and returns the previous progress monitor if any.  The
+%  progress monitor method looks like this:
+%
+%    MagickBooleanType MagickProgressMonitor(const char *text,
+%      const MagickOffsetType offset,const MagickSizeType extent,
+%      void *client_data)
+%
+%  If the progress monitor returns MagickFalse, the current operation is
+%  interrupted.
+%
+%  The format of the SetImageInfoProgressMonitor method is:
+%
+%      MagickProgressMonitor SetImageInfoProgressMonitor(ImageInfo *image_info,
+%        const MagickProgressMonitor progress_monitor,void *client_data)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o progress_monitor: Specifies a pointer to a method to monitor progress of
+%      an image operation.
+%
+%    o client_data: Specifies a pointer to any client data.
+%
+*/
+MagickExport MagickProgressMonitor SetImageInfoProgressMonitor(
+  ImageInfo *image_info,const MagickProgressMonitor progress_monitor,
+  void *client_data)
+{
+  MagickProgressMonitor
+    previous_monitor;
+
+  previous_monitor=image_info->progress_monitor;
+  image_info->progress_monitor=progress_monitor;
+  image_info->client_data=client_data;
+  return(previous_monitor);
+}
diff --git a/MagickCore/monitor.h b/MagickCore/monitor.h
new file mode 100644
index 0000000..a03a882
--- /dev/null
+++ b/MagickCore/monitor.h
@@ -0,0 +1,49 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore progress monitor methods.
+*/
+#ifndef _MAGICKCORE_MONITOR_H
+#define _MAGICKCORE_MONITOR_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef MagickBooleanType
+  (*MagickProgressMonitor)(const char *,const MagickOffsetType,
+    const MagickSizeType,void *);
+
+MagickExport MagickProgressMonitor
+  SetImageProgressMonitor(Image *,const MagickProgressMonitor,void *),
+  SetImageInfoProgressMonitor(ImageInfo *,const MagickProgressMonitor,void *);
+
+static inline MagickBooleanType QuantumTick(const MagickOffsetType offset,
+  const MagickSizeType span)
+{
+  if (span <= 100)
+    return(MagickTrue);
+  if (offset == (MagickOffsetType) (span-1))
+    return(MagickTrue);
+  if ((offset % (span/100)) == 0)
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/montage.c b/MagickCore/montage.c
new file mode 100644
index 0000000..bebb2e3
--- /dev/null
+++ b/MagickCore/montage.c
@@ -0,0 +1,898 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               M   M   OOO   N   N  TTTTT   AAA    GGGG  EEEEE               %
+%               MM MM  O   O  NN  N    T    A   A  G      E                   %
+%               M M M  O   O  N N N    T    AAAAA  G  GG  EEE                 %
+%               M   M  O   O  N  NN    T    A   A  G   G  E                   %
+%               M   M   OOO   N   N    T    A   A   GGG   EEEEE               %
+%                                                                             %
+%                                                                             %
+%                MagickCore Methods to Create Image Thumbnails                %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/annotate.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/option.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/property.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e M o n t a g e I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneMontageInfo() makes a copy of the given montage info structure.  If
+%  NULL is specified, a new image info structure is created initialized to
+%  default values.
+%
+%  The format of the CloneMontageInfo method is:
+%
+%      MontageInfo *CloneMontageInfo(const ImageInfo *image_info,
+%        const MontageInfo *montage_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o montage_info: the montage info.
+%
+*/
+MagickExport MontageInfo *CloneMontageInfo(const ImageInfo *image_info,
+  const MontageInfo *montage_info)
+{
+  MontageInfo
+    *clone_info;
+
+  clone_info=(MontageInfo *) AcquireMagickMemory(sizeof(*clone_info));
+  if (clone_info == (MontageInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetMontageInfo(image_info,clone_info);
+  if (montage_info == (MontageInfo *) NULL)
+    return(clone_info);
+  if (montage_info->geometry != (char *) NULL)
+    clone_info->geometry=AcquireString(montage_info->geometry);
+  if (montage_info->tile != (char *) NULL)
+    clone_info->tile=AcquireString(montage_info->tile);
+  if (montage_info->title != (char *) NULL)
+    clone_info->title=AcquireString(montage_info->title);
+  if (montage_info->frame != (char *) NULL)
+    clone_info->frame=AcquireString(montage_info->frame);
+  if (montage_info->texture != (char *) NULL)
+    clone_info->texture=AcquireString(montage_info->texture);
+  if (montage_info->font != (char *) NULL)
+    clone_info->font=AcquireString(montage_info->font);
+  clone_info->pointsize=montage_info->pointsize;
+  clone_info->border_width=montage_info->border_width;
+  clone_info->shadow=montage_info->shadow;
+  clone_info->fill=montage_info->fill;
+  clone_info->stroke=montage_info->stroke;
+  clone_info->background_color=montage_info->background_color;
+  clone_info->border_color=montage_info->border_color;
+  clone_info->matte_color=montage_info->matte_color;
+  clone_info->gravity=montage_info->gravity;
+  (void) CopyMagickString(clone_info->filename,montage_info->filename,
+    MaxTextExtent);
+  clone_info->debug=IsEventLogging();
+  return(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y M o n t a g e I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyMontageInfo() deallocates memory associated with montage_info.
+%
+%  The format of the DestroyMontageInfo method is:
+%
+%      MontageInfo *DestroyMontageInfo(MontageInfo *montage_info)
+%
+%  A description of each parameter follows:
+%
+%    o montage_info: Specifies a pointer to an MontageInfo structure.
+%
+%
+*/
+MagickExport MontageInfo *DestroyMontageInfo(MontageInfo *montage_info)
+{
+  if (montage_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(montage_info != (MontageInfo *) NULL);
+  assert(montage_info->signature == MagickSignature);
+  if (montage_info->geometry != (char *) NULL)
+    montage_info->geometry=(char *)
+      RelinquishMagickMemory(montage_info->geometry);
+  if (montage_info->tile != (char *) NULL)
+    montage_info->tile=DestroyString(montage_info->tile);
+  if (montage_info->title != (char *) NULL)
+    montage_info->title=DestroyString(montage_info->title);
+  if (montage_info->frame != (char *) NULL)
+    montage_info->frame=DestroyString(montage_info->frame);
+  if (montage_info->texture != (char *) NULL)
+    montage_info->texture=(char *) RelinquishMagickMemory(
+      montage_info->texture);
+  if (montage_info->font != (char *) NULL)
+    montage_info->font=DestroyString(montage_info->font);
+  montage_info->signature=(~MagickSignature);
+  montage_info=(MontageInfo *) RelinquishMagickMemory(montage_info);
+  return(montage_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M o n t a g e I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMontageInfo() initializes montage_info to default values.
+%
+%  The format of the GetMontageInfo method is:
+%
+%      void GetMontageInfo(const ImageInfo *image_info,
+%        MontageInfo *montage_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: a structure of type ImageInfo.
+%
+%    o montage_info: Specifies a pointer to a MontageInfo structure.
+%
+*/
+MagickExport void GetMontageInfo(const ImageInfo *image_info,
+  MontageInfo *montage_info)
+{
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(montage_info != (MontageInfo *) NULL);
+  (void) ResetMagickMemory(montage_info,0,sizeof(*montage_info));
+  (void) CopyMagickString(montage_info->filename,image_info->filename,
+    MaxTextExtent);
+  montage_info->geometry=AcquireString(DefaultTileGeometry);
+  if (image_info->font != (char *) NULL)
+    montage_info->font=AcquireString(image_info->font);
+  montage_info->gravity=CenterGravity;
+  montage_info->pointsize=image_info->pointsize;
+  montage_info->fill.alpha=OpaqueAlpha;
+  montage_info->stroke.alpha=(Quantum) TransparentAlpha;
+  montage_info->background_color=image_info->background_color;
+  montage_info->border_color=image_info->border_color;
+  montage_info->matte_color=image_info->matte_color;
+  montage_info->debug=IsEventLogging();
+  montage_info->signature=MagickSignature;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M o n t a g e I m a g e L i s t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MontageImageList() is a layout manager that lets you tile one or more
+%  thumbnails across an image canvas.
+%
+%  The format of the MontageImageList method is:
+%
+%      Image *MontageImageList(const ImageInfo *image_info,
+%        const MontageInfo *montage_info,Image *images,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o montage_info: Specifies a pointer to a MontageInfo structure.
+%
+%    o images: Specifies a pointer to an array of Image structures.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void GetMontageGeometry(char *geometry,const size_t number_images,
+  ssize_t *x_offset,ssize_t *y_offset,size_t *tiles_per_column,
+  size_t *tiles_per_row)
+{
+  *tiles_per_column=0;
+  *tiles_per_row=0;
+  (void) GetGeometry(geometry,x_offset,y_offset,tiles_per_row,tiles_per_column);
+  if ((*tiles_per_column == 0) && (*tiles_per_row == 0))
+    *tiles_per_column=(size_t) sqrt((double) number_images);
+  if (*tiles_per_column == 0)
+    *tiles_per_column=(size_t)
+      ceil((double) number_images/(*tiles_per_row));
+  if (*tiles_per_row == 0)
+    *tiles_per_row=(size_t)
+      ceil((double) number_images/(*tiles_per_column));
+}
+
+static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int SceneCompare(const void *x,const void *y)
+{
+  Image
+    **image_1,
+    **image_2;
+
+  image_1=(Image **) x;
+  image_2=(Image **) y;
+  return((int) ((*image_1)->scene-(*image_2)->scene));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport Image *MontageImages(const Image *images,
+  const MontageInfo *montage_info,ExceptionInfo *exception)
+{
+  Image
+    *montage_image;
+
+  ImageInfo
+    *image_info;
+
+  image_info=AcquireImageInfo();
+  montage_image=MontageImageList(image_info,montage_info,images,exception);
+  image_info=DestroyImageInfo(image_info);
+  return(montage_image);
+}
+
+MagickExport Image *MontageImageList(const ImageInfo *image_info,
+  const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception)
+{
+#define MontageImageTag  "Montage/Image"
+#define TileImageTag  "Tile/Image"
+
+  char
+    tile_geometry[MaxTextExtent],
+    *title;
+
+  const char
+    *value;
+
+  DrawInfo
+    *draw_info;
+
+  FrameInfo
+    frame_info;
+
+  Image
+    *image,
+    **image_list,
+    **master_list,
+    *montage,
+    *texture,
+    *tile_image,
+    *thumbnail;
+
+  ImageInfo
+    *clone_info;
+
+  MagickBooleanType
+    concatenate,
+    proceed,
+    status;
+
+  MagickOffsetType
+    tiles;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  MagickStatusType
+    flags;
+
+  register ssize_t
+    i;
+
+  RectangleInfo
+    bounds,
+    geometry,
+    extract_info;
+
+
+  size_t
+    bevel_width,
+    border_width,
+    extent,
+    height,
+    images_per_page,
+    max_height,
+    number_images,
+    number_lines,
+    sans,
+    tiles_per_column,
+    tiles_per_page,
+    tiles_per_row,
+    title_offset,
+    total_tiles,
+    width;
+
+  ssize_t
+    tile,
+    x,
+    x_offset,
+    y,
+    y_offset;
+
+  TypeMetric
+    metrics;
+
+  /*
+    Create image tiles.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(montage_info != (MontageInfo *) NULL);
+  assert(montage_info->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  number_images=GetImageListLength(images);
+  master_list=ImageListToArray(images,exception);
+  image_list=master_list;
+  image=image_list[0];
+  if (master_list == (Image **) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  thumbnail=NewImageList();
+  for (i=0; i < (ssize_t) number_images; i++)
+  {
+    image=CloneImage(image_list[i],0,0,MagickTrue,exception);
+    if (image == (Image *) NULL)
+      break;
+    (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
+    progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
+      image->client_data);
+    flags=ParseRegionGeometry(image,montage_info->geometry,&geometry,exception);
+    thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
+    if (thumbnail == (Image *) NULL)
+      break;
+    image_list[i]=thumbnail;
+    (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
+    proceed=SetImageProgress(image,TileImageTag,(MagickOffsetType) i,
+      number_images);
+    if (proceed == MagickFalse)
+      break;
+    image=DestroyImage(image);
+  }
+  if (i < (ssize_t) number_images)
+    {
+      if (thumbnail == (Image *) NULL)
+        i--;
+      for (tile=0; (ssize_t) tile <= i; tile++)
+        if (image_list[tile] != (Image *) NULL)
+          image_list[tile]=DestroyImage(image_list[tile]);
+      master_list=(Image **) RelinquishMagickMemory(master_list);
+      return((Image *) NULL);
+    }
+  /*
+    Sort image list by increasing tile number.
+  */
+  for (i=0; i < (ssize_t) number_images; i++)
+    if (image_list[i]->scene == 0)
+      break;
+  if (i == (ssize_t) number_images)
+    qsort((void *) image_list,(size_t) number_images,sizeof(*image_list),
+      SceneCompare);
+  /*
+    Determine tiles per row and column.
+  */
+  tiles_per_column=(size_t) sqrt((double) number_images);
+  tiles_per_row=(size_t) ceil((double) number_images/tiles_per_column);
+  x_offset=0;
+  y_offset=0;
+  if (montage_info->tile != (char *) NULL)
+    GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
+      &tiles_per_column,&tiles_per_row);
+  /*
+    Determine tile sizes.
+  */
+  concatenate=MagickFalse;
+  SetGeometry(image_list[0],&extract_info);
+  extract_info.x=(ssize_t) montage_info->border_width;
+  extract_info.y=(ssize_t) montage_info->border_width;
+  if (montage_info->geometry != (char *) NULL)
+    {
+      /*
+        Initialize tile geometry.
+      */
+      flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y,
+        &extract_info.width,&extract_info.height);
+      if ((extract_info.x == 0) && (extract_info.y == 0))
+        concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ?
+          MagickTrue : MagickFalse;
+    }
+  border_width=montage_info->border_width;
+  bevel_width=0;
+  if (montage_info->frame != (char *) NULL)
+    {
+      char
+        absolute_geometry[MaxTextExtent];
+
+      (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info));
+      frame_info.width=extract_info.width;
+      frame_info.height=extract_info.height;
+      (void) FormatLocaleString(absolute_geometry,MaxTextExtent,"%s!",
+        montage_info->frame);
+      flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel,
+        &frame_info.inner_bevel,&frame_info.width,&frame_info.height);
+      if ((flags & HeightValue) == 0)
+        frame_info.height=frame_info.width;
+      if ((flags & XiValue) == 0)
+        frame_info.outer_bevel=(ssize_t) frame_info.width/2;
+      if ((flags & PsiValue) == 0)
+        frame_info.inner_bevel=frame_info.outer_bevel;
+      frame_info.x=(ssize_t) frame_info.width;
+      frame_info.y=(ssize_t) frame_info.height;
+      bevel_width=(size_t) MagickMax(frame_info.inner_bevel,
+        frame_info.outer_bevel);
+      border_width=(size_t) MagickMax((ssize_t) frame_info.width,
+        (ssize_t) frame_info.height);
+    }
+  for (i=0; i < (ssize_t) number_images; i++)
+  {
+    if (image_list[i]->columns > extract_info.width)
+      extract_info.width=image_list[i]->columns;
+    if (image_list[i]->rows > extract_info.height)
+      extract_info.height=image_list[i]->rows;
+  }
+  /*
+    Initialize draw attributes.
+  */
+  clone_info=CloneImageInfo(image_info);
+  clone_info->background_color=montage_info->background_color;
+  clone_info->border_color=montage_info->border_color;
+  draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL);
+  if (montage_info->font != (char *) NULL)
+    (void) CloneString(&draw_info->font,montage_info->font);
+  if (montage_info->pointsize != 0.0)
+    draw_info->pointsize=montage_info->pointsize;
+  draw_info->gravity=CenterGravity;
+  draw_info->stroke=montage_info->stroke;
+  draw_info->fill=montage_info->fill;
+  draw_info->text=AcquireString("");
+  (void) GetTypeMetrics(image_list[0],draw_info,&metrics);
+  texture=NewImageList();
+  if (montage_info->texture != (char *) NULL)
+    {
+      (void) CopyMagickString(clone_info->filename,montage_info->texture,
+        MaxTextExtent);
+      texture=ReadImage(clone_info,exception);
+    }
+  /*
+    Determine the number of lines in an next label.
+  */
+  title=InterpretImageProperties(clone_info,image_list[0],montage_info->title);
+  title_offset=0;
+  if (montage_info->title != (char *) NULL)
+    title_offset=(size_t) (2*(metrics.ascent-metrics.descent)*
+      MultilineCensus(title)+2*extract_info.y);
+  number_lines=0;
+  for (i=0; i < (ssize_t) number_images; i++)
+  {
+    value=GetImageProperty(image_list[i],"label");
+    if (value == (const char *) NULL)
+      continue;
+    if (MultilineCensus(value) > number_lines)
+      number_lines=MultilineCensus(value);
+  }
+  /*
+    Allocate next structure.
+  */
+  tile_image=AcquireImage(NULL);
+  montage=AcquireImage(clone_info);
+  montage->background_color=montage_info->background_color;
+  montage->scene=0;
+  images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1;
+  tiles=0;
+  total_tiles=(size_t) number_images;
+  for (i=0; i < (ssize_t) images_per_page; i++)
+  {
+    /*
+      Determine bounding box.
+    */
+    tiles_per_page=tiles_per_row*tiles_per_column;
+    x_offset=0;
+    y_offset=0;
+    if (montage_info->tile != (char *) NULL)
+      GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
+        &sans,&sans);
+    tiles_per_page=tiles_per_row*tiles_per_column;
+    y_offset+=(ssize_t) title_offset;
+    max_height=0;
+    bounds.width=0;
+    bounds.height=0;
+    width=0;
+    for (tile=0; tile < (ssize_t) tiles_per_page; tile++)
+    {
+      if (tile < (ssize_t) number_images)
+        {
+          width=concatenate != MagickFalse ? image_list[tile]->columns :
+            extract_info.width;
+          if (image_list[tile]->rows > max_height)
+            max_height=image_list[tile]->rows;
+        }
+      x_offset+=(ssize_t) (width+2*(extract_info.x+border_width));
+      if (x_offset > (ssize_t) bounds.width)
+        bounds.width=(size_t) x_offset;
+      if (((tile+1) == (ssize_t) tiles_per_page) ||
+          (((tile+1) % tiles_per_row) == 0))
+        {
+          x_offset=0;
+          if (montage_info->tile != (char *) NULL)
+            GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y,
+              &sans,&sans);
+          height=concatenate != MagickFalse ? max_height : extract_info.height;
+          y_offset+=(ssize_t) (height+(extract_info.y+(ssize_t) border_width)*2+
+            (metrics.ascent-metrics.descent+4)*number_lines+
+            (montage_info->shadow != MagickFalse ? 4 : 0));
+          if (y_offset > (ssize_t) bounds.height)
+            bounds.height=(size_t) y_offset;
+          max_height=0;
+        }
+    }
+    if (montage_info->shadow != MagickFalse)
+      bounds.width+=4;
+    /*
+      Initialize montage image.
+    */
+    (void) CopyMagickString(montage->filename,montage_info->filename,
+      MaxTextExtent);
+    montage->columns=bounds.width;
+    montage->rows=bounds.height;
+    (void) SetImageBackgroundColor(montage);
+    /*
+      Set montage geometry.
+    */
+    montage->montage=AcquireString((char *) NULL);
+    tile=0;
+    extent=1;
+    while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images))
+    {
+      extent+=strlen(image_list[tile]->filename)+1;
+      tile++;
+    }
+    montage->directory=(char *) AcquireQuantumMemory(extent,
+      sizeof(*montage->directory));
+    if ((montage->montage == (char *) NULL) ||
+        (montage->directory == (char *) NULL))
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    x_offset=0;
+    y_offset=0;
+    if (montage_info->tile != (char *) NULL)
+      GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
+        &sans,&sans);
+    y_offset+=(ssize_t) title_offset;
+    (void) FormatLocaleString(montage->montage,MaxTextExtent,
+      "%.20gx%.20g%+.20g%+.20g",(double) (extract_info.width+
+      (extract_info.x+border_width)*2),(double) (extract_info.height+
+      (extract_info.y+border_width)*2+(double) ((metrics.ascent-
+      metrics.descent+4)*number_lines+(montage_info->shadow != MagickFalse ? 4 :
+      0))),(double) x_offset,(double) y_offset);
+    *montage->directory='\0';
+    tile=0;
+    while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images))
+    {
+      (void) ConcatenateMagickString(montage->directory,
+        image_list[tile]->filename,extent);
+      (void) ConcatenateMagickString(montage->directory,"\n",extent);
+      tile++;
+    }
+    progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor)
+      NULL,montage->client_data);
+    if (texture != (Image *) NULL)
+      (void) TextureImage(montage,texture);
+    if (montage_info->title != (char *) NULL)
+      {
+        char
+          geometry[MaxTextExtent];
+
+        DrawInfo
+          *clone_info;
+
+        TypeMetric
+          metrics;
+
+        /*
+          Annotate composite image with title.
+        */
+        clone_info=CloneDrawInfo(image_info,draw_info);
+        clone_info->gravity=CenterGravity;
+        clone_info->pointsize*=2.0;
+        (void) GetTypeMetrics(image_list[0],clone_info,&metrics);
+        (void) FormatLocaleString(geometry,MaxTextExtent,
+          "%.20gx%.20g%+.20g%+.20g",(double) montage->columns,(double)
+          (metrics.ascent-metrics.descent),0.0,(double) extract_info.y+4);
+        (void) CloneString(&clone_info->geometry,geometry);
+        (void) CloneString(&clone_info->text,title);
+        (void) AnnotateImage(montage,clone_info);
+        clone_info=DestroyDrawInfo(clone_info);
+      }
+    (void) SetImageProgressMonitor(montage,progress_monitor,
+      montage->client_data);
+    /*
+      Copy tile to the composite.
+    */
+    x_offset=0;
+    y_offset=0;
+    if (montage_info->tile != (char *) NULL)
+      GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
+        &sans,&sans);
+    x_offset+=extract_info.x;
+    y_offset+=(ssize_t) title_offset+extract_info.y;
+    max_height=0;
+    status=MagickTrue;
+    for (tile=0; tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images); tile++)
+    {
+      /*
+        Copy this tile to the composite.
+      */
+      image=CloneImage(image_list[tile],0,0,MagickTrue,exception);
+      progress_monitor=SetImageProgressMonitor(image,
+        (MagickProgressMonitor) NULL,image->client_data);
+      width=concatenate != MagickFalse ? image->columns : extract_info.width;
+      if (image->rows > max_height)
+        max_height=image->rows;
+      height=concatenate != MagickFalse ? max_height : extract_info.height;
+      if (border_width != 0)
+        {
+          Image
+            *border_image;
+
+          RectangleInfo
+            border_info;
+
+          /*
+            Put a border around the image.
+          */
+          border_info.width=border_width;
+          border_info.height=border_width;
+          if (montage_info->frame != (char *) NULL)
+            {
+              border_info.width=(width-image->columns+1)/2;
+              border_info.height=(height-image->rows+1)/2;
+            }
+          border_image=BorderImage(image,&border_info,exception);
+          if (border_image != (Image *) NULL)
+            {
+              image=DestroyImage(image);
+              image=border_image;
+            }
+          if ((montage_info->frame != (char *) NULL) &&
+              (image->compose == DstOutCompositeOp))
+            (void) NegateImageChannel(image,OpacityChannel,MagickFalse);
+        }
+      /*
+        Gravitate as specified by the tile gravity.
+      */
+      tile_image->columns=width;
+      tile_image->rows=height;
+      tile_image->gravity=montage_info->gravity;
+      if (image->gravity != UndefinedGravity)
+        tile_image->gravity=image->gravity;
+      (void) FormatLocaleString(tile_geometry,MaxTextExtent,"%.20gx%.20g+0+0",
+        (double) image->columns,(double) image->rows);
+      flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception);
+      x=(ssize_t) (geometry.x+border_width);
+      y=(ssize_t) (geometry.y+border_width);
+      if ((montage_info->frame != (char *) NULL) && (bevel_width != 0))
+        {
+          FrameInfo
+            extract_info;
+
+          Image
+            *frame_image;
+
+          /*
+            Put an ornamental border around this tile.
+          */
+          extract_info=frame_info;
+          extract_info.width=width+2*frame_info.width;
+          extract_info.height=height+2*frame_info.height;
+          value=GetImageProperty(image,"label");
+          if (value != (const char *) NULL)
+            extract_info.height+=(size_t) ((metrics.ascent-
+              metrics.descent+4)*MultilineCensus(value));
+          frame_image=FrameImage(image,&extract_info,exception);
+          if (frame_image != (Image *) NULL)
+            {
+              image=DestroyImage(image);
+              image=frame_image;
+            }
+          x=0;
+          y=0;
+        }
+      if (LocaleCompare(image->magick,"NULL") != 0)
+        {
+          /*
+            Composite background with tile.
+          */
+          if (montage_info->shadow != MagickFalse)
+            {
+              Image
+                *shadow_image;
+
+              /*
+                Shadow image.
+              */
+              (void) QueryColorDatabase("#00000000",&image->background_color,
+                exception);
+              shadow_image=ShadowImage(image,80.0,2.0,5,5,exception);
+              if (shadow_image != (Image *) NULL)
+                {
+                  InheritException(&shadow_image->exception,exception);
+                  (void) CompositeImage(shadow_image,OverCompositeOp,image,0,0);
+                  image=DestroyImage(image);
+                  image=shadow_image;
+                }
+          }
+          (void) CompositeImage(montage,image->compose,image,x_offset+x,
+            y_offset+y);
+          value=GetImageProperty(image,"label");
+          if (value != (const char *) NULL)
+            {
+              char
+                geometry[MaxTextExtent];
+
+              /*
+                Annotate composite tile with label.
+              */
+              (void) FormatLocaleString(geometry,MaxTextExtent,
+                "%.20gx%.20g%+.20g%+.20g",(double) ((montage_info->frame ?
+                image->columns : width)-2*border_width),(double)
+                (metrics.ascent-metrics.descent+4)*MultilineCensus(value),
+                (double) (x_offset+border_width),(double)
+                ((montage_info->frame ? y_offset+height+border_width+4 :
+                y_offset+extract_info.height+border_width+
+                (montage_info->shadow != MagickFalse ? 4 : 0))+bevel_width));
+              (void) CloneString(&draw_info->geometry,geometry);
+              (void) CloneString(&draw_info->text,value);
+              (void) AnnotateImage(montage,draw_info);
+            }
+        }
+      x_offset+=(ssize_t) (width+2*(extract_info.x+border_width));
+      if (((tile+1) == (ssize_t) tiles_per_page) ||
+          (((tile+1) % tiles_per_row) == 0))
+        {
+          x_offset=extract_info.x;
+          y_offset+=(ssize_t) (height+(extract_info.y+border_width)*2+
+            (metrics.ascent-metrics.descent+4)*number_lines+
+            (montage_info->shadow != MagickFalse ? 4 : 0));
+          max_height=0;
+        }
+      if (images->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+          proceed=SetImageProgress(image,MontageImageTag,tiles,total_tiles);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+      image_list[tile]=DestroyImage(image_list[tile]);
+      image=DestroyImage(image);
+      tiles++;
+    }
+    (void) status;
+    if ((i+1) < (ssize_t) images_per_page)
+      {
+        /*
+          Allocate next image structure.
+        */
+        AcquireNextImage(clone_info,montage);
+        if (GetNextImageInList(montage) == (Image *) NULL)
+          {
+            montage=DestroyImageList(montage);
+            return((Image *) NULL);
+          }
+        montage=GetNextImageInList(montage);
+        montage->background_color=montage_info->background_color;
+        image_list+=tiles_per_page;
+        number_images-=tiles_per_page;
+      }
+  }
+  tile_image=DestroyImage(tile_image);
+  if (texture != (Image *) NULL)
+    texture=DestroyImage(texture);
+  master_list=(Image **) RelinquishMagickMemory(master_list);
+  draw_info=DestroyDrawInfo(draw_info);
+  clone_info=DestroyImageInfo(clone_info);
+  return(GetFirstImageInList(montage));
+}
diff --git a/MagickCore/montage.h b/MagickCore/montage.h
new file mode 100644
index 0000000..34b4a0a
--- /dev/null
+++ b/MagickCore/montage.h
@@ -0,0 +1,88 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore montage methods.
+*/
+#ifndef _MAGICKCORE_MONTAGE_H
+#define _MAGICKCORE_MONTAGE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedMode,
+  FrameMode,
+  UnframeMode,
+  ConcatenateMode
+} MontageMode;
+
+typedef struct _MontageInfo
+{
+  char
+    *geometry,
+    *tile,
+    *title,
+    *frame,
+    *texture,
+    *font;
+
+  double
+    pointsize;
+
+  size_t
+    border_width;
+
+  MagickBooleanType
+    shadow;
+
+  PixelPacket
+    fill,
+    stroke,
+    background_color,
+    border_color,
+    matte_color;
+
+  GravityType
+    gravity;
+
+  char
+    filename[MaxTextExtent];
+
+  MagickBooleanType
+    debug;
+
+  size_t
+    signature;
+} MontageInfo;
+
+extern MagickExport Image
+  *MontageImages(const Image *,const MontageInfo *,ExceptionInfo *),
+  *MontageImageList(const ImageInfo *,const MontageInfo *,const Image *,
+    ExceptionInfo *);
+
+extern MagickExport MontageInfo
+  *CloneMontageInfo(const ImageInfo *,const MontageInfo *),
+  *DestroyMontageInfo(MontageInfo *);
+
+extern MagickExport void
+  GetMontageInfo(const ImageInfo *,MontageInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/morphology-private.h b/MagickCore/morphology-private.h
new file mode 100644
index 0000000..78bc9e7
--- /dev/null
+++ b/MagickCore/morphology-private.h
@@ -0,0 +1,41 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  The ImageMagick morphology private methods.
+*/
+#ifndef _MAGICK_MORPHOLOGY_PRIVATE_H
+#define _MAGICK_MORPHOLOGY_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#include <MagickCore/morphology.h>
+
+extern MagickExport Image
+  *MorphologyApply(const Image *,const ChannelType,const MorphologyMethod,
+    const ssize_t,const KernelInfo *,const CompositeOperator,const double,
+    ExceptionInfo *);
+
+extern MagickExport void
+  ScaleKernelInfo(KernelInfo *,const double,const GeometryFlags),
+  UnityAddKernelInfo(KernelInfo *,const double),
+  ZeroKernelNans(KernelInfo *);
+
+#endif
diff --git a/MagickCore/morphology.c b/MagickCore/morphology.c
new file mode 100644
index 0000000..5f725f3
--- /dev/null
+++ b/MagickCore/morphology.c
@@ -0,0 +1,4845 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%    M   M    OOO    RRRR   PPPP   H   H   OOO   L       OOO    GGGG  Y   Y   %
+%    MM MM   O   O   R   R  P   P  H   H  O   O  L      O   O  G       Y Y    %
+%    M M M   O   O   RRRR   PPPP   HHHHH  O   O  L      O   O  G GGG    Y     %
+%    M   M   O   O   R R    P      H   H  O   O  L      O   O  G   G    Y     %
+%    M   M    OOO    R  R   P      H   H   OOO   LLLLL   OOO    GGG     Y     %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Morphology Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                              Anthony Thyssen                                %
+%                               January 2010                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Morpology is the the application of various kernels, of any size and even
+% shape, to a image in various ways (typically binary, but not always).
+%
+% Convolution (weighted sum or average) is just one specific type of
+% morphology. Just one that is very common for image bluring and sharpening
+% effects.  Not only 2D Gaussian blurring, but also 2-pass 1D Blurring.
+%
+% This module provides not only a general morphology function, and the ability
+% to apply more advanced or iterative morphologies, but also functions for the
+% generation of many different types of kernel arrays from user supplied
+% arguments. Prehaps even the generation of a kernel from a small image.
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/morphology.h"
+#include "MagickCore/morphology-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/prepress.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+
+
+/*
+** The following test is for special floating point numbers of value NaN (not
+** a number), that may be used within a Kernel Definition.  NaN's are defined
+** as part of the IEEE standard for floating point number representation.
+**
+** These are used as a Kernel value to mean that this kernel position is not
+** part of the kernel neighbourhood for convolution or morphology processing,
+** and thus should be ignored.  This allows the use of 'shaped' kernels.
+**
+** The special properity that two NaN's are never equal, even if they are from
+** the same variable allow you to test if a value is special NaN value.
+**
+** This macro  IsNaN() is thus is only true if the value given is NaN.
+*/
+#define IsNan(a)   ((a)!=(a))
+
+/*
+  Other global definitions used by module.
+*/
+static inline double MagickMin(const double x,const double y)
+{
+  return( x < y ? x : y);
+}
+static inline double MagickMax(const double x,const double y)
+{
+  return( x > y ? x : y);
+}
+#define Minimize(assign,value) assign=MagickMin(assign,value)
+#define Maximize(assign,value) assign=MagickMax(assign,value)
+
+/* Currently these are only internal to this module */
+static void
+  CalcKernelMetaData(KernelInfo *),
+  ExpandMirrorKernelInfo(KernelInfo *),
+  ExpandRotateKernelInfo(KernelInfo *, const double),
+  RotateKernelInfo(KernelInfo *, double);
+
+
+/* Quick function to find last kernel in a kernel list */
+static inline KernelInfo *LastKernelInfo(KernelInfo *kernel)
+{
+  while (kernel->next != (KernelInfo *) NULL)
+    kernel = kernel->next;
+  return(kernel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A c q u i r e K e r n e l I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireKernelInfo() takes the given string (generally supplied by the
+%  user) and converts it into a Morphology/Convolution Kernel.  This allows
+%  users to specify a kernel from a number of pre-defined kernels, or to fully
+%  specify their own kernel for a specific Convolution or Morphology
+%  Operation.
+%
+%  The kernel so generated can be any rectangular array of floating point
+%  values (doubles) with the 'control point' or 'pixel being affected'
+%  anywhere within that array of values.
+%
+%  Previously IM was restricted to a square of odd size using the exact
+%  center as origin, this is no longer the case, and any rectangular kernel
+%  with any value being declared the origin. This in turn allows the use of
+%  highly asymmetrical kernels.
+%
+%  The floating point values in the kernel can also include a special value
+%  known as 'nan' or 'not a number' to indicate that this value is not part
+%  of the kernel array. This allows you to shaped the kernel within its
+%  rectangular area. That is 'nan' values provide a 'mask' for the kernel
+%  shape.  However at least one non-nan value must be provided for correct
+%  working of a kernel.
+%
+%  The returned kernel should be freed using the DestroyKernelInfo() when you
+%  are finished with it.  Do not free this memory yourself.
+%
+%  Input kernel defintion strings can consist of any of three types.
+%
+%    "name:args[[@><]"
+%         Select from one of the built in kernels, using the name and
+%         geometry arguments supplied.  See AcquireKernelBuiltIn()
+%
+%    "WxH[+X+Y][@><]:num, num, num ..."
+%         a kernel of size W by H, with W*H floating point numbers following.
+%         the 'center' can be optionally be defined at +X+Y (such that +0+0
+%         is top left corner). If not defined the pixel in the center, for
+%         odd sizes, or to the immediate top or left of center for even sizes
+%         is automatically selected.
+%
+%    "num, num, num, num, ..."
+%         list of floating point numbers defining an 'old style' odd sized
+%         square kernel.  At least 9 values should be provided for a 3x3
+%         square kernel, 25 for a 5x5 square kernel, 49 for 7x7, etc.
+%         Values can be space or comma separated.  This is not recommended.
+%
+%  You can define a 'list of kernels' which can be used by some morphology
+%  operators A list is defined as a semi-colon separated list kernels.
+%
+%     " kernel ; kernel ; kernel ; "
+%
+%  Any extra ';' characters, at start, end or between kernel defintions are
+%  simply ignored.
+%
+%  The special flags will expand a single kernel, into a list of rotated
+%  kernels. A '@' flag will expand a 3x3 kernel into a list of 45-degree
+%  cyclic rotations, while a '>' will generate a list of 90-degree rotations.
+%  The '<' also exands using 90-degree rotates, but giving a 180-degree
+%  reflected kernel before the +/- 90-degree rotations, which can be important
+%  for Thinning operations.
+%
+%  Note that 'name' kernels will start with an alphabetic character while the
+%  new kernel specification has a ':' character in its specification string.
+%  If neither is the case, it is assumed an old style of a simple list of
+%  numbers generating a odd-sized square kernel has been given.
+%
+%  The format of the AcquireKernal method is:
+%
+%      KernelInfo *AcquireKernelInfo(const char *kernel_string)
+%
+%  A description of each parameter follows:
+%
+%    o kernel_string: the Morphology/Convolution kernel wanted.
+%
+*/
+
+/* This was separated so that it could be used as a separate
+** array input handling function, such as for -color-matrix
+*/
+static KernelInfo *ParseKernelArray(const char *kernel_string)
+{
+  KernelInfo
+    *kernel;
+
+  char
+    token[MaxTextExtent];
+
+  const char
+    *p,
+    *end;
+
+  register ssize_t
+    i;
+
+  double
+    nan = sqrt((double)-1.0);  /* Special Value : Not A Number */
+
+  MagickStatusType
+    flags;
+
+  GeometryInfo
+    args;
+
+  kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
+  if (kernel == (KernelInfo *)NULL)
+    return(kernel);
+  (void) ResetMagickMemory(kernel,0,sizeof(*kernel));
+  kernel->minimum = kernel->maximum = kernel->angle = 0.0;
+  kernel->negative_range = kernel->positive_range = 0.0;
+  kernel->type = UserDefinedKernel;
+  kernel->next = (KernelInfo *) NULL;
+  kernel->signature = MagickSignature;
+
+  /* find end of this specific kernel definition string */
+  end = strchr(kernel_string, ';');
+  if ( end == (char *) NULL )
+    end = strchr(kernel_string, '\0');
+
+  /* clear flags - for Expanding kernel lists thorugh rotations */
+   flags = NoValue;
+
+  /* Has a ':' in argument - New user kernel specification */
+  p = strchr(kernel_string, ':');
+  if ( p != (char *) NULL && p < end)
+    {
+      /* ParseGeometry() needs the geometry separated! -- Arrgghh */
+      memcpy(token, kernel_string, (size_t) (p-kernel_string));
+      token[p-kernel_string] = '\0';
+      SetGeometryInfo(&args);
+      flags = ParseGeometry(token, &args);
+
+      /* Size handling and checks of geometry settings */
+      if ( (flags & WidthValue) == 0 ) /* if no width then */
+        args.rho = args.sigma;         /* then  width = height */
+      if ( args.rho < 1.0 )            /* if width too small */
+         args.rho = 1.0;               /* then  width = 1 */
+      if ( args.sigma < 1.0 )          /* if height too small */
+        args.sigma = args.rho;         /* then  height = width */
+      kernel->width = (size_t)args.rho;
+      kernel->height = (size_t)args.sigma;
+
+      /* Offset Handling and Checks */
+      if ( args.xi  < 0.0 || args.psi < 0.0 )
+        return(DestroyKernelInfo(kernel));
+      kernel->x = ((flags & XValue)!=0) ? (ssize_t)args.xi
+                                               : (ssize_t) (kernel->width-1)/2;
+      kernel->y = ((flags & YValue)!=0) ? (ssize_t)args.psi
+                                               : (ssize_t) (kernel->height-1)/2;
+      if ( kernel->x >= (ssize_t) kernel->width ||
+           kernel->y >= (ssize_t) kernel->height )
+        return(DestroyKernelInfo(kernel));
+
+      p++; /* advance beyond the ':' */
+    }
+  else
+    { /* ELSE - Old old specification, forming odd-square kernel */
+      /* count up number of values given */
+      p=(const char *) kernel_string;
+      while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\''))
+        p++;  /* ignore "'" chars for convolve filter usage - Cristy */
+      for (i=0; p < end; i++)
+      {
+        GetMagickToken(p,&p,token);
+        if (*token == ',')
+          GetMagickToken(p,&p,token);
+      }
+      /* set the size of the kernel - old sized square */
+      kernel->width = kernel->height= (size_t) sqrt((double) i+1.0);
+      kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+      p=(const char *) kernel_string;
+      while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == '\''))
+        p++;  /* ignore "'" chars for convolve filter usage - Cristy */
+    }
+
+  /* Read in the kernel values from rest of input string argument */
+  kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                        kernel->height*sizeof(double));
+  if (kernel->values == (double *) NULL)
+    return(DestroyKernelInfo(kernel));
+
+  kernel->minimum = +MagickHuge;
+  kernel->maximum = -MagickHuge;
+  kernel->negative_range = kernel->positive_range = 0.0;
+
+  for (i=0; (i < (ssize_t) (kernel->width*kernel->height)) && (p < end); i++)
+  {
+    GetMagickToken(p,&p,token);
+    if (*token == ',')
+      GetMagickToken(p,&p,token);
+    if (    LocaleCompare("nan",token) == 0
+        || LocaleCompare("-",token) == 0 ) {
+      kernel->values[i] = nan; /* do not include this value in kernel */
+    }
+    else {
+      kernel->values[i] = InterpretLocaleValue(token,(char **) NULL);
+      ( kernel->values[i] < 0)
+          ?  ( kernel->negative_range += kernel->values[i] )
+          :  ( kernel->positive_range += kernel->values[i] );
+      Minimize(kernel->minimum, kernel->values[i]);
+      Maximize(kernel->maximum, kernel->values[i]);
+    }
+  }
+
+  /* sanity check -- no more values in kernel definition */
+  GetMagickToken(p,&p,token);
+  if ( *token != '\0' && *token != ';' && *token != '\'' )
+    return(DestroyKernelInfo(kernel));
+
+#if 0
+  /* this was the old method of handling a incomplete kernel */
+  if ( i < (ssize_t) (kernel->width*kernel->height) ) {
+    Minimize(kernel->minimum, kernel->values[i]);
+    Maximize(kernel->maximum, kernel->values[i]);
+    for ( ; i < (ssize_t) (kernel->width*kernel->height); i++)
+      kernel->values[i]=0.0;
+  }
+#else
+  /* Number of values for kernel was not enough - Report Error */
+  if ( i < (ssize_t) (kernel->width*kernel->height) )
+    return(DestroyKernelInfo(kernel));
+#endif
+
+  /* check that we recieved at least one real (non-nan) value! */
+  if ( kernel->minimum == MagickHuge )
+    return(DestroyKernelInfo(kernel));
+
+  if ( (flags & AreaValue) != 0 )         /* '@' symbol in kernel size */
+    ExpandRotateKernelInfo(kernel, 45.0); /* cyclic rotate 3x3 kernels */
+  else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */
+    ExpandRotateKernelInfo(kernel, 90.0); /* 90 degree rotate of kernel */
+  else if ( (flags & LessValue) != 0 )    /* '<' symbol in kernel args */
+    ExpandMirrorKernelInfo(kernel);       /* 90 degree mirror rotate */
+
+  return(kernel);
+}
+
+static KernelInfo *ParseKernelName(const char *kernel_string)
+{
+  char
+    token[MaxTextExtent];
+
+  const char
+    *p,
+    *end;
+
+  GeometryInfo
+    args;
+
+  KernelInfo
+    *kernel;
+
+  MagickStatusType
+    flags;
+
+  ssize_t
+    type;
+
+  /* Parse special 'named' kernel */
+  GetMagickToken(kernel_string,&p,token);
+  type=ParseCommandOption(MagickKernelOptions,MagickFalse,token);
+  if ( type < 0 || type == UserDefinedKernel )
+    return((KernelInfo *)NULL);  /* not a valid named kernel */
+
+  while (((isspace((int) ((unsigned char) *p)) != 0) ||
+          (*p == ',') || (*p == ':' )) && (*p != '\0') && (*p != ';'))
+    p++;
+
+  end = strchr(p, ';'); /* end of this kernel defintion */
+  if ( end == (char *) NULL )
+    end = strchr(p, '\0');
+
+  /* ParseGeometry() needs the geometry separated! -- Arrgghh */
+  memcpy(token, p, (size_t) (end-p));
+  token[end-p] = '\0';
+  SetGeometryInfo(&args);
+  flags = ParseGeometry(token, &args);
+
+#if 0
+  /* For Debugging Geometry Input */
+  (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
+    flags, args.rho, args.sigma, args.xi, args.psi );
+#endif
+
+  /* special handling of missing values in input string */
+  switch( type ) {
+    /* Shape Kernel Defaults */
+    case UnityKernel:
+      if ( (flags & WidthValue) == 0 )
+        args.rho = 1.0;    /* Default scale = 1.0, zero is valid */
+      break;
+    case SquareKernel:
+    case DiamondKernel:
+    case OctagonKernel:
+    case DiskKernel:
+    case PlusKernel:
+    case CrossKernel:
+      if ( (flags & HeightValue) == 0 )
+        args.sigma = 1.0;    /* Default scale = 1.0, zero is valid */
+      break;
+    case RingKernel:
+      if ( (flags & XValue) == 0 )
+        args.xi = 1.0;       /* Default scale = 1.0, zero is valid */
+      break;
+    case RectangleKernel:    /* Rectangle - set size defaults */
+      if ( (flags & WidthValue) == 0 ) /* if no width then */
+        args.rho = args.sigma;         /* then  width = height */
+      if ( args.rho < 1.0 )            /* if width too small */
+          args.rho = 3;                /* then  width = 3 */
+      if ( args.sigma < 1.0 )          /* if height too small */
+        args.sigma = args.rho;         /* then  height = width */
+      if ( (flags & XValue) == 0 )     /* center offset if not defined */
+        args.xi = (double)(((ssize_t)args.rho-1)/2);
+      if ( (flags & YValue) == 0 )
+        args.psi = (double)(((ssize_t)args.sigma-1)/2);
+      break;
+    /* Distance Kernel Defaults */
+    case ChebyshevKernel:
+    case ManhattanKernel:
+    case OctagonalKernel:
+    case EuclideanKernel:
+      if ( (flags & HeightValue) == 0 )           /* no distance scale */
+        args.sigma = 100.0;                       /* default distance scaling */
+      else if ( (flags & AspectValue ) != 0 )     /* '!' flag */
+        args.sigma = QuantumRange/(args.sigma+1); /* maximum pixel distance */
+      else if ( (flags & PercentValue ) != 0 )    /* '%' flag */
+        args.sigma *= QuantumRange/100.0;         /* percentage of color range */
+      break;
+    default:
+      break;
+  }
+
+  kernel = AcquireKernelBuiltIn((KernelInfoType)type, &args);
+  if ( kernel == (KernelInfo *) NULL )
+    return(kernel);
+
+  /* global expand to rotated kernel list - only for single kernels */
+  if ( kernel->next == (KernelInfo *) NULL ) {
+    if ( (flags & AreaValue) != 0 )         /* '@' symbol in kernel args */
+      ExpandRotateKernelInfo(kernel, 45.0);
+    else if ( (flags & GreaterValue) != 0 ) /* '>' symbol in kernel args */
+      ExpandRotateKernelInfo(kernel, 90.0);
+    else if ( (flags & LessValue) != 0 )    /* '<' symbol in kernel args */
+      ExpandMirrorKernelInfo(kernel);
+  }
+
+  return(kernel);
+}
+
+MagickExport KernelInfo *AcquireKernelInfo(const char *kernel_string)
+{
+
+  KernelInfo
+    *kernel,
+    *new_kernel;
+
+  char
+    token[MaxTextExtent];
+
+  const char
+    *p;
+
+  size_t
+    kernel_number;
+
+  p = kernel_string;
+  kernel = NULL;
+  kernel_number = 0;
+
+  while ( GetMagickToken(p,NULL,token),  *token != '\0' ) {
+
+    /* ignore extra or multiple ';' kernel separators */
+    if ( *token != ';' ) {
+
+      /* tokens starting with alpha is a Named kernel */
+      if (isalpha((int) *token) != 0)
+        new_kernel = ParseKernelName(p);
+      else /* otherwise a user defined kernel array */
+        new_kernel = ParseKernelArray(p);
+
+      /* Error handling -- this is not proper error handling! */
+      if ( new_kernel == (KernelInfo *) NULL ) {
+        (void) FormatLocaleFile(stderr, "Failed to parse kernel number #%.20g\n",
+          (double) kernel_number);
+        if ( kernel != (KernelInfo *) NULL )
+          kernel=DestroyKernelInfo(kernel);
+        return((KernelInfo *) NULL);
+      }
+
+      /* initialise or append the kernel list */
+      if ( kernel == (KernelInfo *) NULL )
+        kernel = new_kernel;
+      else
+        LastKernelInfo(kernel)->next = new_kernel;
+    }
+
+    /* look for the next kernel in list */
+    p = strchr(p, ';');
+    if ( p == (char *) NULL )
+      break;
+    p++;
+
+  }
+  return(kernel);
+}
+
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A c q u i r e K e r n e l B u i l t I n                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireKernelBuiltIn() returned one of the 'named' built-in types of
+%  kernels used for special purposes such as gaussian blurring, skeleton
+%  pruning, and edge distance determination.
+%
+%  They take a KernelType, and a set of geometry style arguments, which were
+%  typically decoded from a user supplied string, or from a more complex
+%  Morphology Method that was requested.
+%
+%  The format of the AcquireKernalBuiltIn method is:
+%
+%      KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
+%           const GeometryInfo args)
+%
+%  A description of each parameter follows:
+%
+%    o type: the pre-defined type of kernel wanted
+%
+%    o args: arguments defining or modifying the kernel
+%
+%  Convolution Kernels
+%
+%    Unity
+%       The a No-Op or Scaling single element kernel.
+%
+%    Gaussian:{radius},{sigma}
+%       Generate a two-dimensional gaussian kernel, as used by -gaussian.
+%       The sigma for the curve is required.  The resulting kernel is
+%       normalized,
+%
+%       If 'sigma' is zero, you get a single pixel on a field of zeros.
+%
+%       NOTE: that the 'radius' is optional, but if provided can limit (clip)
+%       the final size of the resulting kernel to a square 2*radius+1 in size.
+%       The radius should be at least 2 times that of the sigma value, or
+%       sever clipping and aliasing may result.  If not given or set to 0 the
+%       radius will be determined so as to produce the best minimal error
+%       result, which is usally much larger than is normally needed.
+%
+%    LoG:{radius},{sigma}
+%        "Laplacian of a Gaussian" or "Mexician Hat" Kernel.
+%        The supposed ideal edge detection, zero-summing kernel.
+%
+%        An alturnative to this kernel is to use a "DoG" with a sigma ratio of
+%        approx 1.6 (according to wikipedia).
+%
+%    DoG:{radius},{sigma1},{sigma2}
+%        "Difference of Gaussians" Kernel.
+%        As "Gaussian" but with a gaussian produced by 'sigma2' subtracted
+%        from the gaussian produced by 'sigma1'. Typically sigma2 > sigma1.
+%        The result is a zero-summing kernel.
+%
+%    Blur:{radius},{sigma}[,{angle}]
+%       Generates a 1 dimensional or linear gaussian blur, at the angle given
+%       (current restricted to orthogonal angles).  If a 'radius' is given the
+%       kernel is clipped to a width of 2*radius+1.  Kernel can be rotated
+%       by a 90 degree angle.
+%
+%       If 'sigma' is zero, you get a single pixel on a field of zeros.
+%
+%       Note that two convolutions with two "Blur" kernels perpendicular to
+%       each other, is equivalent to a far larger "Gaussian" kernel with the
+%       same sigma value, However it is much faster to apply. This is how the
+%       "-blur" operator actually works.
+%
+%    Comet:{width},{sigma},{angle}
+%       Blur in one direction only, much like how a bright object leaves
+%       a comet like trail.  The Kernel is actually half a gaussian curve,
+%       Adding two such blurs in opposite directions produces a Blur Kernel.
+%       Angle can be rotated in multiples of 90 degrees.
+%
+%       Note that the first argument is the width of the kernel and not the
+%       radius of the kernel.
+%
+%    # Still to be implemented...
+%    #
+%    # Filter2D
+%    # Filter1D
+%    #    Set kernel values using a resize filter, and given scale (sigma)
+%    #    Cylindrical or Linear.   Is this possible with an image?
+%    #
+%
+%  Named Constant Convolution Kernels
+%
+%  All these are unscaled, zero-summing kernels by default. As such for
+%  non-HDRI version of ImageMagick some form of normalization, user scaling,
+%  and biasing the results is recommended, to prevent the resulting image
+%  being 'clipped'.
+%
+%  The 3x3 kernels (most of these) can be circularly rotated in multiples of
+%  45 degrees to generate the 8 angled varients of each of the kernels.
+%
+%    Laplacian:{type}
+%      Discrete Lapacian Kernels, (without normalization)
+%        Type 0 :  3x3 with center:8 surounded by -1  (8 neighbourhood)
+%        Type 1 :  3x3 with center:4 edge:-1 corner:0 (4 neighbourhood)
+%        Type 2 :  3x3 with center:4 edge:1 corner:-2
+%        Type 3 :  3x3 with center:4 edge:-2 corner:1
+%        Type 5 :  5x5 laplacian
+%        Type 7 :  7x7 laplacian
+%        Type 15 : 5x5 LoG (sigma approx 1.4)
+%        Type 19 : 9x9 LoG (sigma approx 1.4)
+%
+%    Sobel:{angle}
+%      Sobel 'Edge' convolution kernel (3x3)
+%          | -1, 0, 1 |
+%          | -2, 0,-2 |
+%          | -1, 0, 1 |
+%
+%    Roberts:{angle}
+%      Roberts convolution kernel (3x3)
+%          |  0, 0, 0 |
+%          | -1, 1, 0 |
+%          |  0, 0, 0 |
+%
+%    Prewitt:{angle}
+%      Prewitt Edge convolution kernel (3x3)
+%          | -1, 0, 1 |
+%          | -1, 0, 1 |
+%          | -1, 0, 1 |
+%
+%    Compass:{angle}
+%      Prewitt's "Compass" convolution kernel (3x3)
+%          | -1, 1, 1 |
+%          | -1,-2, 1 |
+%          | -1, 1, 1 |
+%
+%    Kirsch:{angle}
+%      Kirsch's "Compass" convolution kernel (3x3)
+%          | -3,-3, 5 |
+%          | -3, 0, 5 |
+%          | -3,-3, 5 |
+%
+%    FreiChen:{angle}
+%      Frei-Chen Edge Detector is based on a kernel that is similar to
+%      the Sobel Kernel, but is designed to be isotropic. That is it takes
+%      into account the distance of the diagonal in the kernel.
+%
+%          |   1,     0,   -1     |
+%          | sqrt(2), 0, -sqrt(2) |
+%          |   1,     0,   -1     |
+%
+%    FreiChen:{type},{angle}
+%
+%      Frei-Chen Pre-weighted kernels...
+%
+%        Type 0:  default un-nomalized version shown above.
+%
+%        Type 1: Orthogonal Kernel (same as type 11 below)
+%          |   1,     0,   -1     |
+%          | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2)
+%          |   1,     0,   -1     |
+%
+%        Type 2: Diagonal form of Kernel...
+%          |   1,     sqrt(2),    0     |
+%          | sqrt(2),   0,     -sqrt(2) | / 2*sqrt(2)
+%          |   0,    -sqrt(2)    -1     |
+%
+%      However this kernel is als at the heart of the FreiChen Edge Detection
+%      Process which uses a set of 9 specially weighted kernel.  These 9
+%      kernels not be normalized, but directly applied to the image. The
+%      results is then added together, to produce the intensity of an edge in
+%      a specific direction.  The square root of the pixel value can then be
+%      taken as the cosine of the edge, and at least 2 such runs at 90 degrees
+%      from each other, both the direction and the strength of the edge can be
+%      determined.
+%
+%        Type 10: All 9 of the following pre-weighted kernels...
+%
+%        Type 11: |   1,     0,   -1     |
+%                 | sqrt(2), 0, -sqrt(2) | / 2*sqrt(2)
+%                 |   1,     0,   -1     |
+%
+%        Type 12: | 1, sqrt(2), 1 |
+%                 | 0,   0,     0 | / 2*sqrt(2)
+%                 | 1, sqrt(2), 1 |
+%
+%        Type 13: | sqrt(2), -1,    0     |
+%                 |  -1,      0,    1     | / 2*sqrt(2)
+%                 |   0,      1, -sqrt(2) |
+%
+%        Type 14: |    0,     1, -sqrt(2) |
+%                 |   -1,     0,     1    | / 2*sqrt(2)
+%                 | sqrt(2), -1,     0    |
+%
+%        Type 15: | 0, -1, 0 |
+%                 | 1,  0, 1 | / 2
+%                 | 0, -1, 0 |
+%
+%        Type 16: |  1, 0, -1 |
+%                 |  0, 0,  0 | / 2
+%                 | -1, 0,  1 |
+%
+%        Type 17: |  1, -2,  1 |
+%                 | -2,  4, -2 | / 6
+%                 | -1, -2,  1 |
+%
+%        Type 18: | -2, 1, -2 |
+%                 |  1, 4,  1 | / 6
+%                 | -2, 1, -2 |
+%
+%        Type 19: | 1, 1, 1 |
+%                 | 1, 1, 1 | / 3
+%                 | 1, 1, 1 |
+%
+%      The first 4 are for edge detection, the next 4 are for line detection
+%      and the last is to add a average component to the results.
+%
+%      Using a special type of '-1' will return all 9 pre-weighted kernels
+%      as a multi-kernel list, so that you can use them directly (without
+%      normalization) with the special "-set option:morphology:compose Plus"
+%      setting to apply the full FreiChen Edge Detection Technique.
+%
+%      If 'type' is large it will be taken to be an actual rotation angle for
+%      the default FreiChen (type 0) kernel.  As such  FreiChen:45  will look
+%      like a  Sobel:45  but with 'sqrt(2)' instead of '2' values.
+%
+%      WARNING: The above was layed out as per
+%          http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf
+%      But rotated 90 degrees so direction is from left rather than the top.
+%      I have yet to find any secondary confirmation of the above. The only
+%      other source found was actual source code at
+%          http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf
+%      Neigher paper defineds the kernels in a way that looks locical or
+%      correct when taken as a whole.
+%
+%  Boolean Kernels
+%
+%    Diamond:[{radius}[,{scale}]]
+%       Generate a diamond shaped kernel with given radius to the points.
+%       Kernel size will again be radius*2+1 square and defaults to radius 1,
+%       generating a 3x3 kernel that is slightly larger than a square.
+%
+%    Square:[{radius}[,{scale}]]
+%       Generate a square shaped kernel of size radius*2+1, and defaulting
+%       to a 3x3 (radius 1).
+%
+%    Octagon:[{radius}[,{scale}]]
+%       Generate octagonal shaped kernel of given radius and constant scale.
+%       Default radius is 3 producing a 7x7 kernel. A radius of 1 will result
+%       in "Diamond" kernel.
+%
+%    Disk:[{radius}[,{scale}]]
+%       Generate a binary disk, thresholded at the radius given, the radius
+%       may be a float-point value. Final Kernel size is floor(radius)*2+1
+%       square. A radius of 5.3 is the default.
+%
+%       NOTE: That a low radii Disk kernels produce the same results as
+%       many of the previously defined kernels, but differ greatly at larger
+%       radii.  Here is a table of equivalences...
+%          "Disk:1"    => "Diamond", "Octagon:1", or "Cross:1"
+%          "Disk:1.5"  => "Square"
+%          "Disk:2"    => "Diamond:2"
+%          "Disk:2.5"  => "Octagon"
+%          "Disk:2.9"  => "Square:2"
+%          "Disk:3.5"  => "Octagon:3"
+%          "Disk:4.5"  => "Octagon:4"
+%          "Disk:5.4"  => "Octagon:5"
+%          "Disk:6.4"  => "Octagon:6"
+%       All other Disk shapes are unique to this kernel, but because a "Disk"
+%       is more circular when using a larger radius, using a larger radius is
+%       preferred over iterating the morphological operation.
+%
+%    Rectangle:{geometry}
+%       Simply generate a rectangle of 1's with the size given. You can also
+%       specify the location of the 'control point', otherwise the closest
+%       pixel to the center of the rectangle is selected.
+%
+%       Properly centered and odd sized rectangles work the best.
+%
+%  Symbol Dilation Kernels
+%
+%    These kernel is not a good general morphological kernel, but is used
+%    more for highlighting and marking any single pixels in an image using,
+%    a "Dilate" method as appropriate.
+%
+%    For the same reasons iterating these kernels does not produce the
+%    same result as using a larger radius for the symbol.
+%
+%    Plus:[{radius}[,{scale}]]
+%    Cross:[{radius}[,{scale}]]
+%       Generate a kernel in the shape of a 'plus' or a 'cross' with
+%       a each arm the length of the given radius (default 2).
+%
+%       NOTE: "plus:1" is equivalent to a "Diamond" kernel.
+%
+%    Ring:{radius1},{radius2}[,{scale}]
+%       A ring of the values given that falls between the two radii.
+%       Defaults to a ring of approximataly 3 radius in a 7x7 kernel.
+%       This is the 'edge' pixels of the default "Disk" kernel,
+%       More specifically, "Ring" -> "Ring:2.5,3.5,1.0"
+%
+%  Hit and Miss Kernels
+%
+%    Peak:radius1,radius2
+%       Find any peak larger than the pixels the fall between the two radii.
+%       The default ring of pixels is as per "Ring".
+%    Edges
+%       Find flat orthogonal edges of a binary shape
+%    Corners
+%       Find 90 degree corners of a binary shape
+%    Diagonals:type
+%       A special kernel to thin the 'outside' of diagonals
+%    LineEnds:type
+%       Find end points of lines (for pruning a skeletion)
+%       Two types of lines ends (default to both) can be searched for
+%         Type 0: All line ends
+%         Type 1: single kernel for 4-conneected line ends
+%         Type 2: single kernel for simple line ends
+%    LineJunctions
+%       Find three line junctions (within a skeletion)
+%         Type 0: all line junctions
+%         Type 1: Y Junction kernel
+%         Type 2: Diagonal T Junction kernel
+%         Type 3: Orthogonal T Junction kernel
+%         Type 4: Diagonal X Junction kernel
+%         Type 5: Orthogonal + Junction kernel
+%    Ridges:type
+%       Find single pixel ridges or thin lines
+%         Type 1: Fine single pixel thick lines and ridges
+%         Type 2: Find two pixel thick lines and ridges
+%    ConvexHull
+%       Octagonal Thickening Kernel, to generate convex hulls of 45 degrees
+%    Skeleton:type
+%       Traditional skeleton generating kernels.
+%         Type 1: Tradional Skeleton kernel (4 connected skeleton)
+%         Type 2: HIPR2 Skeleton kernel (8 connected skeleton)
+%         Type 3: Thinning skeleton based on a ressearch paper by
+%                 Dan S. Bloomberg (Default Type)
+%    ThinSE:type
+%       A huge variety of Thinning Kernels designed to preserve conectivity.
+%       many other kernel sets use these kernels as source definitions.
+%       Type numbers are 41-49, 81-89, 481, and 482 which are based on
+%       the super and sub notations used in the source research paper.
+%
+%  Distance Measuring Kernels
+%
+%    Different types of distance measuring methods, which are used with the
+%    a 'Distance' morphology method for generating a gradient based on
+%    distance from an edge of a binary shape, though there is a technique
+%    for handling a anti-aliased shape.
+%
+%    See the 'Distance' Morphological Method, for information of how it is
+%    applied.
+%
+%    Chebyshev:[{radius}][x{scale}[%!]]
+%       Chebyshev Distance (also known as Tchebychev or Chessboard distance)
+%       is a value of one to any neighbour, orthogonal or diagonal. One why
+%       of thinking of it is the number of squares a 'King' or 'Queen' in
+%       chess needs to traverse reach any other position on a chess board.
+%       It results in a 'square' like distance function, but one where
+%       diagonals are given a value that is closer than expected.
+%
+%    Manhattan:[{radius}][x{scale}[%!]]
+%       Manhattan Distance (also known as Rectilinear, City Block, or the Taxi
+%       Cab distance metric), it is the distance needed when you can only
+%       travel in horizontal or vertical directions only.  It is the
+%       distance a 'Rook' in chess would have to travel, and results in a
+%       diamond like distances, where diagonals are further than expected.
+%
+%    Octagonal:[{radius}][x{scale}[%!]]
+%       An interleving of Manhatten and Chebyshev metrics producing an
+%       increasing octagonally shaped distance.  Distances matches those of
+%       the "Octagon" shaped kernel of the same radius.  The minimum radius
+%       and default is 2, producing a 5x5 kernel.
+%
+%    Euclidean:[{radius}][x{scale}[%!]]
+%       Euclidean distance is the 'direct' or 'as the crow flys' distance.
+%       However by default the kernel size only has a radius of 1, which
+%       limits the distance to 'Knight' like moves, with only orthogonal and
+%       diagonal measurements being correct.  As such for the default kernel
+%       you will get octagonal like distance function.
+%
+%       However using a larger radius such as "Euclidean:4" you will get a
+%       much smoother distance gradient from the edge of the shape. Especially
+%       if the image is pre-processed to include any anti-aliasing pixels.
+%       Of course a larger kernel is slower to use, and not always needed.
+%
+%    The first three Distance Measuring Kernels will only generate distances
+%    of exact multiples of {scale} in binary images. As such you can use a
+%    scale of 1 without loosing any information.  However you also need some
+%    scaling when handling non-binary anti-aliased shapes.
+%
+%    The "Euclidean" Distance Kernel however does generate a non-integer
+%    fractional results, and as such scaling is vital even for binary shapes.
+%
+*/
+
+MagickExport KernelInfo *AcquireKernelBuiltIn(const KernelInfoType type,
+   const GeometryInfo *args)
+{
+  KernelInfo
+    *kernel;
+
+  register ssize_t
+    i;
+
+  register ssize_t
+    u,
+    v;
+
+  double
+    nan = sqrt((double)-1.0);  /* Special Value : Not A Number */
+
+  /* Generate a new empty kernel if needed */
+  kernel=(KernelInfo *) NULL;
+  switch(type) {
+    case UndefinedKernel:    /* These should not call this function */
+    case UserDefinedKernel:
+      assert("Should not call this function" != (char *)NULL);
+      break;
+    case LaplacianKernel:   /* Named Descrete Convolution Kernels */
+    case SobelKernel:       /* these are defined using other kernels */
+    case RobertsKernel:
+    case PrewittKernel:
+    case CompassKernel:
+    case KirschKernel:
+    case FreiChenKernel:
+    case EdgesKernel:       /* Hit and Miss kernels */
+    case CornersKernel:
+    case DiagonalsKernel:
+    case LineEndsKernel:
+    case LineJunctionsKernel:
+    case RidgesKernel:
+    case ConvexHullKernel:
+    case SkeletonKernel:
+    case ThinSEKernel:
+      break;               /* A pre-generated kernel is not needed */
+#if 0
+    /* set to 1 to do a compile-time check that we haven't missed anything */
+    case UnityKernel:
+    case GaussianKernel:
+    case DoGKernel:
+    case LoGKernel:
+    case BlurKernel:
+    case CometKernel:
+    case DiamondKernel:
+    case SquareKernel:
+    case RectangleKernel:
+    case OctagonKernel:
+    case DiskKernel:
+    case PlusKernel:
+    case CrossKernel:
+    case RingKernel:
+    case PeaksKernel:
+    case ChebyshevKernel:
+    case ManhattanKernel:
+    case OctangonalKernel:
+    case EuclideanKernel:
+#else
+    default:
+#endif
+      /* Generate the base Kernel Structure */
+      kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
+      if (kernel == (KernelInfo *) NULL)
+        return(kernel);
+      (void) ResetMagickMemory(kernel,0,sizeof(*kernel));
+      kernel->minimum = kernel->maximum = kernel->angle = 0.0;
+      kernel->negative_range = kernel->positive_range = 0.0;
+      kernel->type = type;
+      kernel->next = (KernelInfo *) NULL;
+      kernel->signature = MagickSignature;
+      break;
+  }
+
+  switch(type) {
+    /*
+      Convolution Kernels
+    */
+    case UnityKernel:
+      {
+        kernel->height = kernel->width = (size_t) 1;
+        kernel->x = kernel->y = (ssize_t) 0;
+        kernel->values=(double *) AcquireQuantumMemory(1,sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+        kernel->maximum = kernel->values[0] = args->rho;
+        break;
+      }
+      break;
+    case GaussianKernel:
+    case DoGKernel:
+    case LoGKernel:
+      { double
+          sigma = fabs(args->sigma),
+          sigma2 = fabs(args->xi),
+          A, B, R;
+
+        if ( args->rho >= 1.0 )
+          kernel->width = (size_t)args->rho*2+1;
+        else if ( (type != DoGKernel) || (sigma >= sigma2) )
+          kernel->width = GetOptimalKernelWidth2D(args->rho,sigma);
+        else
+          kernel->width = GetOptimalKernelWidth2D(args->rho,sigma2);
+        kernel->height = kernel->width;
+        kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        /* WARNING: The following generates a 'sampled gaussian' kernel.
+         * What we really want is a 'discrete gaussian' kernel.
+         *
+         * How to do this is I don't know, but appears to be basied on the
+         * Error Function 'erf()' (intergral of a gaussian)
+         */
+
+        if ( type == GaussianKernel || type == DoGKernel )
+          { /* Calculate a Gaussian,  OR positive half of a DoG */
+            if ( sigma > MagickEpsilon )
+              { A = 1.0/(2.0*sigma*sigma);  /* simplify loop expressions */
+                B = (double) (1.0/(Magick2PI*sigma*sigma));
+                for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+                  for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+                      kernel->values[i] = exp(-((double)(u*u+v*v))*A)*B;
+              }
+            else /* limiting case - a unity (normalized Dirac) kernel */
+              { (void) ResetMagickMemory(kernel->values,0, (size_t)
+                            kernel->width*kernel->height*sizeof(double));
+                kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
+              }
+          }
+
+        if ( type == DoGKernel )
+          { /* Subtract a Negative Gaussian for "Difference of Gaussian" */
+            if ( sigma2 > MagickEpsilon )
+              { sigma = sigma2;                /* simplify loop expressions */
+                A = 1.0/(2.0*sigma*sigma);
+                B = (double) (1.0/(Magick2PI*sigma*sigma));
+                for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+                  for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+                    kernel->values[i] -= exp(-((double)(u*u+v*v))*A)*B;
+              }
+            else /* limiting case - a unity (normalized Dirac) kernel */
+              kernel->values[kernel->x+kernel->y*kernel->width] -= 1.0;
+          }
+
+        if ( type == LoGKernel )
+          { /* Calculate a Laplacian of a Gaussian - Or Mexician Hat */
+            if ( sigma > MagickEpsilon )
+              { A = 1.0/(2.0*sigma*sigma);  /* simplify loop expressions */
+                B = (double) (1.0/(MagickPI*sigma*sigma*sigma*sigma));
+                for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+                  for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+                    { R = ((double)(u*u+v*v))*A;
+                      kernel->values[i] = (1-R)*exp(-R)*B;
+                    }
+              }
+            else /* special case - generate a unity kernel */
+              { (void) ResetMagickMemory(kernel->values,0, (size_t)
+                            kernel->width*kernel->height*sizeof(double));
+                kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
+              }
+          }
+
+        /* Note the above kernels may have been 'clipped' by a user defined
+        ** radius, producing a smaller (darker) kernel.  Also for very small
+        ** sigma's (> 0.1) the central value becomes larger than one, and thus
+        ** producing a very bright kernel.
+        **
+        ** Normalization will still be needed.
+        */
+
+        /* Normalize the 2D Gaussian Kernel
+        **
+        ** NB: a CorrelateNormalize performs a normal Normalize if
+        ** there are no negative values.
+        */
+        CalcKernelMetaData(kernel);  /* the other kernel meta-data */
+        ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
+
+        break;
+      }
+    case BlurKernel:
+      { double
+          sigma = fabs(args->sigma),
+          alpha, beta;
+
+        if ( args->rho >= 1.0 )
+          kernel->width = (size_t)args->rho*2+1;
+        else
+          kernel->width = GetOptimalKernelWidth1D(args->rho,sigma);
+        kernel->height = 1;
+        kernel->x = (ssize_t) (kernel->width-1)/2;
+        kernel->y = 0;
+        kernel->negative_range = kernel->positive_range = 0.0;
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+#if 1
+#define KernelRank 3
+        /* Formula derived from GetBlurKernel() in "effect.c" (plus bug fix).
+        ** It generates a gaussian 3 times the width, and compresses it into
+        ** the expected range.  This produces a closer normalization of the
+        ** resulting kernel, especially for very low sigma values.
+        ** As such while wierd it is prefered.
+        **
+        ** I am told this method originally came from Photoshop.
+        **
+        ** A properly normalized curve is generated (apart from edge clipping)
+        ** even though we later normalize the result (for edge clipping)
+        ** to allow the correct generation of a "Difference of Blurs".
+        */
+
+        /* initialize */
+        v = (ssize_t) (kernel->width*KernelRank-1)/2; /* start/end points to fit range */
+        (void) ResetMagickMemory(kernel->values,0, (size_t)
+                     kernel->width*kernel->height*sizeof(double));
+        /* Calculate a Positive 1D Gaussian */
+        if ( sigma > MagickEpsilon )
+          { sigma *= KernelRank;               /* simplify loop expressions */
+            alpha = 1.0/(2.0*sigma*sigma);
+            beta= (double) (1.0/(MagickSQ2PI*sigma ));
+            for ( u=-v; u <= v; u++) {
+              kernel->values[(u+v)/KernelRank] +=
+                              exp(-((double)(u*u))*alpha)*beta;
+            }
+          }
+        else /* special case - generate a unity kernel */
+          kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
+#else
+        /* Direct calculation without curve averaging */
+
+        /* Calculate a Positive Gaussian */
+        if ( sigma > MagickEpsilon )
+          { alpha = 1.0/(2.0*sigma*sigma);    /* simplify loop expressions */
+            beta = 1.0/(MagickSQ2PI*sigma);
+            for ( i=0, u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              kernel->values[i] = exp(-((double)(u*u))*alpha)*beta;
+          }
+        else /* special case - generate a unity kernel */
+          { (void) ResetMagickMemory(kernel->values,0, (size_t)
+                         kernel->width*kernel->height*sizeof(double));
+            kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
+          }
+#endif
+        /* Note the above kernel may have been 'clipped' by a user defined
+        ** radius, producing a smaller (darker) kernel.  Also for very small
+        ** sigma's (> 0.1) the central value becomes larger than one, and thus
+        ** producing a very bright kernel.
+        **
+        ** Normalization will still be needed.
+        */
+
+        /* Normalize the 1D Gaussian Kernel
+        **
+        ** NB: a CorrelateNormalize performs a normal Normalize if
+        ** there are no negative values.
+        */
+        CalcKernelMetaData(kernel);  /* the other kernel meta-data */
+        ScaleKernelInfo(kernel, 1.0, CorrelateNormalizeValue);
+
+        /* rotate the 1D kernel by given angle */
+        RotateKernelInfo(kernel, args->xi );
+        break;
+      }
+    case CometKernel:
+      { double
+          sigma = fabs(args->sigma),
+          A;
+
+        if ( args->rho < 1.0 )
+          kernel->width = (GetOptimalKernelWidth1D(args->rho,sigma)-1)/2+1;
+        else
+          kernel->width = (size_t)args->rho;
+        kernel->x = kernel->y = 0;
+        kernel->height = 1;
+        kernel->negative_range = kernel->positive_range = 0.0;
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        /* A comet blur is half a 1D gaussian curve, so that the object is
+        ** blurred in one direction only.  This may not be quite the right
+        ** curve to use so may change in the future. The function must be
+        ** normalised after generation, which also resolves any clipping.
+        **
+        ** As we are normalizing and not subtracting gaussians,
+        ** there is no need for a divisor in the gaussian formula
+        **
+        ** It is less comples
+        */
+        if ( sigma > MagickEpsilon )
+          {
+#if 1
+#define KernelRank 3
+            v = (ssize_t) kernel->width*KernelRank; /* start/end points */
+            (void) ResetMagickMemory(kernel->values,0, (size_t)
+                          kernel->width*sizeof(double));
+            sigma *= KernelRank;            /* simplify the loop expression */
+            A = 1.0/(2.0*sigma*sigma);
+            /* B = 1.0/(MagickSQ2PI*sigma); */
+            for ( u=0; u < v; u++) {
+              kernel->values[u/KernelRank] +=
+                  exp(-((double)(u*u))*A);
+              /*  exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */
+            }
+            for (i=0; i < (ssize_t) kernel->width; i++)
+              kernel->positive_range += kernel->values[i];
+#else
+            A = 1.0/(2.0*sigma*sigma);     /* simplify the loop expression */
+            /* B = 1.0/(MagickSQ2PI*sigma); */
+            for ( i=0; i < (ssize_t) kernel->width; i++)
+              kernel->positive_range +=
+                kernel->values[i] =
+                  exp(-((double)(i*i))*A);
+                /* exp(-((double)(i*i))/2.0*sigma*sigma)/(MagickSQ2PI*sigma); */
+#endif
+          }
+        else /* special case - generate a unity kernel */
+          { (void) ResetMagickMemory(kernel->values,0, (size_t)
+                         kernel->width*kernel->height*sizeof(double));
+            kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
+            kernel->positive_range = 1.0;
+          }
+
+        kernel->minimum = 0.0;
+        kernel->maximum = kernel->values[0];
+        kernel->negative_range = 0.0;
+
+        ScaleKernelInfo(kernel, 1.0, NormalizeValue); /* Normalize */
+        RotateKernelInfo(kernel, args->xi); /* Rotate by angle */
+        break;
+      }
+
+    /*
+      Convolution Kernels - Well Known Named Constant Kernels
+    */
+    case LaplacianKernel:
+      { switch ( (int) args->rho ) {
+          case 0:
+          default: /* laplacian square filter -- default */
+            kernel=ParseKernelArray("3: -1,-1,-1  -1,8,-1  -1,-1,-1");
+            break;
+          case 1:  /* laplacian diamond filter */
+            kernel=ParseKernelArray("3: 0,-1,0  -1,4,-1  0,-1,0");
+            break;
+          case 2:
+            kernel=ParseKernelArray("3: -2,1,-2  1,4,1  -2,1,-2");
+            break;
+          case 3:
+            kernel=ParseKernelArray("3: 1,-2,1  -2,4,-2  1,-2,1");
+            break;
+          case 5:   /* a 5x5 laplacian */
+            kernel=ParseKernelArray(
+              "5: -4,-1,0,-1,-4  -1,2,3,2,-1  0,3,4,3,0  -1,2,3,2,-1  -4,-1,0,-1,-4");
+            break;
+          case 7:   /* a 7x7 laplacian */
+            kernel=ParseKernelArray(
+              "7:-10,-5,-2,-1,-2,-5,-10 -5,0,3,4,3,0,-5 -2,3,6,7,6,3,-2 -1,4,7,8,7,4,-1 -2,3,6,7,6,3,-2 -5,0,3,4,3,0,-5 -10,-5,-2,-1,-2,-5,-10" );
+            break;
+          case 15:  /* a 5x5 LoG (sigma approx 1.4) */
+            kernel=ParseKernelArray(
+              "5: 0,0,-1,0,0  0,-1,-2,-1,0  -1,-2,16,-2,-1  0,-1,-2,-1,0  0,0,-1,0,0");
+            break;
+          case 19:  /* a 9x9 LoG (sigma approx 1.4) */
+            /* http://www.cscjournals.org/csc/manuscript/Journals/IJIP/volume3/Issue1/IJIP-15.pdf */
+            kernel=ParseKernelArray(
+              "9: 0,-1,-1,-2,-2,-2,-1,-1,0  -1,-2,-4,-5,-5,-5,-4,-2,-1  -1,-4,-5,-3,-0,-3,-5,-4,-1  -2,-5,-3,12,24,12,-3,-5,-2  -2,-5,-0,24,40,24,-0,-5,-2  -2,-5,-3,12,24,12,-3,-5,-2  -1,-4,-5,-3,-0,-3,-5,-4,-1  -1,-2,-4,-5,-5,-5,-4,-2,-1  0,-1,-1,-2,-2,-2,-1,-1,0");
+            break;
+        }
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = type;
+        break;
+      }
+    case SobelKernel:
+      { /* Simple Sobel Kernel */
+        kernel=ParseKernelArray("3: 1,0,-1  2,0,-2  1,0,-1");
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = type;
+        RotateKernelInfo(kernel, args->rho);
+        break;
+      }
+    case RobertsKernel:
+      {
+        kernel=ParseKernelArray("3: 0,0,0  1,-1,0  0,0,0");
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = type;
+        RotateKernelInfo(kernel, args->rho);
+        break;
+      }
+    case PrewittKernel:
+      {
+        kernel=ParseKernelArray("3: 1,0,-1  1,0,-1  1,0,-1");
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = type;
+        RotateKernelInfo(kernel, args->rho);
+        break;
+      }
+    case CompassKernel:
+      {
+        kernel=ParseKernelArray("3: 1,1,-1  1,-2,-1  1,1,-1");
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = type;
+        RotateKernelInfo(kernel, args->rho);
+        break;
+      }
+    case KirschKernel:
+      {
+        kernel=ParseKernelArray("3: 5,-3,-3  5,0,-3  5,-3,-3");
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = type;
+        RotateKernelInfo(kernel, args->rho);
+        break;
+      }
+    case FreiChenKernel:
+      /* Direction is set to be left to right positive */
+      /* http://www.math.tau.ac.il/~turkel/notes/edge_detectors.pdf -- RIGHT? */
+      /* http://ltswww.epfl.ch/~courstiv/exos_labos/sol3.pdf -- WRONG? */
+      { switch ( (int) args->rho ) {
+          default:
+          case 0:
+            kernel=ParseKernelArray("3: 1,0,-1  2,0,-2  1,0,-1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            kernel->values[3] = +MagickSQ2;
+            kernel->values[5] = -MagickSQ2;
+            CalcKernelMetaData(kernel);     /* recalculate meta-data */
+            break;
+          case 2:
+            kernel=ParseKernelArray("3: 1,2,0  2,0,-2  0,-2,-1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            kernel->values[1] = kernel->values[3] = +MagickSQ2;
+            kernel->values[5] = kernel->values[7] = -MagickSQ2;
+            CalcKernelMetaData(kernel);     /* recalculate meta-data */
+            ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
+            break;
+          case 10:
+            kernel=AcquireKernelInfo("FreiChen:11;FreiChen:12;FreiChen:13;FreiChen:14;FreiChen:15;FreiChen:16;FreiChen:17;FreiChen:18;FreiChen:19");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            break;
+          case 1:
+          case 11:
+            kernel=ParseKernelArray("3: 1,0,-1  2,0,-2  1,0,-1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            kernel->values[3] = +MagickSQ2;
+            kernel->values[5] = -MagickSQ2;
+            CalcKernelMetaData(kernel);     /* recalculate meta-data */
+            ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
+            break;
+          case 12:
+            kernel=ParseKernelArray("3: 1,2,1  0,0,0  1,2,1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            kernel->values[1] = +MagickSQ2;
+            kernel->values[7] = +MagickSQ2;
+            CalcKernelMetaData(kernel);
+            ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
+            break;
+          case 13:
+            kernel=ParseKernelArray("3: 2,-1,0  -1,0,1  0,1,-2");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            kernel->values[0] = +MagickSQ2;
+            kernel->values[8] = -MagickSQ2;
+            CalcKernelMetaData(kernel);
+            ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
+            break;
+          case 14:
+            kernel=ParseKernelArray("3: 0,1,-2  -1,0,1  2,-1,0");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            kernel->values[2] = -MagickSQ2;
+            kernel->values[6] = +MagickSQ2;
+            CalcKernelMetaData(kernel);
+            ScaleKernelInfo(kernel, (double) (1.0/2.0*MagickSQ2), NoValue);
+            break;
+          case 15:
+            kernel=ParseKernelArray("3: 0,-1,0  1,0,1  0,-1,0");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
+            break;
+          case 16:
+            kernel=ParseKernelArray("3: 1,0,-1  0,0,0  -1,0,1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            ScaleKernelInfo(kernel, 1.0/2.0, NoValue);
+            break;
+          case 17:
+            kernel=ParseKernelArray("3: 1,-2,1  -2,4,-2  -1,-2,1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
+            break;
+          case 18:
+            kernel=ParseKernelArray("3: -2,1,-2  1,4,1  -2,1,-2");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            ScaleKernelInfo(kernel, 1.0/6.0, NoValue);
+            break;
+          case 19:
+            kernel=ParseKernelArray("3: 1,1,1  1,1,1  1,1,1");
+            if (kernel == (KernelInfo *) NULL)
+              return(kernel);
+            kernel->type = type;
+            ScaleKernelInfo(kernel, 1.0/3.0, NoValue);
+            break;
+        }
+        if ( fabs(args->sigma) > MagickEpsilon )
+          /* Rotate by correctly supplied 'angle' */
+          RotateKernelInfo(kernel, args->sigma);
+        else if ( args->rho > 30.0 || args->rho < -30.0 )
+          /* Rotate by out of bounds 'type' */
+          RotateKernelInfo(kernel, args->rho);
+        break;
+      }
+
+    /*
+      Boolean or Shaped Kernels
+    */
+    case DiamondKernel:
+      {
+        if (args->rho < 1.0)
+          kernel->width = kernel->height = 3;  /* default radius = 1 */
+        else
+          kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+        kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        /* set all kernel values within diamond area to scale given */
+        for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+          for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+            if ( (labs((long) u)+labs((long) v)) <= (long) kernel->x)
+              kernel->positive_range += kernel->values[i] = args->sigma;
+            else
+              kernel->values[i] = nan;
+        kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
+        break;
+      }
+    case SquareKernel:
+    case RectangleKernel:
+      { double
+          scale;
+        if ( type == SquareKernel )
+          {
+            if (args->rho < 1.0)
+              kernel->width = kernel->height = 3;  /* default radius = 1 */
+            else
+              kernel->width = kernel->height = (size_t) (2*args->rho+1);
+            kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+            scale = args->sigma;
+          }
+        else {
+            /* NOTE: user defaults set in "AcquireKernelInfo()" */
+            if ( args->rho < 1.0 || args->sigma < 1.0 )
+              return(DestroyKernelInfo(kernel));    /* invalid args given */
+            kernel->width = (size_t)args->rho;
+            kernel->height = (size_t)args->sigma;
+            if ( args->xi  < 0.0 || args->xi  > (double)kernel->width ||
+                 args->psi < 0.0 || args->psi > (double)kernel->height )
+              return(DestroyKernelInfo(kernel));    /* invalid args given */
+            kernel->x = (ssize_t) args->xi;
+            kernel->y = (ssize_t) args->psi;
+            scale = 1.0;
+          }
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        /* set all kernel values to scale given */
+        u=(ssize_t) (kernel->width*kernel->height);
+        for ( i=0; i < u; i++)
+            kernel->values[i] = scale;
+        kernel->minimum = kernel->maximum = scale;   /* a flat shape */
+        kernel->positive_range = scale*u;
+        break;
+      }
+      case OctagonKernel:
+        {
+          if (args->rho < 1.0)
+            kernel->width = kernel->height = 5;  /* default radius = 2 */
+          else
+            kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              if ( (labs((long) u)+labs((long) v)) <=
+                        ((long)kernel->x + (long)(kernel->x/2)) )
+                kernel->positive_range += kernel->values[i] = args->sigma;
+              else
+                kernel->values[i] = nan;
+          kernel->minimum = kernel->maximum = args->sigma;  /* a flat shape */
+          break;
+        }
+      case DiskKernel:
+        {
+          ssize_t
+            limit = (ssize_t)(args->rho*args->rho);
+
+          if (args->rho < 0.4)           /* default radius approx 4.3 */
+            kernel->width = kernel->height = 9L, limit = 18L;
+          else
+            kernel->width = kernel->height = (size_t)fabs(args->rho)*2+1;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              if ((u*u+v*v) <= limit)
+                kernel->positive_range += kernel->values[i] = args->sigma;
+              else
+                kernel->values[i] = nan;
+          kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
+          break;
+        }
+      case PlusKernel:
+        {
+          if (args->rho < 1.0)
+            kernel->width = kernel->height = 5;  /* default radius 2 */
+          else
+            kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          /* set all kernel values along axises to given scale */
+          for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              kernel->values[i] = (u == 0 || v == 0) ? args->sigma : nan;
+          kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
+          kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
+          break;
+        }
+      case CrossKernel:
+        {
+          if (args->rho < 1.0)
+            kernel->width = kernel->height = 5;  /* default radius 2 */
+          else
+            kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          /* set all kernel values along axises to given scale */
+          for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              kernel->values[i] = (u == v || u == -v) ? args->sigma : nan;
+          kernel->minimum = kernel->maximum = args->sigma;   /* a flat shape */
+          kernel->positive_range = args->sigma*(kernel->width*2.0 - 1.0);
+          break;
+        }
+      /*
+        HitAndMiss Kernels
+      */
+      case RingKernel:
+      case PeaksKernel:
+        {
+          ssize_t
+            limit1,
+            limit2,
+            scale;
+
+          if (args->rho < args->sigma)
+            {
+              kernel->width = ((size_t)args->sigma)*2+1;
+              limit1 = (ssize_t)(args->rho*args->rho);
+              limit2 = (ssize_t)(args->sigma*args->sigma);
+            }
+          else
+            {
+              kernel->width = ((size_t)args->rho)*2+1;
+              limit1 = (ssize_t)(args->sigma*args->sigma);
+              limit2 = (ssize_t)(args->rho*args->rho);
+            }
+          if ( limit2 <= 0 )
+            kernel->width = 7L, limit1 = 7L, limit2 = 11L;
+
+          kernel->height = kernel->width;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          /* set a ring of points of 'scale' ( 0.0 for PeaksKernel ) */
+          scale = (ssize_t) (( type == PeaksKernel) ? 0.0 : args->xi);
+          for ( i=0, v= -kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              { ssize_t radius=u*u+v*v;
+                if (limit1 < radius && radius <= limit2)
+                  kernel->positive_range += kernel->values[i] = (double) scale;
+                else
+                  kernel->values[i] = nan;
+              }
+          kernel->minimum = kernel->maximum = (double) scale;
+          if ( type == PeaksKernel ) {
+            /* set the central point in the middle */
+            kernel->values[kernel->x+kernel->y*kernel->width] = 1.0;
+            kernel->positive_range = 1.0;
+            kernel->maximum = 1.0;
+          }
+          break;
+        }
+      case EdgesKernel:
+        {
+          kernel=AcquireKernelInfo("ThinSE:482");
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          ExpandMirrorKernelInfo(kernel); /* mirror expansion of kernels */
+          break;
+        }
+      case CornersKernel:
+        {
+          kernel=AcquireKernelInfo("ThinSE:87");
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          ExpandRotateKernelInfo(kernel, 90.0); /* Expand 90 degree rotations */
+          break;
+        }
+      case DiagonalsKernel:
+        {
+          switch ( (int) args->rho ) {
+            case 0:
+            default:
+              { KernelInfo
+                  *new_kernel;
+                kernel=ParseKernelArray("3: 0,0,0  0,-,1  1,1,-");
+                if (kernel == (KernelInfo *) NULL)
+                  return(kernel);
+                kernel->type = type;
+                new_kernel=ParseKernelArray("3: 0,0,1  0,-,1  0,1,-");
+                if (new_kernel == (KernelInfo *) NULL)
+                  return(DestroyKernelInfo(kernel));
+                new_kernel->type = type;
+                LastKernelInfo(kernel)->next = new_kernel;
+                ExpandMirrorKernelInfo(kernel);
+                return(kernel);
+              }
+            case 1:
+              kernel=ParseKernelArray("3: 0,0,0  0,-,1  1,1,-");
+              break;
+            case 2:
+              kernel=ParseKernelArray("3: 0,0,1  0,-,1  0,1,-");
+              break;
+          }
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          RotateKernelInfo(kernel, args->sigma);
+          break;
+        }
+      case LineEndsKernel:
+        { /* Kernels for finding the end of thin lines */
+          switch ( (int) args->rho ) {
+            case 0:
+            default:
+              /* set of kernels to find all end of lines */
+              return(AcquireKernelInfo("LineEnds:1>;LineEnds:2>"));
+            case 1:
+              /* kernel for 4-connected line ends - no rotation */
+              kernel=ParseKernelArray("3: 0,0,-  0,1,1  0,0,-");
+              break;
+          case 2:
+              /* kernel to add for 8-connected lines - no rotation */
+              kernel=ParseKernelArray("3: 0,0,0  0,1,0  0,0,1");
+              break;
+          case 3:
+              /* kernel to add for orthogonal line ends - does not find corners */
+              kernel=ParseKernelArray("3: 0,0,0  0,1,1  0,0,0");
+              break;
+          case 4:
+              /* traditional line end - fails on last T end */
+              kernel=ParseKernelArray("3: 0,0,0  0,1,-  0,0,-");
+              break;
+          }
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          RotateKernelInfo(kernel, args->sigma);
+          break;
+        }
+      case LineJunctionsKernel:
+        { /* kernels for finding the junctions of multiple lines */
+          switch ( (int) args->rho ) {
+            case 0:
+            default:
+              /* set of kernels to find all line junctions */
+              return(AcquireKernelInfo("LineJunctions:1@;LineJunctions:2>"));
+            case 1:
+              /* Y Junction */
+              kernel=ParseKernelArray("3: 1,-,1  -,1,-  -,1,-");
+              break;
+            case 2:
+              /* Diagonal T Junctions */
+              kernel=ParseKernelArray("3: 1,-,-  -,1,-  1,-,1");
+              break;
+            case 3:
+              /* Orthogonal T Junctions */
+              kernel=ParseKernelArray("3: -,-,-  1,1,1  -,1,-");
+              break;
+            case 4:
+              /* Diagonal X Junctions */
+              kernel=ParseKernelArray("3: 1,-,1  -,1,-  1,-,1");
+              break;
+            case 5:
+              /* Orthogonal X Junctions - minimal diamond kernel */
+              kernel=ParseKernelArray("3: -,1,-  1,1,1  -,1,-");
+              break;
+          }
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          RotateKernelInfo(kernel, args->sigma);
+          break;
+        }
+      case RidgesKernel:
+        { /* Ridges - Ridge finding kernels */
+          KernelInfo
+            *new_kernel;
+          switch ( (int) args->rho ) {
+            case 1:
+            default:
+              kernel=ParseKernelArray("3x1:0,1,0");
+              if (kernel == (KernelInfo *) NULL)
+                return(kernel);
+              kernel->type = type;
+              ExpandRotateKernelInfo(kernel, 90.0); /* 2 rotated kernels (symmetrical) */
+              break;
+            case 2:
+              kernel=ParseKernelArray("4x1:0,1,1,0");
+              if (kernel == (KernelInfo *) NULL)
+                return(kernel);
+              kernel->type = type;
+              ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotated kernels */
+
+              /* Kernels to find a stepped 'thick' line, 4 rotates + mirrors */
+              /* Unfortunatally we can not yet rotate a non-square kernel */
+              /* But then we can't flip a non-symetrical kernel either */
+              new_kernel=ParseKernelArray("4x3+1+1:0,1,1,- -,1,1,- -,1,1,0");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("4x3+2+1:0,1,1,- -,1,1,- -,1,1,0");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("4x3+1+1:-,1,1,0 -,1,1,- 0,1,1,-");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("4x3+2+1:-,1,1,0 -,1,1,- 0,1,1,-");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("3x4+1+1:0,-,- 1,1,1 1,1,1 -,-,0");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("3x4+1+2:0,-,- 1,1,1 1,1,1 -,-,0");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("3x4+1+1:-,-,0 1,1,1 1,1,1 0,-,-");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              new_kernel=ParseKernelArray("3x4+1+2:-,-,0 1,1,1 1,1,1 0,-,-");
+              if (new_kernel == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              new_kernel->type = type;
+              LastKernelInfo(kernel)->next = new_kernel;
+              break;
+          }
+          break;
+        }
+      case ConvexHullKernel:
+        {
+          KernelInfo
+            *new_kernel;
+          /* first set of 8 kernels */
+          kernel=ParseKernelArray("3: 1,1,-  1,0,-  1,-,0");
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          ExpandRotateKernelInfo(kernel, 90.0);
+          /* append the mirror versions too - no flip function yet */
+          new_kernel=ParseKernelArray("3: 1,1,1  1,0,-  -,-,0");
+          if (new_kernel == (KernelInfo *) NULL)
+            return(DestroyKernelInfo(kernel));
+          new_kernel->type = type;
+          ExpandRotateKernelInfo(new_kernel, 90.0);
+          LastKernelInfo(kernel)->next = new_kernel;
+          break;
+        }
+      case SkeletonKernel:
+        {
+          switch ( (int) args->rho ) {
+            case 1:
+            default:
+              /* Traditional Skeleton...
+              ** A cyclically rotated single kernel
+              */
+              kernel=AcquireKernelInfo("ThinSE:482");
+              if (kernel == (KernelInfo *) NULL)
+                return(kernel);
+              kernel->type = type;
+              ExpandRotateKernelInfo(kernel, 45.0); /* 8 rotations */
+              break;
+            case 2:
+              /* HIPR Variation of the cyclic skeleton
+              ** Corners of the traditional method made more forgiving,
+              ** but the retain the same cyclic order.
+              */
+              kernel=AcquireKernelInfo("ThinSE:482; ThinSE:87x90;");
+              if (kernel == (KernelInfo *) NULL)
+                return(kernel);
+              if (kernel->next == (KernelInfo *) NULL)
+                return(DestroyKernelInfo(kernel));
+              kernel->type = type;
+              kernel->next->type = type;
+              ExpandRotateKernelInfo(kernel, 90.0); /* 4 rotations of the 2 kernels */
+              break;
+            case 3:
+              /* Dan Bloomberg Skeleton, from his paper on 3x3 thinning SE's
+              ** "Connectivity-Preserving Morphological Image Thransformations"
+              ** by Dan S. Bloomberg, available on Leptonica, Selected Papers,
+              **   http://www.leptonica.com/papers/conn.pdf
+              */
+              kernel=AcquireKernelInfo(
+                            "ThinSE:41; ThinSE:42; ThinSE:43");
+              if (kernel == (KernelInfo *) NULL)
+                return(kernel);
+              kernel->type = type;
+              kernel->next->type = type;
+              kernel->next->next->type = type;
+              ExpandMirrorKernelInfo(kernel); /* 12 kernels total */
+              break;
+           }
+          break;
+        }
+      case ThinSEKernel:
+        { /* Special kernels for general thinning, while preserving connections
+          ** "Connectivity-Preserving Morphological Image Thransformations"
+          ** by Dan S. Bloomberg, available on Leptonica, Selected Papers,
+          **   http://www.leptonica.com/papers/conn.pdf
+          ** And
+          **   http://tpgit.github.com/Leptonica/ccthin_8c_source.html
+          **
+          ** Note kernels do not specify the origin pixel, allowing them
+          ** to be used for both thickening and thinning operations.
+          */
+          switch ( (int) args->rho ) {
+            /* SE for 4-connected thinning */
+            case 41: /* SE_4_1 */
+              kernel=ParseKernelArray("3: -,-,1  0,-,1  -,-,1");
+              break;
+            case 42: /* SE_4_2 */
+              kernel=ParseKernelArray("3: -,-,1  0,-,1  -,0,-");
+              break;
+            case 43: /* SE_4_3 */
+              kernel=ParseKernelArray("3: -,0,-  0,-,1  -,-,1");
+              break;
+            case 44: /* SE_4_4 */
+              kernel=ParseKernelArray("3: -,0,-  0,-,1  -,0,-");
+              break;
+            case 45: /* SE_4_5 */
+              kernel=ParseKernelArray("3: -,0,1  0,-,1  -,0,-");
+              break;
+            case 46: /* SE_4_6 */
+              kernel=ParseKernelArray("3: -,0,-  0,-,1  -,0,1");
+              break;
+            case 47: /* SE_4_7 */
+              kernel=ParseKernelArray("3: -,1,1  0,-,1  -,0,-");
+              break;
+            case 48: /* SE_4_8 */
+              kernel=ParseKernelArray("3: -,-,1  0,-,1  0,-,1");
+              break;
+            case 49: /* SE_4_9 */
+              kernel=ParseKernelArray("3: 0,-,1  0,-,1  -,-,1");
+              break;
+            /* SE for 8-connected thinning - negatives of the above */
+            case 81: /* SE_8_0 */
+              kernel=ParseKernelArray("3: -,1,-  0,-,1  -,1,-");
+              break;
+            case 82: /* SE_8_2 */
+              kernel=ParseKernelArray("3: -,1,-  0,-,1  0,-,-");
+              break;
+            case 83: /* SE_8_3 */
+              kernel=ParseKernelArray("3: 0,-,-  0,-,1  -,1,-");
+              break;
+            case 84: /* SE_8_4 */
+              kernel=ParseKernelArray("3: 0,-,-  0,-,1  0,-,-");
+              break;
+            case 85: /* SE_8_5 */
+              kernel=ParseKernelArray("3: 0,-,1  0,-,1  0,-,-");
+              break;
+            case 86: /* SE_8_6 */
+              kernel=ParseKernelArray("3: 0,-,-  0,-,1  0,-,1");
+              break;
+            case 87: /* SE_8_7 */
+              kernel=ParseKernelArray("3: -,1,-  0,-,1  0,0,-");
+              break;
+            case 88: /* SE_8_8 */
+              kernel=ParseKernelArray("3: -,1,-  0,-,1  0,1,-");
+              break;
+            case 89: /* SE_8_9 */
+              kernel=ParseKernelArray("3: 0,1,-  0,-,1  -,1,-");
+              break;
+            /* Special combined SE kernels */
+            case 423: /* SE_4_2 , SE_4_3 Combined Kernel */
+              kernel=ParseKernelArray("3: -,-,1  0,-,-  -,0,-");
+              break;
+            case 823: /* SE_8_2 , SE_8_3 Combined Kernel */
+              kernel=ParseKernelArray("3: -,1,-  -,-,1  0,-,-");
+              break;
+            case 481: /* SE_48_1 - General Connected Corner Kernel */
+              kernel=ParseKernelArray("3: -,1,1  0,-,1  0,0,-");
+              break;
+            default:
+            case 482: /* SE_48_2 - General Edge Kernel */
+              kernel=ParseKernelArray("3: 0,-,1  0,-,1  0,-,1");
+              break;
+          }
+          if (kernel == (KernelInfo *) NULL)
+            return(kernel);
+          kernel->type = type;
+          RotateKernelInfo(kernel, args->sigma);
+          break;
+        }
+      /*
+        Distance Measuring Kernels
+      */
+      case ChebyshevKernel:
+        {
+          if (args->rho < 1.0)
+            kernel->width = kernel->height = 3;  /* default radius = 1 */
+          else
+            kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              kernel->positive_range += ( kernel->values[i] =
+                  args->sigma*MagickMax(fabs((double)u),fabs((double)v)) );
+          kernel->maximum = kernel->values[0];
+          break;
+        }
+      case ManhattanKernel:
+        {
+          if (args->rho < 1.0)
+            kernel->width = kernel->height = 3;  /* default radius = 1 */
+          else
+            kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+          kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+          kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                                kernel->height*sizeof(double));
+          if (kernel->values == (double *) NULL)
+            return(DestroyKernelInfo(kernel));
+
+          for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+            for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+              kernel->positive_range += ( kernel->values[i] =
+                  args->sigma*(labs((long) u)+labs((long) v)) );
+          kernel->maximum = kernel->values[0];
+          break;
+        }
+      case OctagonalKernel:
+      {
+        if (args->rho < 2.0)
+          kernel->width = kernel->height = 5;  /* default/minimum radius = 2 */
+        else
+          kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+        kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+          for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+            {
+              double
+                r1 = MagickMax(fabs((double)u),fabs((double)v)),
+                r2 = floor((double)(labs((long)u)+labs((long)v)+1)/1.5);
+              kernel->positive_range += kernel->values[i] =
+                        args->sigma*MagickMax(r1,r2);
+            }
+        kernel->maximum = kernel->values[0];
+        break;
+      }
+    case EuclideanKernel:
+      {
+        if (args->rho < 1.0)
+          kernel->width = kernel->height = 3;  /* default radius = 1 */
+        else
+          kernel->width = kernel->height = ((size_t)args->rho)*2+1;
+        kernel->x = kernel->y = (ssize_t) (kernel->width-1)/2;
+
+        kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+                              kernel->height*sizeof(double));
+        if (kernel->values == (double *) NULL)
+          return(DestroyKernelInfo(kernel));
+
+        for ( i=0, v=-kernel->y; v <= (ssize_t)kernel->y; v++)
+          for ( u=-kernel->x; u <= (ssize_t)kernel->x; u++, i++)
+            kernel->positive_range += ( kernel->values[i] =
+                 args->sigma*sqrt((double)(u*u+v*v)) );
+        kernel->maximum = kernel->values[0];
+        break;
+      }
+    default:
+      {
+        /* No-Op Kernel - Basically just a single pixel on its own */
+        kernel=ParseKernelArray("1:1");
+        if (kernel == (KernelInfo *) NULL)
+          return(kernel);
+        kernel->type = UndefinedKernel;
+        break;
+      }
+      break;
+  }
+  return(kernel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C l o n e K e r n e l I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneKernelInfo() creates a new clone of the given Kernel List so that its
+%  can be modified without effecting the original.  The cloned kernel should
+%  be destroyed using DestoryKernelInfo() when no longer needed.
+%
+%  The format of the CloneKernelInfo method is:
+%
+%      KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel to be cloned
+%
+*/
+MagickExport KernelInfo *CloneKernelInfo(const KernelInfo *kernel)
+{
+  register ssize_t
+    i;
+
+  KernelInfo
+    *new_kernel;
+
+  assert(kernel != (KernelInfo *) NULL);
+  new_kernel=(KernelInfo *) AcquireMagickMemory(sizeof(*kernel));
+  if (new_kernel == (KernelInfo *) NULL)
+    return(new_kernel);
+  *new_kernel=(*kernel); /* copy values in structure */
+
+  /* replace the values with a copy of the values */
+  new_kernel->values=(double *) AcquireQuantumMemory(kernel->width,
+    kernel->height*sizeof(double));
+  if (new_kernel->values == (double *) NULL)
+    return(DestroyKernelInfo(new_kernel));
+  for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
+    new_kernel->values[i]=kernel->values[i];
+
+  /* Also clone the next kernel in the kernel list */
+  if ( kernel->next != (KernelInfo *) NULL ) {
+    new_kernel->next = CloneKernelInfo(kernel->next);
+    if ( new_kernel->next == (KernelInfo *) NULL )
+      return(DestroyKernelInfo(new_kernel));
+  }
+
+  return(new_kernel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D e s t r o y K e r n e l I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyKernelInfo() frees the memory used by a Convolution/Morphology
+%  kernel.
+%
+%  The format of the DestroyKernelInfo method is:
+%
+%      KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel to be destroyed
+%
+*/
+MagickExport KernelInfo *DestroyKernelInfo(KernelInfo *kernel)
+{
+  assert(kernel != (KernelInfo *) NULL);
+
+  if ( kernel->next != (KernelInfo *) NULL )
+    kernel->next = DestroyKernelInfo(kernel->next);
+
+  kernel->values = (double *)RelinquishMagickMemory(kernel->values);
+  kernel = (KernelInfo *) RelinquishMagickMemory(kernel);
+  return(kernel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     E x p a n d M i r r o r K e r n e l I n f o                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExpandMirrorKernelInfo() takes a single kernel, and expands it into a
+%  sequence of 90-degree rotated kernels but providing a reflected 180
+%  rotatation, before the -/+ 90-degree rotations.
+%
+%  This special rotation order produces a better, more symetrical thinning of
+%  objects.
+%
+%  The format of the ExpandMirrorKernelInfo method is:
+%
+%      void ExpandMirrorKernelInfo(KernelInfo *kernel)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+% This function is only internel to this module, as it is not finalized,
+% especially with regard to non-orthogonal angles, and rotation of larger
+% 2D kernels.
+*/
+
+#if 0
+static void FlopKernelInfo(KernelInfo *kernel)
+    { /* Do a Flop by reversing each row. */
+      size_t
+        y;
+      register ssize_t
+        x,r;
+      register double
+        *k,t;
+
+      for ( y=0, k=kernel->values; y < kernel->height; y++, k+=kernel->width)
+        for ( x=0, r=kernel->width-1; x<kernel->width/2; x++, r--)
+          t=k[x],  k[x]=k[r],  k[r]=t;
+
+      kernel->x = kernel->width - kernel->x - 1;
+      angle = fmod(angle+180.0, 360.0);
+    }
+#endif
+
+static void ExpandMirrorKernelInfo(KernelInfo *kernel)
+{
+  KernelInfo
+    *clone,
+    *last;
+
+  last = kernel;
+
+  clone = CloneKernelInfo(last);
+  RotateKernelInfo(clone, 180);   /* flip */
+  LastKernelInfo(last)->next = clone;
+  last = clone;
+
+  clone = CloneKernelInfo(last);
+  RotateKernelInfo(clone, 90);   /* transpose */
+  LastKernelInfo(last)->next = clone;
+  last = clone;
+
+  clone = CloneKernelInfo(last);
+  RotateKernelInfo(clone, 180);  /* flop */
+  LastKernelInfo(last)->next = clone;
+
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     E x p a n d R o t a t e K e r n e l I n f o                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExpandRotateKernelInfo() takes a kernel list, and expands it by rotating
+%  incrementally by the angle given, until the kernel repeats.
+%
+%  WARNING: 45 degree rotations only works for 3x3 kernels.
+%  While 90 degree roatations only works for linear and square kernels
+%
+%  The format of the ExpandRotateKernelInfo method is:
+%
+%      void ExpandRotateKernelInfo(KernelInfo *kernel, double angle)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+%    o angle: angle to rotate in degrees
+%
+% This function is only internel to this module, as it is not finalized,
+% especially with regard to non-orthogonal angles, and rotation of larger
+% 2D kernels.
+*/
+
+/* Internal Routine - Return true if two kernels are the same */
+static MagickBooleanType SameKernelInfo(const KernelInfo *kernel1,
+     const KernelInfo *kernel2)
+{
+  register size_t
+    i;
+
+  /* check size and origin location */
+  if (    kernel1->width != kernel2->width
+       || kernel1->height != kernel2->height
+       || kernel1->x != kernel2->x
+       || kernel1->y != kernel2->y )
+    return MagickFalse;
+
+  /* check actual kernel values */
+  for (i=0; i < (kernel1->width*kernel1->height); i++) {
+    /* Test for Nan equivalence */
+    if ( IsNan(kernel1->values[i]) && !IsNan(kernel2->values[i]) )
+      return MagickFalse;
+    if ( IsNan(kernel2->values[i]) && !IsNan(kernel1->values[i]) )
+      return MagickFalse;
+    /* Test actual values are equivalent */
+    if ( fabs(kernel1->values[i] - kernel2->values[i]) > MagickEpsilon )
+      return MagickFalse;
+  }
+
+  return MagickTrue;
+}
+
+static void ExpandRotateKernelInfo(KernelInfo *kernel, const double angle)
+{
+  KernelInfo
+    *clone,
+    *last;
+
+  last = kernel;
+  while(1) {
+    clone = CloneKernelInfo(last);
+    RotateKernelInfo(clone, angle);
+    if ( SameKernelInfo(kernel, clone) == MagickTrue )
+      break;
+    LastKernelInfo(last)->next = clone;
+    last = clone;
+  }
+  clone = DestroyKernelInfo(clone); /* kernel has repeated - junk the clone */
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     C a l c M e t a K e r n a l I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CalcKernelMetaData() recalculate the KernelInfo meta-data of this kernel only,
+%  using the kernel values.  This should only ne used if it is not possible to
+%  calculate that meta-data in some easier way.
+%
+%  It is important that the meta-data is correct before ScaleKernelInfo() is
+%  used to perform kernel normalization.
+%
+%  The format of the CalcKernelMetaData method is:
+%
+%      void CalcKernelMetaData(KernelInfo *kernel, const double scale )
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel to modify
+%
+%  WARNING: Minimum and Maximum values are assumed to include zero, even if
+%  zero is not part of the kernel (as in Gaussian Derived kernels). This
+%  however is not true for flat-shaped morphological kernels.
+%
+%  WARNING: Only the specific kernel pointed to is modified, not a list of
+%  multiple kernels.
+%
+% This is an internal function and not expected to be useful outside this
+% module.  This could change however.
+*/
+static void CalcKernelMetaData(KernelInfo *kernel)
+{
+  register size_t
+    i;
+
+  kernel->minimum = kernel->maximum = 0.0;
+  kernel->negative_range = kernel->positive_range = 0.0;
+  for (i=0; i < (kernel->width*kernel->height); i++)
+    {
+      if ( fabs(kernel->values[i]) < MagickEpsilon )
+        kernel->values[i] = 0.0;
+      ( kernel->values[i] < 0)
+          ?  ( kernel->negative_range += kernel->values[i] )
+          :  ( kernel->positive_range += kernel->values[i] );
+      Minimize(kernel->minimum, kernel->values[i]);
+      Maximize(kernel->maximum, kernel->values[i]);
+    }
+
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M o r p h o l o g y A p p l y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MorphologyApply() applies a morphological method, multiple times using
+%  a list of multiple kernels.
+%
+%  It is basically equivalent to as MorphologyImageChannel() (see below) but
+%  without any user controls.  This allows internel programs to use this
+%  function, to actually perform a specific task without possible interference
+%  by any API user supplied settings.
+%
+%  It is MorphologyImageChannel() task to extract any such user controls, and
+%  pass them to this function for processing.
+%
+%  More specifically kernels are not normalized/scaled/blended by the
+%  'convolve:scale' Image Artifact (setting), nor is the convolve bias
+%  (-bias setting or image->bias) loooked at, but must be supplied from the
+%  function arguments.
+%
+%  The format of the MorphologyApply method is:
+%
+%      Image *MorphologyApply(const Image *image,MorphologyMethod method,
+%        const ChannelType channel, const ssize_t iterations,
+%        const KernelInfo *kernel, const CompositeMethod compose,
+%        const double bias, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the source image
+%
+%    o method: the morphology method to be applied.
+%
+%    o channel: the channels to which the operations are applied
+%               The channel 'sync' flag determines if 'alpha weighting' is
+%               applied for convolution style operations.
+%
+%    o iterations: apply the operation this many times (or no change).
+%                  A value of -1 means loop until no change found.
+%                  How this is applied may depend on the morphology method.
+%                  Typically this is a value of 1.
+%
+%    o channel: the channel type.
+%
+%    o kernel: An array of double representing the morphology kernel.
+%
+%    o compose: How to handle or merge multi-kernel results.
+%          If 'UndefinedCompositeOp' use default for the Morphology method.
+%          If 'NoCompositeOp' force image to be re-iterated by each kernel.
+%          Otherwise merge the results using the compose method given.
+%
+%    o bias: Convolution Output Bias.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+/* Apply a Morphology Primative to an image using the given kernel.
+** Two pre-created images must be provided, and no image is created.
+** It returns the number of pixels that changed between the images
+** for result convergence determination.
+*/
+static ssize_t MorphologyPrimitive(const Image *image, Image *morphology_image,
+     const MorphologyMethod method, const ChannelType channel,
+     const KernelInfo *kernel,const double bias,ExceptionInfo *exception)
+{
+#define MorphologyTag  "Morphology/Image"
+
+  CacheView
+    *image_view,
+    *morphology_view;
+
+  ssize_t
+    y, offx, offy;
+
+  size_t
+    virt_width,
+    changed;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(morphology_image != (Image *) NULL);
+  assert(morphology_image->signature == MagickSignature);
+  assert(kernel != (KernelInfo *) NULL);
+  assert(kernel->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  status=MagickTrue;
+  changed=0;
+  progress=0;
+
+  image_view=AcquireCacheView(image);
+  morphology_view=AcquireCacheView(morphology_image);
+  virt_width=image->columns+kernel->width-1;
+
+  /* Some methods (including convolve) needs use a reflected kernel.
+   * Adjust 'origin' offsets to loop though kernel as a reflection.
+   */
+  offx = kernel->x;
+  offy = kernel->y;
+  switch(method) {
+    case ConvolveMorphology:
+    case DilateMorphology:
+    case DilateIntensityMorphology:
+    /*case DistanceMorphology:*/
+      /* kernel needs to used with reflection about origin */
+      offx = (ssize_t) kernel->width-offx-1;
+      offy = (ssize_t) kernel->height-offy-1;
+      break;
+    case ErodeMorphology:
+    case ErodeIntensityMorphology:
+    case HitAndMissMorphology:
+    case ThinningMorphology:
+    case ThickenMorphology:
+      /* kernel is used as is, without reflection */
+      break;
+    default:
+      assert("Not a Primitive Morphology Method" != (char *) NULL);
+      break;
+  }
+
+
+  if ( method == ConvolveMorphology && kernel->width == 1 )
+  { /* Special handling (for speed) of vertical (blur) kernels.
+    ** This performs its handling in columns rather than in rows.
+    ** This is only done for convolve as it is the only method that
+    ** generates very large 1-D vertical kernels (such as a 'BlurKernel')
+    **
+    ** Timing tests (on single CPU laptop)
+    ** Using a vertical 1-d Blue with normal row-by-row (below)
+    **   time convert logo: -morphology Convolve Blur:0x10+90 null:
+    **      0.807u
+    ** Using this column method
+    **   time convert logo: -morphology Convolve Blur:0x10+90 null:
+    **      0.620u
+    **
+    ** Anthony Thyssen, 14 June 2010
+    */
+    register ssize_t
+      x;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      register const Quantum
+        *restrict p;
+
+      register Quantum
+        *restrict q;
+
+      register ssize_t
+        y;
+
+      ssize_t
+        r;
+
+      if (status == MagickFalse)
+        continue;
+      p=GetCacheViewVirtualPixels(image_view, x,  -offy,1,
+          image->rows+kernel->height-1, exception);
+      q=GetCacheViewAuthenticPixels(morphology_view,x,0,1,morphology_image->rows,exception);
+      if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+        {
+          status=MagickFalse;
+          continue;
+        }
+      /* offset to origin in 'p'. while 'q' points to it directly */
+      r = offy;
+
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        register ssize_t
+          v;
+
+        register const double
+          *restrict k;
+
+        register const Quantum
+          *restrict k_pixels;
+
+        PixelInfo
+          result;
+
+        /* Copy input image to the output image for unused channels
+        * This removes need for 'cloning' a new image every iteration
+        */
+        SetPixelRed(morphology_image,GetPixelRed(image,p+r*
+          GetPixelChannels(image)),q);
+        SetPixelGreen(morphology_image,GetPixelGreen(image,p+r*
+          GetPixelChannels(image)),q);
+        SetPixelBlue(morphology_image,GetPixelBlue(image,p+r*
+          GetPixelChannels(image)),q);
+        if (image->colorspace == CMYKColorspace)
+          SetPixelBlack(morphology_image,GetPixelBlack(image,p+r*
+            GetPixelChannels(image)),q);
+
+        /* Set the bias of the weighted average output */
+        result.red     =
+        result.green   =
+        result.blue    =
+        result.alpha =
+        result.black   = bias;
+
+
+        /* Weighted Average of pixels using reflected kernel
+        **
+        ** NOTE for correct working of this operation for asymetrical
+        ** kernels, the kernel needs to be applied in its reflected form.
+        ** That is its values needs to be reversed.
+        */
+        k = &kernel->values[ kernel->height-1 ];
+        k_pixels = p;
+        if ( ((channel & SyncChannels) == 0 ) ||
+                             (image->matte == MagickFalse) )
+          { /* No 'Sync' involved.
+            ** Convolution is simple greyscale channel operation
+            */
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              if ( IsNan(*k) ) continue;
+              result.red     += (*k)*GetPixelRed(image,k_pixels);
+              result.green   += (*k)*GetPixelGreen(image,k_pixels);
+              result.blue    += (*k)*GetPixelBlue(image,k_pixels);
+              if (image->colorspace == CMYKColorspace)
+                result.black+=(*k)*GetPixelBlack(image,k_pixels);
+              result.alpha += (*k)*GetPixelAlpha(image,k_pixels);
+              k--;
+              k_pixels++;
+            }
+            if ((channel & RedChannel) != 0)
+              SetPixelRed(morphology_image,ClampToQuantum(result.red),q);
+            if ((channel & GreenChannel) != 0)
+              SetPixelGreen(morphology_image,ClampToQuantum(result.green),q);
+            if ((channel & BlueChannel) != 0)
+              SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q);
+            if (((channel & BlackChannel) != 0) &&
+                (image->colorspace == CMYKColorspace))
+              SetPixelBlack(morphology_image,ClampToQuantum(result.black),q);
+            if (((channel & OpacityChannel) != 0) &&
+                (image->matte == MagickTrue))
+              SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
+          }
+        else
+          { /* Channel 'Sync' Flag, and Alpha Channel enabled.
+            ** Weight the color channels with Alpha Channel so that
+            ** transparent pixels are not part of the results.
+            */
+            MagickRealType
+              alpha,  /* alpha weighting of colors : kernel*alpha  */
+              gamma;  /* divisor, sum of color weighting values */
+
+            gamma=0.0;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              if ( IsNan(*k) ) continue;
+              alpha=(*k)*(QuantumScale*GetPixelAlpha(image,k_pixels));
+              gamma += alpha;
+              result.red     += alpha*GetPixelRed(image,k_pixels);
+              result.green   += alpha*GetPixelGreen(image,k_pixels);
+              result.blue    += alpha*GetPixelBlue(image,k_pixels);
+              if (image->colorspace == CMYKColorspace)
+                result.black += alpha*GetPixelBlack(image,k_pixels);
+              result.alpha += (*k)*GetPixelAlpha(image,k_pixels);
+              k--;
+              k_pixels++;
+            }
+            /* Sync'ed channels, all channels are modified */
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            SetPixelRed(morphology_image,
+              ClampToQuantum(gamma*result.red),q);
+            SetPixelGreen(morphology_image,
+              ClampToQuantum(gamma*result.green),q);
+            SetPixelBlue(morphology_image,
+              ClampToQuantum(gamma*result.blue),q);
+            if (image->colorspace == CMYKColorspace)
+              SetPixelBlack(morphology_image,
+                ClampToQuantum(gamma*result.black),q);
+            SetPixelAlpha(morphology_image,
+              ClampToQuantum(result.alpha),q);
+          }
+
+        /* Count up changed pixels */
+        if ((GetPixelRed(image,p+r) != GetPixelRed(morphology_image,q))
+            || (GetPixelGreen(image,p+r) != GetPixelGreen(morphology_image,q))
+            || (GetPixelBlue(image,p+r) != GetPixelBlue(morphology_image,q))
+            || (GetPixelAlpha(image,p+r) != GetPixelAlpha(morphology_image,q))
+            || ((image->colorspace == CMYKColorspace) &&
+                (GetPixelBlack(image,p+r) != GetPixelBlack(morphology_image,q))))
+          changed++;  /* The pixel was changed in some way! */
+        p+=GetPixelChannels(image);
+        q+=GetPixelChannels(morphology_image);
+      } /* y */
+      if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
+        status=MagickFalse;
+      if (image->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_MorphologyImage)
+#endif
+          proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+    } /* x */
+    morphology_image->type=image->type;
+    morphology_view=DestroyCacheView(morphology_view);
+    image_view=DestroyCacheView(image_view);
+    return(status ? (ssize_t) changed : 0);
+  }
+
+  /*
+  ** Normal handling of horizontal or rectangular kernels (row by row)
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    size_t
+      r;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view, -offx, y-offy, virt_width,
+         kernel->height,  exception);
+    q=GetCacheViewAuthenticPixels(morphology_view,0,y,morphology_image->columns,1,
+         exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    /* offset to origin in 'p'. while 'q' points to it directly */
+    r = virt_width*offy + offx;
+
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+       ssize_t
+        v;
+
+      register ssize_t
+        u;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict k_pixels;
+
+      PixelInfo
+        result,
+        min,
+        max;
+
+      /* Copy input image to the output image for unused channels
+       * This removes need for 'cloning' a new image every iteration
+       */
+      SetPixelRed(morphology_image,GetPixelRed(image,p+r*
+        GetPixelChannels(image)),q);
+      SetPixelGreen(morphology_image,GetPixelGreen(image,p+r*
+        GetPixelChannels(image)),q);
+      SetPixelBlue(morphology_image,GetPixelBlue(image,p+r*
+        GetPixelChannels(image)),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(morphology_image,GetPixelBlack(image,p+r*
+          GetPixelChannels(image)),q);
+
+      /* Defaults */
+      min.red     =
+      min.green   =
+      min.blue    =
+      min.alpha =
+      min.black   = (MagickRealType) QuantumRange;
+      max.red     =
+      max.green   =
+      max.blue    =
+      max.alpha =
+      max.black   = (MagickRealType) 0;
+      /* default result is the original pixel value */
+      result.red     = (MagickRealType) GetPixelRed(image,p+r);
+      result.green   = (MagickRealType) GetPixelGreen(image,p+r);
+      result.blue    = (MagickRealType) GetPixelBlue(image,p+r);
+      result.black   = 0.0;
+      if (image->colorspace == CMYKColorspace)
+         result.black = (MagickRealType) GetPixelBlack(image,p+r);
+      result.alpha=(MagickRealType) GetPixelAlpha(image,p+r);
+
+      switch (method) {
+        case ConvolveMorphology:
+          /* Set the bias of the weighted average output */
+          result.red     =
+          result.green   =
+          result.blue    =
+          result.alpha =
+          result.black   = bias;
+          break;
+        case DilateIntensityMorphology:
+        case ErodeIntensityMorphology:
+          /* use a boolean flag indicating when first match found */
+          result.red = 0.0;  /* result is not used otherwise */
+          break;
+        default:
+          break;
+      }
+
+      switch ( method ) {
+        case ConvolveMorphology:
+            /* Weighted Average of pixels using reflected kernel
+            **
+            ** NOTE for correct working of this operation for asymetrical
+            ** kernels, the kernel needs to be applied in its reflected form.
+            ** That is its values needs to be reversed.
+            **
+            ** Correlation is actually the same as this but without reflecting
+            ** the kernel, and thus 'lower-level' that Convolution.  However
+            ** as Convolution is the more common method used, and it does not
+            ** really cost us much in terms of processing to use a reflected
+            ** kernel, so it is Convolution that is implemented.
+            **
+            ** Correlation will have its kernel reflected before calling
+            ** this function to do a Convolve.
+            **
+            ** For more details of Correlation vs Convolution see
+            **   http://www.cs.umd.edu/~djacobs/CMSC426/Convolution.pdf
+            */
+            k = &kernel->values[ kernel->width*kernel->height-1 ];
+            k_pixels = p;
+            if ( ((channel & SyncChannels) == 0 ) ||
+                                 (image->matte == MagickFalse) )
+              { /* No 'Sync' involved.
+                ** Convolution is simple greyscale channel operation
+                */
+                for (v=0; v < (ssize_t) kernel->height; v++) {
+                  for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                    if ( IsNan(*k) ) continue;
+                    result.red     += (*k)*
+                      GetPixelRed(image,k_pixels+u*GetPixelChannels(image));
+                    result.green   += (*k)*
+                      GetPixelGreen(image,k_pixels+u*GetPixelChannels(image));
+                    result.blue    += (*k)*
+                      GetPixelBlue(image,k_pixels+u*GetPixelChannels(image));
+                    if (image->colorspace == CMYKColorspace)
+                      result.black += (*k)*
+                        GetPixelBlack(image,k_pixels+u*GetPixelChannels(image));
+                    result.alpha += (*k)*
+                      GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image));
+                  }
+                  k_pixels += virt_width*GetPixelChannels(image);
+                }
+                if ((channel & RedChannel) != 0)
+                  SetPixelRed(morphology_image,ClampToQuantum(result.red),q);
+                if ((channel & GreenChannel) != 0)
+                  SetPixelGreen(morphology_image,ClampToQuantum(result.green),q);
+                if ((channel & BlueChannel) != 0)
+                  SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q);
+                if (((channel & BlackChannel) != 0) &&
+                    (image->colorspace == CMYKColorspace))
+                  SetPixelBlack(morphology_image,ClampToQuantum(result.black),q);
+                if (((channel & OpacityChannel) != 0) &&
+                    (image->matte == MagickTrue))
+                  SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
+              }
+            else
+              { /* Channel 'Sync' Flag, and Alpha Channel enabled.
+                ** Weight the color channels with Alpha Channel so that
+                ** transparent pixels are not part of the results.
+                */
+                MagickRealType
+                  alpha,  /* alpha weighting of colors : kernel*alpha  */
+                  gamma;  /* divisor, sum of color weighting values */
+
+                gamma=0.0;
+                for (v=0; v < (ssize_t) kernel->height; v++) {
+                  for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                    if ( IsNan(*k) ) continue;
+                    alpha=(*k)*(QuantumScale*
+                      GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+                    gamma += alpha;
+                    result.red     += alpha*
+                      GetPixelRed(image,k_pixels+u*GetPixelChannels(image));
+                    result.green   += alpha*
+                      GetPixelGreen(image,k_pixels+u*GetPixelChannels(image));
+                    result.blue    += alpha*
+                      GetPixelBlue(image,k_pixels+u*GetPixelChannels(image));
+                    if (image->colorspace == CMYKColorspace)
+                      result.black+=alpha*
+                        GetPixelBlack(image,k_pixels+u*GetPixelChannels(image));
+                    result.alpha += (*k)*
+                      GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image));
+                  }
+                  k_pixels += virt_width*GetPixelChannels(image);
+                }
+                /* Sync'ed channels, all channels are modified */
+                gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+                SetPixelRed(morphology_image,
+                  ClampToQuantum(gamma*result.red),q);
+                SetPixelGreen(morphology_image,
+                  ClampToQuantum(gamma*result.green),q);
+                SetPixelBlue(morphology_image,
+                  ClampToQuantum(gamma*result.blue),q);
+                if (image->colorspace == CMYKColorspace)
+                  SetPixelBlack(morphology_image,
+                    ClampToQuantum(gamma*result.black),q);
+                SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
+              }
+            break;
+
+        case ErodeMorphology:
+            /* Minimum Value within kernel neighbourhood
+            **
+            ** NOTE that the kernel is not reflected for this operation!
+            **
+            ** NOTE: in normal Greyscale Morphology, the kernel value should
+            ** be added to the real value, this is currently not done, due to
+            ** the nature of the boolean kernels being used.
+            */
+            k = kernel->values;
+            k_pixels = p;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k++) {
+                if ( IsNan(*k) || (*k) < 0.5 ) continue;
+                Minimize(min.red,     (double)
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(min.green,   (double) 
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(min.blue,    (double)
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                if (image->colorspace == CMYKColorspace)
+                  Minimize(min.black,(double)
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(min.alpha,(double)
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            break;
+
+        case DilateMorphology:
+            /* Maximum Value within kernel neighbourhood
+            **
+            ** NOTE for correct working of this operation for asymetrical
+            ** kernels, the kernel needs to be applied in its reflected form.
+            ** That is its values needs to be reversed.
+            **
+            ** NOTE: in normal Greyscale Morphology, the kernel value should
+            ** be added to the real value, this is currently not done, due to
+            ** the nature of the boolean kernels being used.
+            **
+            */
+            k = &kernel->values[ kernel->width*kernel->height-1 ];
+            k_pixels = p;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) || (*k) < 0.5 ) continue;
+                Maximize(max.red,     (double)
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Maximize(max.green,   (double) 
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Maximize(max.blue,    (double) 
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                if (image->colorspace == CMYKColorspace)
+                  Maximize(max.black,   (double)
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                Maximize(max.alpha,(double) 
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            break;
+
+        case HitAndMissMorphology:
+        case ThinningMorphology:
+        case ThickenMorphology:
+            /* Minimum of Foreground Pixel minus Maxumum of Background Pixels
+            **
+            ** NOTE that the kernel is not reflected for this operation,
+            ** and consists of both foreground and background pixel
+            ** neighbourhoods, 0.0 for background, and 1.0 for foreground
+            ** with either Nan or 0.5 values for don't care.
+            **
+            ** Note that this will never produce a meaningless negative
+            ** result.  Such results can cause Thinning/Thicken to not work
+            ** correctly when used against a greyscale image.
+            */
+            k = kernel->values;
+            k_pixels = p;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k++) {
+                if ( IsNan(*k) ) continue;
+                if ( (*k) > 0.7 )
+                { /* minimim of foreground pixels */
+                  Minimize(min.red,     (double)
+                    GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                  Minimize(min.green,   (double)
+                    GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                  Minimize(min.blue,    (double)
+                    GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                  if ( image->colorspace == CMYKColorspace)
+                    Minimize(min.black,(double)
+                      GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                  Minimize(min.alpha,(double)
+                    GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+                }
+                else if ( (*k) < 0.3 )
+                { /* maximum of background pixels */
+                  Maximize(max.red,     (double)
+                    GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                  Maximize(max.green,   (double)
+                    GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                  Maximize(max.blue,    (double)
+                    GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                  if (image->colorspace == CMYKColorspace)
+                    Maximize(max.black,   (double)
+                      GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                  Maximize(max.alpha,(double)
+                    GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+                }
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            /* Pattern Match if difference is positive */
+            min.red     -= max.red;     Maximize( min.red,     0.0 );
+            min.green   -= max.green;   Maximize( min.green,   0.0 );
+            min.blue    -= max.blue;    Maximize( min.blue,    0.0 );
+            min.alpha -= max.alpha; Maximize( min.alpha, 0.0 );
+            min.black   -= max.black;   Maximize( min.black,   0.0 );
+            break;
+
+        case ErodeIntensityMorphology:
+            /* Select Pixel with Minimum Intensity within kernel neighbourhood
+            **
+            ** WARNING: the intensity test fails for CMYK and does not
+            ** take into account the moderating effect of the alpha channel
+            ** on the intensity.
+            **
+            ** NOTE that the kernel is not reflected for this operation!
+            */
+            k = kernel->values;
+            k_pixels = p;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k++) {
+                if ( IsNan(*k) || (*k) < 0.5 ) continue;
+                if ( result.red == 0.0 ||
+                     GetPixelIntensity(image,&(k_pixels[u])) < GetPixelIntensity(morphology_image,q) ) {
+                  /* copy the whole pixel - no channel selection */
+                  *q = k_pixels[u];
+                  if ( result.red > 0.0 ) changed++;
+                  result.red = 1.0;
+                }
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            break;
+
+        case DilateIntensityMorphology:
+            /* Select Pixel with Maximum Intensity within kernel neighbourhood
+            **
+            ** WARNING: the intensity test fails for CMYK and does not
+            ** take into account the moderating effect of the alpha channel
+            ** on the intensity (yet).
+            **
+            ** NOTE for correct working of this operation for asymetrical
+            ** kernels, the kernel needs to be applied in its reflected form.
+            ** That is its values needs to be reversed.
+            */
+            k = &kernel->values[ kernel->width*kernel->height-1 ];
+            k_pixels = p;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) || (*k) < 0.5 ) continue; /* boolean kernel */
+                if ( result.red == 0.0 ||
+                     GetPixelIntensity(image,&(k_pixels[u])) > GetPixelIntensity(morphology_image,q) ) {
+                  /* copy the whole pixel - no channel selection */
+                  *q = k_pixels[u];
+                  if ( result.red > 0.0 ) changed++;
+                  result.red = 1.0;
+                }
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            break;
+#if 0
+  This code has been obsoleted by the MorphologyPrimitiveDirect() function.
+  However it is still (almost) correct coding for Grayscale Morphology.
+  That is...
+
+  GrayErode    is equivalent but with kernel values subtracted from pixels
+               without the kernel rotation
+  GreyDilate   is equivalent but using Maximum() instead of Minimum()
+               useing kernel rotation
+
+        case DistanceMorphology:
+            /* Add kernel Value and select the minimum value found.
+            ** The result is a iterative distance from edge of image shape.
+            **
+            ** All Distance Kernels are symetrical, but that may not always
+            ** be the case. For example how about a distance from left edges?
+            ** To work correctly with asymetrical kernels the reflected kernel
+            ** needs to be applied.
+            */
+            k = &kernel->values[ kernel->width*kernel->height-1 ];
+            k_pixels = p;
+            for (v=0; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) ) continue;
+                Minimize(result.red,     (*k)+k_pixels[u].red);
+                Minimize(result.green,   (*k)+k_pixels[u].green);
+                Minimize(result.blue,    (*k)+k_pixels[u].blue);
+                Minimize(result.alpha, (*k)+k_pixels[u].alpha);
+                if ( image->colorspace == CMYKColorspace)
+                  Minimize(result.black,(*k)+GetPixelBlack(p_image,k_indexes+u));
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            break;
+#endif
+        case UndefinedMorphology:
+        default:
+            break; /* Do nothing */
+      }
+      /* Final mathematics of results (combine with original image?)
+      **
+      ** NOTE: Difference Morphology operators Edge* and *Hat could also
+      ** be done here but works better with iteration as a image difference
+      ** in the controling function (below).  Thicken and Thinning however
+      ** should be done here so thay can be iterated correctly.
+      */
+      switch ( method ) {
+        case HitAndMissMorphology:
+        case ErodeMorphology:
+          result = min;    /* minimum of neighbourhood */
+          break;
+        case DilateMorphology:
+          result = max;    /* maximum of neighbourhood */
+          break;
+        case ThinningMorphology:
+          /* subtract pattern match from original */
+          result.red     -= min.red;
+          result.green   -= min.green;
+          result.blue    -= min.blue;
+          result.alpha -= min.alpha;
+          result.black   -= min.black;
+          break;
+        case ThickenMorphology:
+          /* Add the pattern matchs to the original */
+          result.red     += min.red;
+          result.green   += min.green;
+          result.blue    += min.blue;
+          result.alpha += min.alpha;
+          result.black   += min.black;
+          break;
+        default:
+          /* result directly calculated or assigned */
+          break;
+      }
+      /* Assign the resulting pixel values - Clamping Result */
+      switch ( method ) {
+        case UndefinedMorphology:
+        case ConvolveMorphology:
+        case DilateIntensityMorphology:
+        case ErodeIntensityMorphology:
+          break;  /* full pixel was directly assigned - not a channel method */
+        default:
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(morphology_image,ClampToQuantum(result.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(morphology_image,ClampToQuantum(result.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(morphology_image,ClampToQuantum(result.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(morphology_image,ClampToQuantum(result.black),q);
+          if (((channel & OpacityChannel) != 0) &&
+              (image->matte == MagickTrue))
+            SetPixelAlpha(morphology_image,ClampToQuantum(result.alpha),q);
+          break;
+      }
+      /* Count up changed pixels */
+      if ((GetPixelRed(image,p+r) != GetPixelRed(morphology_image,q)) ||
+          (GetPixelGreen(image,p+r) != GetPixelGreen(morphology_image,q)) ||
+          (GetPixelBlue(image,p+r) != GetPixelBlue(morphology_image,q)) ||
+          (GetPixelAlpha(image,p+r) != GetPixelAlpha(morphology_image,q)) ||
+          ((image->colorspace == CMYKColorspace) &&
+           (GetPixelBlack(image,p+r) != GetPixelBlack(morphology_image,q))))
+        changed++;  /* The pixel was changed in some way! */
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(morphology_image);
+    } /* x */
+    if ( SyncCacheViewAuthenticPixels(morphology_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_MorphologyImage)
+#endif
+        proceed=SetImageProgress(image,MorphologyTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  } /* y */
+  morphology_view=DestroyCacheView(morphology_view);
+  image_view=DestroyCacheView(image_view);
+  return(status ? (ssize_t)changed : -1);
+}
+
+/* This is almost identical to the MorphologyPrimative() function above,
+** but will apply the primitive directly to the image in two passes.
+**
+** That is after each row is 'Sync'ed' into the image, the next row will
+** make use of those values as part of the calculation of the next row.
+** It then repeats, but going in the oppisite (bottom-up) direction.
+**
+** Because of this 'iterative' handling this function can not make use
+** of multi-threaded, parellel processing.
+*/
+static ssize_t MorphologyPrimitiveDirect(Image *image,
+     const MorphologyMethod method, const ChannelType channel,
+     const KernelInfo *kernel,ExceptionInfo *exception)
+{
+  CacheView
+    *auth_view,
+    *virt_view;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y, offx, offy;
+
+  size_t
+    virt_width,
+    changed;
+
+  status=MagickTrue;
+  changed=0;
+  progress=0;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(kernel != (KernelInfo *) NULL);
+  assert(kernel->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  /* Some methods (including convolve) needs use a reflected kernel.
+   * Adjust 'origin' offsets to loop though kernel as a reflection.
+   */
+  offx = kernel->x;
+  offy = kernel->y;
+  switch(method) {
+    case DistanceMorphology:
+    case VoronoiMorphology:
+      /* kernel needs to used with reflection about origin */
+      offx = (ssize_t) kernel->width-offx-1;
+      offy = (ssize_t) kernel->height-offy-1;
+      break;
+#if 0
+    case ?????Morphology:
+      /* kernel is used as is, without reflection */
+      break;
+#endif
+    default:
+      assert("Not a PrimativeDirect Morphology Method" != (char *) NULL);
+      break;
+  }
+
+  /* DO NOT THREAD THIS CODE! */
+  /* two views into same image (virtual, and actual) */
+  virt_view=AcquireCacheView(image);
+  auth_view=AcquireCacheView(image);
+  virt_width=image->columns+kernel->width-1;
+
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    ssize_t
+      r;
+
+    /* NOTE read virtual pixels, and authentic pixels, from the same image!
+    ** we read using virtual to get virtual pixel handling, but write back
+    ** into the same image.
+    **
+    ** Only top half of kernel is processed as we do a single pass downward
+    ** through the image iterating the distance function as we go.
+    */
+    if (status == MagickFalse)
+      break;
+    p=GetCacheViewVirtualPixels(virt_view,-offx,y-offy,virt_width,(size_t)
+      offy+1,exception);
+    q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+
+    /* offset to origin in 'p'. while 'q' points to it directly */
+    r = (ssize_t) virt_width*offy + offx;
+
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      ssize_t
+        v;
+
+      register ssize_t
+        u;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict k_pixels;
+
+      PixelInfo
+        result;
+
+      /* Starting Defaults */
+      GetPixelInfo(image,&result);
+      SetPixelInfo(image,q,&result);
+      if ( method != VoronoiMorphology )
+        result.alpha = QuantumRange - result.alpha;
+
+      switch ( method ) {
+        case DistanceMorphology:
+            /* Add kernel Value and select the minimum value found. */
+            k = &kernel->values[ kernel->width*kernel->height-1 ];
+            k_pixels = p;
+            for (v=0; v <= (ssize_t) offy; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) ) continue;
+                Minimize(result.red,     (*k)+
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.green,   (*k)+
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.blue,    (*k)+
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                if (image->colorspace == CMYKColorspace)
+                  Minimize(result.black,(*k)+
+                    GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.alpha, (*k)+
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            /* repeat with the just processed pixels of this row */
+            k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
+            k_pixels = q-offx;
+              for (u=0; u < (ssize_t) offx; u++, k--) {
+                if ( x+u-offx < 0 ) continue;  /* off the edge! */
+                if ( IsNan(*k) ) continue;
+                Minimize(result.red,     (*k)+
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.green,   (*k)+
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.blue,    (*k)+
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                if (image->colorspace == CMYKColorspace)
+                  Minimize(result.black,(*k)+
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.alpha,(*k)+
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+              }
+            break;
+        case VoronoiMorphology:
+            /* Apply Distance to 'Matte' channel, coping the closest color.
+            **
+            ** This is experimental, and realy the 'alpha' component should
+            ** be completely separate 'masking' channel.
+            */
+            k = &kernel->values[ kernel->width*kernel->height-1 ];
+            k_pixels = p;
+            for (v=0; v <= (ssize_t) offy; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) ) continue;
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
+                  {
+                    SetPixelInfo(image,k_pixels+u*GetPixelChannels(image),
+                      &result);
+                    result.alpha += *k;
+                  }
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            /* repeat with the just processed pixels of this row */
+            k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
+            k_pixels = q-offx;
+              for (u=0; u < (ssize_t) offx; u++, k--) {
+                if ( x+u-offx < 0 ) continue;  /* off the edge! */
+                if ( IsNan(*k) ) continue;
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
+                  {
+                    SetPixelInfo(image,k_pixels+u*GetPixelChannels(image),
+                      &result);
+                    result.alpha += *k;
+                  }
+              }
+            break;
+        default:
+          /* result directly calculated or assigned */
+          break;
+      }
+      /* Assign the resulting pixel values - Clamping Result */
+      switch ( method ) {
+        case VoronoiMorphology:
+          SetPixelPixelInfo(image,&result,q);
+          break;
+        default:
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(image,ClampToQuantum(result.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(image,ClampToQuantum(result.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(image,ClampToQuantum(result.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(image,ClampToQuantum(result.black),q);
+          if ((channel & OpacityChannel) != 0 && image->matte == MagickTrue )
+            SetPixelAlpha(image,ClampToQuantum(result.alpha),q);
+          break;
+      }
+      /* Count up changed pixels */
+      if ((GetPixelRed(image,p+r) != GetPixelRed(image,q)) ||
+          (GetPixelGreen(image,p+r) != GetPixelGreen(image,q)) ||
+          (GetPixelBlue(image,p+r) != GetPixelBlue(image,q)) ||
+          (GetPixelAlpha(image,p+r) != GetPixelAlpha(image,q)) ||
+          ((image->colorspace == CMYKColorspace) &&
+           (GetPixelBlack(image,p+r) != GetPixelBlack(image,q))))
+        changed++;  /* The pixel was changed in some way! */
+
+      p+=GetPixelChannels(image); /* increment pixel buffers */
+      q+=GetPixelChannels(image);
+    } /* x */
+
+    if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      if ( SetImageProgress(image,MorphologyTag,progress++,image->rows)
+                == MagickFalse )
+        status=MagickFalse;
+
+  } /* y */
+
+  /* Do the reversed pass through the image */
+  for (y=(ssize_t)image->rows-1; y >= 0; y--)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    ssize_t
+      r;
+
+    if (status == MagickFalse)
+      break;
+    /* NOTE read virtual pixels, and authentic pixels, from the same image!
+    ** we read using virtual to get virtual pixel handling, but write back
+    ** into the same image.
+    **
+    ** Only the bottom half of the kernel will be processes as we
+    ** up the image.
+    */
+    p=GetCacheViewVirtualPixels(virt_view,-offx,y,virt_width,(size_t)
+      kernel->y+1,exception);
+    q=GetCacheViewAuthenticPixels(auth_view, 0, y, image->columns, 1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      status=MagickFalse;
+    if (status == MagickFalse)
+      break;
+
+    /* adjust positions to end of row */
+    p += image->columns-1;
+    q += image->columns-1;
+
+    /* offset to origin in 'p'. while 'q' points to it directly */
+    r = offx;
+
+    for (x=(ssize_t)image->columns-1; x >= 0; x--)
+    {
+      ssize_t
+        v;
+
+      register ssize_t
+        u;
+
+      register const double
+        *restrict k;
+
+      register const Quantum
+        *restrict k_pixels;
+
+      PixelInfo
+        result;
+
+      /* Default - previously modified pixel */
+      GetPixelInfo(image,&result);
+      SetPixelInfo(image,q,&result);
+      if ( method != VoronoiMorphology )
+        result.alpha = QuantumRange - result.alpha;
+
+      switch ( method ) {
+        case DistanceMorphology:
+            /* Add kernel Value and select the minimum value found. */
+            k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
+            k_pixels = p;
+            for (v=offy; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) ) continue;
+                Minimize(result.red,     (*k)+
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.green,   (*k)+
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.blue,    (*k)+
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                if ( image->colorspace == CMYKColorspace)
+                  Minimize(result.black,(*k)+
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.alpha, (*k)+
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            /* repeat with the just processed pixels of this row */
+            k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ];
+            k_pixels = q-offx;
+              for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) {
+                if ( (x+u-offx) >= (ssize_t)image->columns ) continue;
+                if ( IsNan(*k) ) continue;
+                Minimize(result.red,     (*k)+
+                  GetPixelRed(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.green,   (*k)+
+                  GetPixelGreen(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.blue,    (*k)+
+                  GetPixelBlue(image,k_pixels+u*GetPixelChannels(image)));
+                if ( image->colorspace == CMYKColorspace)
+                  Minimize(result.black,   (*k)+
+                    GetPixelBlack(image,k_pixels+u*GetPixelChannels(image)));
+                Minimize(result.alpha, (*k)+
+                  GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)));
+              }
+            break;
+        case VoronoiMorphology:
+            /* Apply Distance to 'Matte' channel, coping the closest color.
+            **
+            ** This is experimental, and realy the 'alpha' component should
+            ** be completely separate 'masking' channel.
+            */
+            k = &kernel->values[ kernel->width*(kernel->y+1)-1 ];
+            k_pixels = p;
+            for (v=offy; v < (ssize_t) kernel->height; v++) {
+              for (u=0; u < (ssize_t) kernel->width; u++, k--) {
+                if ( IsNan(*k) ) continue;
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
+                  {
+                    SetPixelInfo(image,k_pixels+u*GetPixelChannels(image),
+                      &result);
+                    result.alpha += *k;
+                  }
+              }
+              k_pixels += virt_width*GetPixelChannels(image);
+            }
+            /* repeat with the just processed pixels of this row */
+            k = &kernel->values[ kernel->width*(kernel->y)+kernel->x-1 ];
+            k_pixels = q-offx;
+              for (u=offx+1; u < (ssize_t) kernel->width; u++, k--) {
+                if ( (x+u-offx) >= (ssize_t)image->columns ) continue;
+                if ( IsNan(*k) ) continue;
+                if( result.alpha > (*k)+GetPixelAlpha(image,k_pixels+u*GetPixelChannels(image)) )
+                  {
+                    SetPixelInfo(image,k_pixels+u*GetPixelChannels(image),
+                      &result);
+                    result.alpha += *k;
+                  }
+              }
+            break;
+        default:
+          /* result directly calculated or assigned */
+          break;
+      }
+      /* Assign the resulting pixel values - Clamping Result */
+      switch ( method ) {
+        case VoronoiMorphology:
+          SetPixelPixelInfo(image,&result,q);
+          break;
+        default:
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(image,ClampToQuantum(result.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(image,ClampToQuantum(result.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(image,ClampToQuantum(result.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(image,ClampToQuantum(result.black),q);
+          if ((channel & OpacityChannel) != 0 && image->matte == MagickTrue )
+            SetPixelAlpha(image,ClampToQuantum(result.alpha),q);
+          break;
+      }
+      /* Count up changed pixels */
+      if (   (GetPixelRed(image,p+r) != GetPixelRed(image,q))
+          || (GetPixelGreen(image,p+r) != GetPixelGreen(image,q))
+          || (GetPixelBlue(image,p+r) != GetPixelBlue(image,q))
+          || (GetPixelAlpha(image,p+r) != GetPixelAlpha(image,q))
+          || ((image->colorspace == CMYKColorspace) &&
+              (GetPixelBlack(image,p+r) != GetPixelBlack(image,q))))
+        changed++;  /* The pixel was changed in some way! */
+
+      p--; /* go backward through pixel buffers */
+      q--;
+    } /* x */
+    if ( SyncCacheViewAuthenticPixels(auth_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      if ( SetImageProgress(image,MorphologyTag,progress++,image->rows)
+                == MagickFalse )
+        status=MagickFalse;
+
+  } /* y */
+
+  auth_view=DestroyCacheView(auth_view);
+  virt_view=DestroyCacheView(virt_view);
+  return(status ? (ssize_t) changed : -1);
+}
+
+/* Apply a Morphology by calling theabove low level primitive application
+** functions.  This function handles any iteration loops, composition or
+** re-iteration of results, and compound morphology methods that is based
+** on multiple low-level (staged) morphology methods.
+**
+** Basically this provides the complex grue between the requested morphology
+** method and raw low-level implementation (above).
+*/
+MagickExport Image *MorphologyApply(const Image *image, const ChannelType
+     channel,const MorphologyMethod method, const ssize_t iterations,
+     const KernelInfo *kernel, const CompositeOperator compose,
+     const double bias, ExceptionInfo *exception)
+{
+  CompositeOperator
+    curr_compose;
+
+  Image
+    *curr_image,    /* Image we are working with or iterating */
+    *work_image,    /* secondary image for primitive iteration */
+    *save_image,    /* saved image - for 'edge' method only */
+    *rslt_image;    /* resultant image - after multi-kernel handling */
+
+  KernelInfo
+    *reflected_kernel, /* A reflected copy of the kernel (if needed) */
+    *norm_kernel,      /* the current normal un-reflected kernel */
+    *rflt_kernel,      /* the current reflected kernel (if needed) */
+    *this_kernel;      /* the kernel being applied */
+
+  MorphologyMethod
+    primitive;      /* the current morphology primitive being applied */
+
+  CompositeOperator
+    rslt_compose;   /* multi-kernel compose method for results to use */
+
+  MagickBooleanType
+    special,        /* do we use a direct modify function? */
+    verbose;        /* verbose output of results */
+
+  size_t
+    method_loop,    /* Loop 1: number of compound method iterations (norm 1) */
+    method_limit,   /*         maximum number of compound method iterations */
+    kernel_number,  /* Loop 2: the kernel number being applied */
+    stage_loop,     /* Loop 3: primitive loop for compound morphology */
+    stage_limit,    /*         how many primitives are in this compound */
+    kernel_loop,    /* Loop 4: iterate the kernel over image */
+    kernel_limit,   /*         number of times to iterate kernel */
+    count,          /* total count of primitive steps applied */
+    kernel_changed, /* total count of changed using iterated kernel */
+    method_changed; /* total count of changed over method iteration */
+
+  ssize_t
+    changed;        /* number pixels changed by last primitive operation */
+
+  char
+    v_info[80];
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(kernel != (KernelInfo *) NULL);
+  assert(kernel->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  count = 0;      /* number of low-level morphology primitives performed */
+  if ( iterations == 0 )
+    return((Image *)NULL);   /* null operation - nothing to do! */
+
+  kernel_limit = (size_t) iterations;
+  if ( iterations < 0 )  /* negative interations = infinite (well alomst) */
+     kernel_limit = image->columns>image->rows ? image->columns : image->rows;
+
+  verbose = IsMagickTrue(GetImageArtifact(image,"verbose"));
+
+  /* initialise for cleanup */
+  curr_image = (Image *) image;
+  curr_compose = image->compose;
+  (void) curr_compose;
+  work_image = save_image = rslt_image = (Image *) NULL;
+  reflected_kernel = (KernelInfo *) NULL;
+
+  /* Initialize specific methods
+   * + which loop should use the given iteratations
+   * + how many primitives make up the compound morphology
+   * + multi-kernel compose method to use (by default)
+   */
+  method_limit = 1;       /* just do method once, unless otherwise set */
+  stage_limit = 1;        /* assume method is not a compound */
+  special = MagickFalse;   /* assume it is NOT a direct modify primitive */
+  rslt_compose = compose; /* and we are composing multi-kernels as given */
+  switch( method ) {
+    case SmoothMorphology:  /* 4 primitive compound morphology */
+      stage_limit = 4;
+      break;
+    case OpenMorphology:    /* 2 primitive compound morphology */
+    case OpenIntensityMorphology:
+    case TopHatMorphology:
+    case CloseMorphology:
+    case CloseIntensityMorphology:
+    case BottomHatMorphology:
+    case EdgeMorphology:
+      stage_limit = 2;
+      break;
+    case HitAndMissMorphology:
+      rslt_compose = LightenCompositeOp;  /* Union of multi-kernel results */
+      /* FALL THUR */
+    case ThinningMorphology:
+    case ThickenMorphology:
+      method_limit = kernel_limit;  /* iterate the whole method */
+      kernel_limit = 1;             /* do not do kernel iteration  */
+      break;
+    case DistanceMorphology:
+    case VoronoiMorphology:
+      special = MagickTrue;
+      break;
+    default:
+      break;
+  }
+
+  /* Apply special methods with special requirments
+  ** For example, single run only, or post-processing requirements
+  */
+  if ( special == MagickTrue )
+    {
+      rslt_image=CloneImage(image,0,0,MagickTrue,exception);
+      if (rslt_image == (Image *) NULL)
+        goto error_cleanup;
+      if (SetImageStorageClass(rslt_image,DirectClass) == MagickFalse)
+        {
+          InheritException(exception,&rslt_image->exception);
+          goto error_cleanup;
+        }
+
+      changed = MorphologyPrimitiveDirect(rslt_image, method,
+                      channel, kernel, exception);
+
+      if ( verbose == MagickTrue )
+        (void) (void) FormatLocaleFile(stderr,
+          "%s:%.20g.%.20g #%.20g => Changed %.20g\n",
+          CommandOptionToMnemonic(MagickMorphologyOptions, method),
+          1.0,0.0,1.0, (double) changed);
+
+      if ( changed < 0 )
+        goto error_cleanup;
+
+      if ( method == VoronoiMorphology ) {
+        /* Preserve the alpha channel of input image - but turned off */
+        (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel);
+        (void) CompositeImageChannel(rslt_image, DefaultChannels,
+          CopyOpacityCompositeOp, image, 0, 0);
+        (void) SetImageAlphaChannel(rslt_image, DeactivateAlphaChannel);
+      }
+      goto exit_cleanup;
+    }
+
+  /* Handle user (caller) specified multi-kernel composition method */
+  if ( compose != UndefinedCompositeOp )
+    rslt_compose = compose;  /* override default composition for method */
+  if ( rslt_compose == UndefinedCompositeOp )
+    rslt_compose = NoCompositeOp; /* still not defined! Then re-iterate */
+
+  /* Some methods require a reflected kernel to use with primitives.
+   * Create the reflected kernel for those methods. */
+  switch ( method ) {
+    case CorrelateMorphology:
+    case CloseMorphology:
+    case CloseIntensityMorphology:
+    case BottomHatMorphology:
+    case SmoothMorphology:
+      reflected_kernel = CloneKernelInfo(kernel);
+      if (reflected_kernel == (KernelInfo *) NULL)
+        goto error_cleanup;
+      RotateKernelInfo(reflected_kernel,180);
+      break;
+    default:
+      break;
+  }
+
+  /* Loops around more primitive morpholgy methods
+  **  erose, dilate, open, close, smooth, edge, etc...
+  */
+  /* Loop 1:  iterate the compound method */
+  method_loop = 0;
+  method_changed = 1;
+  while ( method_loop < method_limit && method_changed > 0 ) {
+    method_loop++;
+    method_changed = 0;
+
+    /* Loop 2:  iterate over each kernel in a multi-kernel list */
+    norm_kernel = (KernelInfo *) kernel;
+    this_kernel = (KernelInfo *) kernel;
+    rflt_kernel = reflected_kernel;
+
+    kernel_number = 0;
+    while ( norm_kernel != NULL ) {
+
+      /* Loop 3: Compound Morphology Staging - Select Primative to apply */
+      stage_loop = 0;          /* the compound morphology stage number */
+      while ( stage_loop < stage_limit ) {
+        stage_loop++;   /* The stage of the compound morphology */
+
+        /* Select primitive morphology for this stage of compound method */
+        this_kernel = norm_kernel; /* default use unreflected kernel */
+        primitive = method;        /* Assume method is a primitive */
+        switch( method ) {
+          case ErodeMorphology:      /* just erode */
+          case EdgeInMorphology:     /* erode and image difference */
+            primitive = ErodeMorphology;
+            break;
+          case DilateMorphology:     /* just dilate */
+          case EdgeOutMorphology:    /* dilate and image difference */
+            primitive = DilateMorphology;
+            break;
+          case OpenMorphology:       /* erode then dialate */
+          case TopHatMorphology:     /* open and image difference */
+            primitive = ErodeMorphology;
+            if ( stage_loop == 2 )
+              primitive = DilateMorphology;
+            break;
+          case OpenIntensityMorphology:
+            primitive = ErodeIntensityMorphology;
+            if ( stage_loop == 2 )
+              primitive = DilateIntensityMorphology;
+            break;
+          case CloseMorphology:      /* dilate, then erode */
+          case BottomHatMorphology:  /* close and image difference */
+            this_kernel = rflt_kernel; /* use the reflected kernel */
+            primitive = DilateMorphology;
+            if ( stage_loop == 2 )
+              primitive = ErodeMorphology;
+            break;
+          case CloseIntensityMorphology:
+            this_kernel = rflt_kernel; /* use the reflected kernel */
+            primitive = DilateIntensityMorphology;
+            if ( stage_loop == 2 )
+              primitive = ErodeIntensityMorphology;
+            break;
+          case SmoothMorphology:         /* open, close */
+            switch ( stage_loop ) {
+              case 1: /* start an open method, which starts with Erode */
+                primitive = ErodeMorphology;
+                break;
+              case 2:  /* now Dilate the Erode */
+                primitive = DilateMorphology;
+                break;
+              case 3:  /* Reflect kernel a close */
+                this_kernel = rflt_kernel; /* use the reflected kernel */
+                primitive = DilateMorphology;
+                break;
+              case 4:  /* Finish the Close */
+                this_kernel = rflt_kernel; /* use the reflected kernel */
+                primitive = ErodeMorphology;
+                break;
+            }
+            break;
+          case EdgeMorphology:        /* dilate and erode difference */
+            primitive = DilateMorphology;
+            if ( stage_loop == 2 ) {
+              save_image = curr_image;      /* save the image difference */
+              curr_image = (Image *) image;
+              primitive = ErodeMorphology;
+            }
+            break;
+          case CorrelateMorphology:
+            /* A Correlation is a Convolution with a reflected kernel.
+            ** However a Convolution is a weighted sum using a reflected
+            ** kernel.  It may seem stange to convert a Correlation into a
+            ** Convolution as the Correlation is the simplier method, but
+            ** Convolution is much more commonly used, and it makes sense to
+            ** implement it directly so as to avoid the need to duplicate the
+            ** kernel when it is not required (which is typically the
+            ** default).
+            */
+            this_kernel = rflt_kernel; /* use the reflected kernel */
+            primitive = ConvolveMorphology;
+            break;
+          default:
+            break;
+        }
+        assert( this_kernel != (KernelInfo *) NULL );
+
+        /* Extra information for debugging compound operations */
+        if ( verbose == MagickTrue ) {
+          if ( stage_limit > 1 )
+            (void) FormatLocaleString(v_info,MaxTextExtent,"%s:%.20g.%.20g -> ",
+             CommandOptionToMnemonic(MagickMorphologyOptions,method),(double)
+             method_loop,(double) stage_loop);
+          else if ( primitive != method )
+            (void) FormatLocaleString(v_info, MaxTextExtent, "%s:%.20g -> ",
+              CommandOptionToMnemonic(MagickMorphologyOptions, method),(double)
+              method_loop);
+          else
+            v_info[0] = '\0';
+        }
+
+        /* Loop 4: Iterate the kernel with primitive */
+        kernel_loop = 0;
+        kernel_changed = 0;
+        changed = 1;
+        while ( kernel_loop < kernel_limit && changed > 0 ) {
+          kernel_loop++;     /* the iteration of this kernel */
+
+          /* Create a clone as the destination image, if not yet defined */
+          if ( work_image == (Image *) NULL )
+            {
+              work_image=CloneImage(image,0,0,MagickTrue,exception);
+              if (work_image == (Image *) NULL)
+                goto error_cleanup;
+              if (SetImageStorageClass(work_image,DirectClass) == MagickFalse)
+                {
+                  InheritException(exception,&work_image->exception);
+                  goto error_cleanup;
+                }
+              /* work_image->type=image->type; ??? */
+            }
+
+          /* APPLY THE MORPHOLOGICAL PRIMITIVE (curr -> work) */
+          count++;
+          changed = MorphologyPrimitive(curr_image, work_image, primitive,
+                       channel, this_kernel, bias, exception);
+
+          if ( verbose == MagickTrue ) {
+            if ( kernel_loop > 1 )
+              (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line from previous */
+            (void) (void) FormatLocaleFile(stderr,
+              "%s%s%s:%.20g.%.20g #%.20g => Changed %.20g",
+              v_info,CommandOptionToMnemonic(MagickMorphologyOptions,
+              primitive),(this_kernel == rflt_kernel ) ? "*" : "",
+              (double) (method_loop+kernel_loop-1),(double) kernel_number,
+              (double) count,(double) changed);
+          }
+          if ( changed < 0 )
+            goto error_cleanup;
+          kernel_changed += changed;
+          method_changed += changed;
+
+          /* prepare next loop */
+          { Image *tmp = work_image;   /* swap images for iteration */
+            work_image = curr_image;
+            curr_image = tmp;
+          }
+          if ( work_image == image )
+            work_image = (Image *) NULL; /* replace input 'image' */
+
+        } /* End Loop 4: Iterate the kernel with primitive */
+
+        if ( verbose == MagickTrue && kernel_changed != (size_t)changed )
+          (void) FormatLocaleFile(stderr, "   Total %.20g",(double) kernel_changed);
+        if ( verbose == MagickTrue && stage_loop < stage_limit )
+          (void) FormatLocaleFile(stderr, "\n"); /* add end-of-line before looping */
+
+#if 0
+    (void) FormatLocaleFile(stderr, "--E-- image=0x%lx\n", (unsigned long)image);
+    (void) FormatLocaleFile(stderr, "      curr =0x%lx\n", (unsigned long)curr_image);
+    (void) FormatLocaleFile(stderr, "      work =0x%lx\n", (unsigned long)work_image);
+    (void) FormatLocaleFile(stderr, "      save =0x%lx\n", (unsigned long)save_image);
+    (void) FormatLocaleFile(stderr, "      union=0x%lx\n", (unsigned long)rslt_image);
+#endif
+
+      } /* End Loop 3: Primative (staging) Loop for Coumpound Methods */
+
+      /*  Final Post-processing for some Compound Methods
+      **
+      ** The removal of any 'Sync' channel flag in the Image Compositon
+      ** below ensures the methematical compose method is applied in a
+      ** purely mathematical way, and only to the selected channels.
+      ** Turn off SVG composition 'alpha blending'.
+      */
+      switch( method ) {
+        case EdgeOutMorphology:
+        case EdgeInMorphology:
+        case TopHatMorphology:
+        case BottomHatMorphology:
+          if ( verbose == MagickTrue )
+            (void) FormatLocaleFile(stderr, "\n%s: Difference with original image",
+                 CommandOptionToMnemonic(MagickMorphologyOptions, method) );
+          (void) CompositeImageChannel(curr_image,
+                  (ChannelType) (channel & ~SyncChannels),
+                  DifferenceCompositeOp, image, 0, 0);
+          break;
+        case EdgeMorphology:
+          if ( verbose == MagickTrue )
+            (void) FormatLocaleFile(stderr, "\n%s: Difference of Dilate and Erode",
+                 CommandOptionToMnemonic(MagickMorphologyOptions, method) );
+          (void) CompositeImageChannel(curr_image,
+                  (ChannelType) (channel & ~SyncChannels),
+                  DifferenceCompositeOp, save_image, 0, 0);
+          save_image = DestroyImage(save_image); /* finished with save image */
+          break;
+        default:
+          break;
+      }
+
+      /* multi-kernel handling:  re-iterate, or compose results */
+      if ( kernel->next == (KernelInfo *) NULL )
+        rslt_image = curr_image;   /* just return the resulting image */
+      else if ( rslt_compose == NoCompositeOp )
+        { if ( verbose == MagickTrue ) {
+            if ( this_kernel->next != (KernelInfo *) NULL )
+              (void) FormatLocaleFile(stderr, " (re-iterate)");
+            else
+              (void) FormatLocaleFile(stderr, " (done)");
+          }
+          rslt_image = curr_image; /* return result, and re-iterate */
+        }
+      else if ( rslt_image == (Image *) NULL)
+        { if ( verbose == MagickTrue )
+            (void) FormatLocaleFile(stderr, " (save for compose)");
+          rslt_image = curr_image;
+          curr_image = (Image *) image;  /* continue with original image */
+        }
+      else
+        { /* Add the new 'current' result to the composition
+          **
+          ** The removal of any 'Sync' channel flag in the Image Compositon
+          ** below ensures the methematical compose method is applied in a
+          ** purely mathematical way, and only to the selected channels.
+          ** IE: Turn off SVG composition 'alpha blending'.
+          */
+          if ( verbose == MagickTrue )
+            (void) FormatLocaleFile(stderr, " (compose \"%s\")",
+                 CommandOptionToMnemonic(MagickComposeOptions, rslt_compose) );
+          (void) CompositeImageChannel(rslt_image,
+               (ChannelType) (channel & ~SyncChannels), rslt_compose,
+               curr_image, 0, 0);
+          curr_image = DestroyImage(curr_image);
+          curr_image = (Image *) image;  /* continue with original image */
+        }
+      if ( verbose == MagickTrue )
+        (void) FormatLocaleFile(stderr, "\n");
+
+      /* loop to the next kernel in a multi-kernel list */
+      norm_kernel = norm_kernel->next;
+      if ( rflt_kernel != (KernelInfo *) NULL )
+        rflt_kernel = rflt_kernel->next;
+      kernel_number++;
+    } /* End Loop 2: Loop over each kernel */
+
+  } /* End Loop 1: compound method interation */
+
+  goto exit_cleanup;
+
+  /* Yes goto's are bad, but it makes cleanup lot more efficient */
+error_cleanup:
+  if ( curr_image == rslt_image )
+    curr_image = (Image *) NULL;
+  if ( rslt_image != (Image *) NULL )
+    rslt_image = DestroyImage(rslt_image);
+exit_cleanup:
+  if ( curr_image == rslt_image || curr_image == image )
+    curr_image = (Image *) NULL;
+  if ( curr_image != (Image *) NULL )
+    curr_image = DestroyImage(curr_image);
+  if ( work_image != (Image *) NULL )
+    work_image = DestroyImage(work_image);
+  if ( save_image != (Image *) NULL )
+    save_image = DestroyImage(save_image);
+  if ( reflected_kernel != (KernelInfo *) NULL )
+    reflected_kernel = DestroyKernelInfo(reflected_kernel);
+  return(rslt_image);
+}
+
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     M o r p h o l o g y I m a g e C h a n n e l                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MorphologyImageChannel() applies a user supplied kernel to the image
+%  according to the given mophology method.
+%
+%  This function applies any and all user defined settings before calling
+%  the above internal function MorphologyApply().
+%
+%  User defined settings include...
+%    * Output Bias for Convolution and correlation   ("-bias")
+%    * Kernel Scale/normalize settings     ("-set 'option:convolve:scale'")
+%      This can also includes the addition of a scaled unity kernel.
+%    * Show Kernel being applied           ("-set option:showkernel 1")
+%
+%  The format of the MorphologyImage method is:
+%
+%      Image *MorphologyImage(const Image *image,MorphologyMethod method,
+%        const ssize_t iterations,KernelInfo *kernel,ExceptionInfo *exception)
+%
+%      Image *MorphologyImageChannel(const Image *image, const ChannelType
+%        channel,MorphologyMethod method,const ssize_t iterations,
+%        KernelInfo *kernel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o method: the morphology method to be applied.
+%
+%    o iterations: apply the operation this many times (or no change).
+%                  A value of -1 means loop until no change found.
+%                  How this is applied may depend on the morphology method.
+%                  Typically this is a value of 1.
+%
+%    o channel: the channel type.
+%
+%    o kernel: An array of double representing the morphology kernel.
+%              Warning: kernel may be normalized for the Convolve method.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport Image *MorphologyImageChannel(const Image *image,
+  const ChannelType channel,const MorphologyMethod method,
+  const ssize_t iterations,const KernelInfo *kernel,ExceptionInfo *exception)
+{
+  KernelInfo
+    *curr_kernel;
+
+  CompositeOperator
+    compose;
+
+  Image
+    *morphology_image;
+
+
+  /* Apply Convolve/Correlate Normalization and Scaling Factors.
+   * This is done BEFORE the ShowKernelInfo() function is called so that
+   * users can see the results of the 'option:convolve:scale' option.
+   */
+  curr_kernel = (KernelInfo *) kernel;
+  if ( method == ConvolveMorphology ||  method == CorrelateMorphology )
+    {
+      const char
+        *artifact;
+      artifact = GetImageArtifact(image,"convolve:scale");
+      if ( artifact != (const char *)NULL ) {
+        if ( curr_kernel == kernel )
+          curr_kernel = CloneKernelInfo(kernel);
+        if (curr_kernel == (KernelInfo *) NULL) {
+          curr_kernel=DestroyKernelInfo(curr_kernel);
+          return((Image *) NULL);
+        }
+        ScaleGeometryKernelInfo(curr_kernel, artifact);
+      }
+    }
+
+  /* display the (normalized) kernel via stderr */
+  if ( IsMagickTrue(GetImageArtifact(image,"showkernel"))
+    || IsMagickTrue(GetImageArtifact(image,"convolve:showkernel"))
+    || IsMagickTrue(GetImageArtifact(image,"morphology:showkernel")) )
+    ShowKernelInfo(curr_kernel);
+
+  /* Override the default handling of multi-kernel morphology results
+   * If 'Undefined' use the default method
+   * If 'None' (default for 'Convolve') re-iterate previous result
+   * Otherwise merge resulting images using compose method given.
+   * Default for 'HitAndMiss' is 'Lighten'.
+   */
+  { const char
+      *artifact;
+    artifact = GetImageArtifact(image,"morphology:compose");
+    compose = UndefinedCompositeOp;  /* use default for method */
+    if ( artifact != (const char *) NULL)
+      compose = (CompositeOperator) ParseCommandOption(
+                             MagickComposeOptions,MagickFalse,artifact);
+  }
+  /* Apply the Morphology */
+  morphology_image = MorphologyApply(image, channel, method, iterations,
+                         curr_kernel, compose, image->bias, exception);
+
+  /* Cleanup and Exit */
+  if ( curr_kernel != kernel )
+    curr_kernel=DestroyKernelInfo(curr_kernel);
+  return(morphology_image);
+}
+
+MagickExport Image *MorphologyImage(const Image *image, const MorphologyMethod
+  method, const ssize_t iterations,const KernelInfo *kernel, ExceptionInfo
+  *exception)
+{
+  Image
+    *morphology_image;
+
+  morphology_image=MorphologyImageChannel(image,DefaultChannels,method,
+    iterations,kernel,exception);
+  return(morphology_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     R o t a t e K e r n e l I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RotateKernelInfo() rotates the kernel by the angle given.
+%
+%  Currently it is restricted to 90 degree angles, of either 1D kernels
+%  or square kernels. And 'circular' rotations of 45 degrees for 3x3 kernels.
+%  It will ignore usless rotations for specific 'named' built-in kernels.
+%
+%  The format of the RotateKernelInfo method is:
+%
+%      void RotateKernelInfo(KernelInfo *kernel, double angle)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+%    o angle: angle to rotate in degrees
+%
+% This function is currently internal to this module only, but can be exported
+% to other modules if needed.
+*/
+static void RotateKernelInfo(KernelInfo *kernel, double angle)
+{
+  /* angle the lower kernels first */
+  if ( kernel->next != (KernelInfo *) NULL)
+    RotateKernelInfo(kernel->next, angle);
+
+  /* WARNING: Currently assumes the kernel (rightly) is horizontally symetrical
+  **
+  ** TODO: expand beyond simple 90 degree rotates, flips and flops
+  */
+
+  /* Modulus the angle */
+  angle = fmod(angle, 360.0);
+  if ( angle < 0 )
+    angle += 360.0;
+
+  if ( 337.5 < angle || angle <= 22.5 )
+    return;   /* Near zero angle - no change! - At least not at this time */
+
+  /* Handle special cases */
+  switch (kernel->type) {
+    /* These built-in kernels are cylindrical kernels, rotating is useless */
+    case GaussianKernel:
+    case DoGKernel:
+    case LoGKernel:
+    case DiskKernel:
+    case PeaksKernel:
+    case LaplacianKernel:
+    case ChebyshevKernel:
+    case ManhattanKernel:
+    case EuclideanKernel:
+      return;
+
+    /* These may be rotatable at non-90 angles in the future */
+    /* but simply rotating them in multiples of 90 degrees is useless */
+    case SquareKernel:
+    case DiamondKernel:
+    case PlusKernel:
+    case CrossKernel:
+      return;
+
+    /* These only allows a +/-90 degree rotation (by transpose) */
+    /* A 180 degree rotation is useless */
+    case BlurKernel:
+    case RectangleKernel:
+      if ( 135.0 < angle && angle <= 225.0 )
+        return;
+      if ( 225.0 < angle && angle <= 315.0 )
+        angle -= 180;
+      break;
+
+    default:
+      break;
+  }
+  /* Attempt rotations by 45 degrees */
+  if ( 22.5 < fmod(angle,90.0) && fmod(angle,90.0) <= 67.5 )
+    {
+      if ( kernel->width == 3 && kernel->height == 3 )
+        { /* Rotate a 3x3 square by 45 degree angle */
+          MagickRealType t  = kernel->values[0];
+          kernel->values[0] = kernel->values[3];
+          kernel->values[3] = kernel->values[6];
+          kernel->values[6] = kernel->values[7];
+          kernel->values[7] = kernel->values[8];
+          kernel->values[8] = kernel->values[5];
+          kernel->values[5] = kernel->values[2];
+          kernel->values[2] = kernel->values[1];
+          kernel->values[1] = t;
+          /* rotate non-centered origin */
+          if ( kernel->x != 1 || kernel->y != 1 ) {
+            ssize_t x,y;
+            x = (ssize_t) kernel->x-1;
+            y = (ssize_t) kernel->y-1;
+                 if ( x == y  ) x = 0;
+            else if ( x == 0  ) x = -y;
+            else if ( x == -y ) y = 0;
+            else if ( y == 0  ) y = x;
+            kernel->x = (ssize_t) x+1;
+            kernel->y = (ssize_t) y+1;
+          }
+          angle = fmod(angle+315.0, 360.0);  /* angle reduced 45 degrees */
+          kernel->angle = fmod(kernel->angle+45.0, 360.0);
+        }
+      else
+        perror("Unable to rotate non-3x3 kernel by 45 degrees");
+    }
+  if ( 45.0 < fmod(angle, 180.0)  && fmod(angle,180.0) <= 135.0 )
+    {
+      if ( kernel->width == 1 || kernel->height == 1 )
+        { /* Do a transpose of a 1 dimensional kernel,
+          ** which results in a fast 90 degree rotation of some type.
+          */
+          ssize_t
+            t;
+          t = (ssize_t) kernel->width;
+          kernel->width = kernel->height;
+          kernel->height = (size_t) t;
+          t = kernel->x;
+          kernel->x = kernel->y;
+          kernel->y = t;
+          if ( kernel->width == 1 ) {
+            angle = fmod(angle+270.0, 360.0);     /* angle reduced 90 degrees */
+            kernel->angle = fmod(kernel->angle+90.0, 360.0);
+          } else {
+            angle = fmod(angle+90.0, 360.0);   /* angle increased 90 degrees */
+            kernel->angle = fmod(kernel->angle+270.0, 360.0);
+          }
+        }
+      else if ( kernel->width == kernel->height )
+        { /* Rotate a square array of values by 90 degrees */
+          { register size_t
+              i,j,x,y;
+            register MagickRealType
+              *k,t;
+            k=kernel->values;
+            for( i=0, x=kernel->width-1;  i<=x;   i++, x--)
+              for( j=0, y=kernel->height-1;  j<y;   j++, y--)
+                { t                    = k[i+j*kernel->width];
+                  k[i+j*kernel->width] = k[j+x*kernel->width];
+                  k[j+x*kernel->width] = k[x+y*kernel->width];
+                  k[x+y*kernel->width] = k[y+i*kernel->width];
+                  k[y+i*kernel->width] = t;
+                }
+          }
+          /* rotate the origin - relative to center of array */
+          { register ssize_t x,y;
+            x = (ssize_t) (kernel->x*2-kernel->width+1);
+            y = (ssize_t) (kernel->y*2-kernel->height+1);
+            kernel->x = (ssize_t) ( -y +(ssize_t) kernel->width-1)/2;
+            kernel->y = (ssize_t) ( +x +(ssize_t) kernel->height-1)/2;
+          }
+          angle = fmod(angle+270.0, 360.0);     /* angle reduced 90 degrees */
+          kernel->angle = fmod(kernel->angle+90.0, 360.0);
+        }
+      else
+        perror("Unable to rotate a non-square, non-linear kernel 90 degrees");
+    }
+  if ( 135.0 < angle && angle <= 225.0 )
+    {
+      /* For a 180 degree rotation - also know as a reflection
+       * This is actually a very very common operation!
+       * Basically all that is needed is a reversal of the kernel data!
+       * And a reflection of the origon
+       */
+      size_t
+        i,j;
+      register double
+        *k,t;
+
+      k=kernel->values;
+      for ( i=0, j=kernel->width*kernel->height-1;  i<j;  i++, j--)
+        t=k[i],  k[i]=k[j],  k[j]=t;
+
+      kernel->x = (ssize_t) kernel->width  - kernel->x - 1;
+      kernel->y = (ssize_t) kernel->height - kernel->y - 1;
+      angle = fmod(angle-180.0, 360.0);   /* angle+180 degrees */
+      kernel->angle = fmod(kernel->angle+180.0, 360.0);
+    }
+  /* At this point angle should at least between -45 (315) and +45 degrees
+   * In the future some form of non-orthogonal angled rotates could be
+   * performed here, posibily with a linear kernel restriction.
+   */
+
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S c a l e G e o m e t r y K e r n e l I n f o                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ScaleGeometryKernelInfo() takes a geometry argument string, typically
+%  provided as a  "-set option:convolve:scale {geometry}" user setting,
+%  and modifies the kernel according to the parsed arguments of that setting.
+%
+%  The first argument (and any normalization flags) are passed to
+%  ScaleKernelInfo() to scale/normalize the kernel.  The second argument
+%  is then passed to UnityAddKernelInfo() to add a scled unity kernel
+%  into the scaled/normalized kernel.
+%
+%  The format of the ScaleGeometryKernelInfo method is:
+%
+%      void ScaleGeometryKernelInfo(KernelInfo *kernel,
+%        const double scaling_factor,const MagickStatusType normalize_flags)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel to modify
+%
+%    o geometry:
+%             The geometry string to parse, typically from the user provided
+%             "-set option:convolve:scale {geometry}" setting.
+%
+*/
+MagickExport void ScaleGeometryKernelInfo (KernelInfo *kernel,
+     const char *geometry)
+{
+  GeometryFlags
+    flags;
+  GeometryInfo
+    args;
+
+  SetGeometryInfo(&args);
+  flags = (GeometryFlags) ParseGeometry(geometry, &args);
+
+#if 0
+  /* For Debugging Geometry Input */
+  (void) FormatLocaleFile(stderr, "Geometry = 0x%04X : %lg x %lg %+lg %+lg\n",
+       flags, args.rho, args.sigma, args.xi, args.psi );
+#endif
+
+  if ( (flags & PercentValue) != 0 )      /* Handle Percentage flag*/
+    args.rho *= 0.01,  args.sigma *= 0.01;
+
+  if ( (flags & RhoValue) == 0 )          /* Set Defaults for missing args */
+    args.rho = 1.0;
+  if ( (flags & SigmaValue) == 0 )
+    args.sigma = 0.0;
+
+  /* Scale/Normalize the input kernel */
+  ScaleKernelInfo(kernel, args.rho, flags);
+
+  /* Add Unity Kernel, for blending with original */
+  if ( (flags & SigmaValue) != 0 )
+    UnityAddKernelInfo(kernel, args.sigma);
+
+  return;
+}
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S c a l e K e r n e l I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ScaleKernelInfo() scales the given kernel list by the given amount, with or
+%  without normalization of the sum of the kernel values (as per given flags).
+%
+%  By default (no flags given) the values within the kernel is scaled
+%  directly using given scaling factor without change.
+%
+%  If either of the two 'normalize_flags' are given the kernel will first be
+%  normalized and then further scaled by the scaling factor value given.
+%
+%  Kernel normalization ('normalize_flags' given) is designed to ensure that
+%  any use of the kernel scaling factor with 'Convolve' or 'Correlate'
+%  morphology methods will fall into -1.0 to +1.0 range.  Note that for
+%  non-HDRI versions of IM this may cause images to have any negative results
+%  clipped, unless some 'bias' is used.
+%
+%  More specifically.  Kernels which only contain positive values (such as a
+%  'Gaussian' kernel) will be scaled so that those values sum to +1.0,
+%  ensuring a 0.0 to +1.0 output range for non-HDRI images.
+%
+%  For Kernels that contain some negative values, (such as 'Sharpen' kernels)
+%  the kernel will be scaled by the absolute of the sum of kernel values, so
+%  that it will generally fall within the +/- 1.0 range.
+%
+%  For kernels whose values sum to zero, (such as 'Laplician' kernels) kernel
+%  will be scaled by just the sum of the postive values, so that its output
+%  range will again fall into the  +/- 1.0 range.
+%
+%  For special kernels designed for locating shapes using 'Correlate', (often
+%  only containing +1 and -1 values, representing foreground/brackground
+%  matching) a special normalization method is provided to scale the positive
+%  values separately to those of the negative values, so the kernel will be
+%  forced to become a zero-sum kernel better suited to such searches.
+%
+%  WARNING: Correct normalization of the kernel assumes that the '*_range'
+%  attributes within the kernel structure have been correctly set during the
+%  kernels creation.
+%
+%  NOTE: The values used for 'normalize_flags' have been selected specifically
+%  to match the use of geometry options, so that '!' means NormalizeValue, '^'
+%  means CorrelateNormalizeValue.  All other GeometryFlags values are ignored.
+%
+%  The format of the ScaleKernelInfo method is:
+%
+%      void ScaleKernelInfo(KernelInfo *kernel, const double scaling_factor,
+%               const MagickStatusType normalize_flags )
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+%    o scaling_factor:
+%             multiply all values (after normalization) by this factor if not
+%             zero.  If the kernel is normalized regardless of any flags.
+%
+%    o normalize_flags:
+%             GeometryFlags defining normalization method to use.
+%             specifically: NormalizeValue, CorrelateNormalizeValue,
+%                           and/or PercentValue
+%
+*/
+MagickExport void ScaleKernelInfo(KernelInfo *kernel,
+  const double scaling_factor,const GeometryFlags normalize_flags)
+{
+  register ssize_t
+    i;
+
+  register double
+    pos_scale,
+    neg_scale;
+
+  /* do the other kernels in a multi-kernel list first */
+  if ( kernel->next != (KernelInfo *) NULL)
+    ScaleKernelInfo(kernel->next, scaling_factor, normalize_flags);
+
+  /* Normalization of Kernel */
+  pos_scale = 1.0;
+  if ( (normalize_flags&NormalizeValue) != 0 ) {
+    if ( fabs(kernel->positive_range + kernel->negative_range) > MagickEpsilon )
+      /* non-zero-summing kernel (generally positive) */
+      pos_scale = fabs(kernel->positive_range + kernel->negative_range);
+    else
+      /* zero-summing kernel */
+      pos_scale = kernel->positive_range;
+  }
+  /* Force kernel into a normalized zero-summing kernel */
+  if ( (normalize_flags&CorrelateNormalizeValue) != 0 ) {
+    pos_scale = ( fabs(kernel->positive_range) > MagickEpsilon )
+                 ? kernel->positive_range : 1.0;
+    neg_scale = ( fabs(kernel->negative_range) > MagickEpsilon )
+                 ? -kernel->negative_range : 1.0;
+  }
+  else
+    neg_scale = pos_scale;
+
+  /* finialize scaling_factor for positive and negative components */
+  pos_scale = scaling_factor/pos_scale;
+  neg_scale = scaling_factor/neg_scale;
+
+  for (i=0; i < (ssize_t) (kernel->width*kernel->height); i++)
+    if ( ! IsNan(kernel->values[i]) )
+      kernel->values[i] *= (kernel->values[i] >= 0) ? pos_scale : neg_scale;
+
+  /* convolution output range */
+  kernel->positive_range *= pos_scale;
+  kernel->negative_range *= neg_scale;
+  /* maximum and minimum values in kernel */
+  kernel->maximum *= (kernel->maximum >= 0.0) ? pos_scale : neg_scale;
+  kernel->minimum *= (kernel->minimum >= 0.0) ? pos_scale : neg_scale;
+
+  /* swap kernel settings if user's scaling factor is negative */
+  if ( scaling_factor < MagickEpsilon ) {
+    double t;
+    t = kernel->positive_range;
+    kernel->positive_range = kernel->negative_range;
+    kernel->negative_range = t;
+    t = kernel->maximum;
+    kernel->maximum = kernel->minimum;
+    kernel->minimum = 1;
+  }
+
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     S h o w K e r n e l I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShowKernelInfo() outputs the details of the given kernel defination to
+%  standard error, generally due to a users 'showkernel' option request.
+%
+%  The format of the ShowKernel method is:
+%
+%      void ShowKernelInfo(KernelInfo *kernel)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+*/
+MagickExport void ShowKernelInfo(KernelInfo *kernel)
+{
+  KernelInfo
+    *k;
+
+  size_t
+    c, i, u, v;
+
+  for (c=0, k=kernel;  k != (KernelInfo *) NULL;  c++, k=k->next ) {
+
+    (void) FormatLocaleFile(stderr, "Kernel");
+    if ( kernel->next != (KernelInfo *) NULL )
+      (void) FormatLocaleFile(stderr, " #%lu", (unsigned long) c );
+    (void) FormatLocaleFile(stderr, " \"%s",
+          CommandOptionToMnemonic(MagickKernelOptions, k->type) );
+    if ( fabs(k->angle) > MagickEpsilon )
+      (void) FormatLocaleFile(stderr, "@%lg", k->angle);
+    (void) FormatLocaleFile(stderr, "\" of size %lux%lu%+ld%+ld",(unsigned long)
+      k->width,(unsigned long) k->height,(long) k->x,(long) k->y);
+    (void) FormatLocaleFile(stderr,
+          " with values from %.*lg to %.*lg\n",
+          GetMagickPrecision(), k->minimum,
+          GetMagickPrecision(), k->maximum);
+    (void) FormatLocaleFile(stderr, "Forming a output range from %.*lg to %.*lg",
+          GetMagickPrecision(), k->negative_range,
+          GetMagickPrecision(), k->positive_range);
+    if ( fabs(k->positive_range+k->negative_range) < MagickEpsilon )
+      (void) FormatLocaleFile(stderr, " (Zero-Summing)\n");
+    else if ( fabs(k->positive_range+k->negative_range-1.0) < MagickEpsilon )
+      (void) FormatLocaleFile(stderr, " (Normalized)\n");
+    else
+      (void) FormatLocaleFile(stderr, " (Sum %.*lg)\n",
+          GetMagickPrecision(), k->positive_range+k->negative_range);
+    for (i=v=0; v < k->height; v++) {
+      (void) FormatLocaleFile(stderr, "%2lu:", (unsigned long) v );
+      for (u=0; u < k->width; u++, i++)
+        if ( IsNan(k->values[i]) )
+          (void) FormatLocaleFile(stderr," %*s", GetMagickPrecision()+3, "nan");
+        else
+          (void) FormatLocaleFile(stderr," %*.*lg", GetMagickPrecision()+3,
+              GetMagickPrecision(), k->values[i]);
+      (void) FormatLocaleFile(stderr,"\n");
+    }
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     U n i t y A d d K e r n a l I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnityAddKernelInfo() Adds a given amount of the 'Unity' Convolution Kernel
+%  to the given pre-scaled and normalized Kernel.  This in effect adds that
+%  amount of the original image into the resulting convolution kernel.  This
+%  value is usually provided by the user as a percentage value in the
+%  'convolve:scale' setting.
+%
+%  The resulting effect is to convert the defined kernels into blended
+%  soft-blurs, unsharp kernels or into sharpening kernels.
+%
+%  The format of the UnityAdditionKernelInfo method is:
+%
+%      void UnityAdditionKernelInfo(KernelInfo *kernel, const double scale )
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+%    o scale:
+%             scaling factor for the unity kernel to be added to
+%             the given kernel.
+%
+*/
+MagickExport void UnityAddKernelInfo(KernelInfo *kernel,
+  const double scale)
+{
+  /* do the other kernels in a multi-kernel list first */
+  if ( kernel->next != (KernelInfo *) NULL)
+    UnityAddKernelInfo(kernel->next, scale);
+
+  /* Add the scaled unity kernel to the existing kernel */
+  kernel->values[kernel->x+kernel->y*kernel->width] += scale;
+  CalcKernelMetaData(kernel);  /* recalculate the meta-data */
+
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     Z e r o K e r n e l N a n s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ZeroKernelNans() replaces any special 'nan' value that may be present in
+%  the kernel with a zero value.  This is typically done when the kernel will
+%  be used in special hardware (GPU) convolution processors, to simply
+%  matters.
+%
+%  The format of the ZeroKernelNans method is:
+%
+%      void ZeroKernelNans (KernelInfo *kernel)
+%
+%  A description of each parameter follows:
+%
+%    o kernel: the Morphology/Convolution kernel
+%
+*/
+MagickExport void ZeroKernelNans(KernelInfo *kernel)
+{
+  register size_t
+    i;
+
+  /* do the other kernels in a multi-kernel list first */
+  if ( kernel->next != (KernelInfo *) NULL)
+    ZeroKernelNans(kernel->next);
+
+  for (i=0; i < (kernel->width*kernel->height); i++)
+    if ( IsNan(kernel->values[i]) )
+      kernel->values[i] = 0.0;
+
+  return;
+}
diff --git a/MagickCore/morphology.h b/MagickCore/morphology.h
new file mode 100644
index 0000000..fc0e242
--- /dev/null
+++ b/MagickCore/morphology.h
@@ -0,0 +1,148 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore morphology methods.
+*/
+#ifndef _MAGICKCORE_MORPHOLOGY_H
+#define _MAGICKCORE_MORPHOLOGY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/geometry.h>
+
+typedef enum
+{
+  UndefinedKernel,    /* equivalent to UnityKernel */
+  UnityKernel,        /* The no-op or 'original image' kernel */
+  GaussianKernel,     /* Convolution Kernels, Gaussian Based */
+  DoGKernel,
+  LoGKernel,
+  BlurKernel,
+  CometKernel,
+  LaplacianKernel,    /* Convolution Kernels, by Name */
+  SobelKernel,
+  FreiChenKernel,
+  RobertsKernel,
+  PrewittKernel,
+  CompassKernel,
+  KirschKernel,
+  DiamondKernel,      /* Shape Kernels */
+  SquareKernel,
+  RectangleKernel,
+  OctagonKernel,
+  DiskKernel,
+  PlusKernel,
+  CrossKernel,
+  RingKernel,
+  PeaksKernel,         /* Hit And Miss Kernels */
+  EdgesKernel,
+  CornersKernel,
+  DiagonalsKernel,
+  LineEndsKernel,
+  LineJunctionsKernel,
+  RidgesKernel,
+  ConvexHullKernel,
+  ThinSEKernel,
+  SkeletonKernel,
+  ChebyshevKernel,    /* Distance Measuring Kernels */
+  ManhattanKernel,
+  OctagonalKernel,
+  EuclideanKernel,
+  UserDefinedKernel   /* User Specified Kernel Array */
+} KernelInfoType;
+
+typedef enum
+{
+  UndefinedMorphology,
+/* Convolve / Correlate weighted sums */
+  ConvolveMorphology,          /* Weighted Sum with reflected kernel */
+  CorrelateMorphology,         /* Weighted Sum using a sliding window */
+/* Low-level Morphology methods */
+  ErodeMorphology,             /* Minimum Value in Neighbourhood */
+  DilateMorphology,            /* Maximum Value in Neighbourhood */
+  ErodeIntensityMorphology,    /* Pixel Pick using GreyScale Erode */
+  DilateIntensityMorphology,   /* Pixel Pick using GreyScale Dialate */
+  DistanceMorphology,          /* Add Kernel Value, take Minimum */
+/* Second-level Morphology methods */
+  OpenMorphology,              /* Dilate then Erode */
+  CloseMorphology,             /* Erode then Dilate */
+  OpenIntensityMorphology,     /* Pixel Pick using GreyScale Open */
+  CloseIntensityMorphology,    /* Pixel Pick using GreyScale Close */
+  SmoothMorphology,            /* Open then Close */
+/* Difference Morphology methods */
+  EdgeInMorphology,            /* Dilate difference from Original */
+  EdgeOutMorphology,           /* Erode difference from Original */
+  EdgeMorphology,              /* Dilate difference with Erode */
+  TopHatMorphology,            /* Close difference from Original */
+  BottomHatMorphology,         /* Open difference from Original */
+/* Recursive Morphology methods */
+  HitAndMissMorphology,        /* Foreground/Background pattern matching */
+  ThinningMorphology,          /* Remove matching pixels from image */
+  ThickenMorphology,           /* Add matching pixels from image */
+/* Experimental Morphology methods */
+  VoronoiMorphology
+} MorphologyMethod;
+
+typedef struct KernelInfo
+{
+  KernelInfoType
+    type;
+
+  size_t
+    width,
+    height;
+
+  ssize_t
+    x,
+    y;
+
+  double
+    *values,
+    minimum,
+    maximum,
+    negative_range,
+    positive_range,
+    angle;
+
+  struct KernelInfo
+    *next;
+
+  size_t
+    signature;
+} KernelInfo;
+
+extern MagickExport KernelInfo
+  *AcquireKernelInfo(const char *),
+  *AcquireKernelBuiltIn(const KernelInfoType,const GeometryInfo *),
+  *CloneKernelInfo(const KernelInfo *),
+  *DestroyKernelInfo(KernelInfo *);
+
+extern MagickExport Image
+  *MorphologyImage(const Image *,const MorphologyMethod,const ssize_t,
+    const KernelInfo *,ExceptionInfo *),
+  *MorphologyImageChannel(const Image *,const ChannelType,
+    const MorphologyMethod,const ssize_t,const KernelInfo *,ExceptionInfo *);
+
+extern MagickExport void
+  ScaleGeometryKernelInfo(KernelInfo *,const char *),
+  ShowKernelInfo(KernelInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/nt-base.c b/MagickCore/nt-base.c
new file mode 100644
index 0000000..38a00aa
--- /dev/null
+++ b/MagickCore/nt-base.c
@@ -0,0 +1,2234 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                 N   N  TTTTT                                %
+%                                 NN  N    T                                  %
+%                                 N N N    T                                  %
+%                                 N  NN    T                                  %
+%                                 N   N    T                                  %
+%                                                                             %
+%                                                                             %
+%                   Windows NT Utility Methods for MagickCore                 %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                December 1996                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+#include "MagickCore/client.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+#  include "ltdl.h"
+#endif
+#include "MagickCore/nt-base.h"
+#if defined(MAGICKCORE_CIPHER_SUPPORT)
+#include <ntsecapi.h>
+#include <wincrypt.h>
+#endif
+
+/*
+  Define declarations.
+*/
+#if !defined(MAP_FAILED)
+#define MAP_FAILED      ((void *) -1)
+#endif
+
+/*
+  Static declarations.
+*/
+#if !defined(MAGICKCORE_LTDL_DELEGATE)
+static char
+  *lt_slsearchpath = (char *) NULL;
+#endif
+
+static GhostInfo
+  ghost_info;
+
+static void
+  *ghost_handle = (void *) NULL;
+
+/*
+  External declarations.
+*/
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
+extern "C" BOOL WINAPI
+  DllMain(HINSTANCE handle,DWORD reason,LPVOID lpvReserved);
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D l l M a i n                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DllMain() is an entry point to the DLL which is called when processes and
+%  threads are initialized and terminated, or upon calls to the Windows
+%  LoadLibrary and FreeLibrary functions.
+%
+%  The function returns TRUE of it succeeds, or FALSE if initialization fails.
+%
+%  The format of the DllMain method is:
+%
+%    BOOL WINAPI DllMain(HINSTANCE handle,DWORD reason,LPVOID lpvReserved)
+%
+%  A description of each parameter follows:
+%
+%    o handle: handle to the DLL module
+%
+%    o reason: reason for calling function:
+%
+%      DLL_PROCESS_ATTACH - DLL is being loaded into virtual address
+%                           space of current process.
+%      DLL_THREAD_ATTACH - Indicates that the current process is
+%                          creating a new thread.  Called under the
+%                          context of the new thread.
+%      DLL_THREAD_DETACH - Indicates that the thread is exiting.
+%                          Called under the context of the exiting
+%                          thread.
+%      DLL_PROCESS_DETACH - Indicates that the DLL is being unloaded
+%                           from the virtual address space of the
+%                           current process.
+%
+%    o lpvReserved: Used for passing additional info during DLL_PROCESS_ATTACH
+%                   and DLL_PROCESS_DETACH.
+%
+*/
+#if defined(_DLL) && defined( ProvideDllMain )
+BOOL WINAPI DllMain(HINSTANCE handle,DWORD reason,LPVOID lpvReserved)
+{
+  switch (reason)
+  {
+    case DLL_PROCESS_ATTACH:
+    {
+      char
+        *module_path;
+
+      ssize_t
+        count;
+
+      module_path=(char *) AcquireQuantumMemory(MaxTextExtent,
+        sizeof(*module_path));
+      if (module_path == (char *) NULL)
+        return(FALSE);
+      count=(ssize_t) GetModuleFileName(handle,module_path,MaxTextExtent);
+      if (count != 0)
+        {
+          char
+            *path;
+
+          for ( ; count > 0; count--)
+            if (module_path[count] == '\\')
+              {
+                module_path[count+1]='\0';
+                break;
+              }
+          MagickCoreGenesis(module_path,MagickFalse);
+          path=(char *) AcquireQuantumMemory(16UL*MaxTextExtent,sizeof(*path));
+          if (path == (char *) NULL)
+            {
+              module_path=DestroyString(module_path);
+              return(FALSE);
+            }
+          count=(ssize_t) GetEnvironmentVariable("PATH",path,16*MaxTextExtent);
+          if ((count != 0) && (strstr(path,module_path) == (char *) NULL))
+            {
+              if ((strlen(module_path)+count+1) < (16*MaxTextExtent-1))
+                {
+                  char
+                    *variable;
+
+                  variable=(char *) AcquireQuantumMemory(16UL*MaxTextExtent,
+                    sizeof(*variable));
+                  if (variable == (char *) NULL)
+                    {
+                      path=DestroyString(path);
+                      module_path=DestroyString(module_path);
+                      return(FALSE);
+                    }
+                  (void) FormatLocaleString(variable,16*MaxTextExtent,
+                    "%s;%s",module_path,path);
+                  SetEnvironmentVariable("PATH",variable);
+                  variable=DestroyString(variable);
+                }
+            }
+          path=DestroyString(path);
+        }
+      module_path=DestroyString(module_path);
+      break;
+    }
+    case DLL_PROCESS_DETACH:
+    {
+      MagickCoreTerminus();
+      break;
+    }
+    default:
+      break;
+  }
+  return(TRUE);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x i t                                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Exit() calls TerminateProcess for Win95.
+%
+%  The format of the exit method is:
+%
+%      int Exit(int status)
+%
+%  A description of each parameter follows:
+%
+%    o status: an integer value representing the status of the terminating
+%      process.
+%
+*/
+MagickExport int Exit(int status)
+{
+  if (IsWindows95())
+    TerminateProcess(GetCurrentProcess(),(unsigned int) status);
+  exit(status);
+  return(0);
+}
+
+#if !defined(__MINGW32__)
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   g e t t i m e o f d a y                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The gettimeofday() method get the time of day.
+%
+%  The format of the gettimeofday method is:
+%
+%      int gettimeofday(struct timeval *time_value,struct timezone *time_zone)
+%
+%  A description of each parameter follows:
+%
+%    o time_value: the time value.
+%
+%    o time_zone: the time zone.
+%
+*/
+MagickExport int gettimeofday (struct timeval *time_value,
+  struct timezone *time_zone)
+{
+#define EpochFiletime  MagickLLConstant(116444736000000000)
+
+  static int
+    is_tz_set;
+
+  if (time_value != (struct timeval *) NULL)
+    {
+      FILETIME
+        file_time;
+
+      __int64
+        time;
+
+      LARGE_INTEGER
+        date_time;
+
+      GetSystemTimeAsFileTime(&file_time);
+      date_time.LowPart=file_time.dwLowDateTime;
+      date_time.HighPart=file_time.dwHighDateTime;
+      time=date_time.QuadPart;
+      time-=EpochFiletime;
+      time/=10;
+      time_value->tv_sec=(ssize_t) (time / 1000000);
+      time_value->tv_usec=(ssize_t) (time % 1000000);
+    }
+  if (time_zone != (struct timezone *) NULL)
+    {
+      if (is_tz_set == 0)
+        {
+          _tzset();
+          is_tz_set++;
+        }
+      time_zone->tz_minuteswest=_timezone/60;
+      time_zone->tz_dsttime=_daylight;
+    }
+  return(0);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s W i n d o w s 9 5                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsWindows95() returns true if the system is Windows 95.
+%
+%  The format of the IsWindows95 method is:
+%
+%      int IsWindows95()
+%
+*/
+MagickExport int IsWindows95()
+{
+  OSVERSIONINFO
+    version_info;
+
+  version_info.dwOSVersionInfoSize=sizeof(version_info);
+  if (GetVersionEx(&version_info) &&
+      (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS))
+    return(1);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T C l o s e D i r e c t o r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTCloseDirectory() closes the named directory stream and frees the DIR
+%  structure.
+%
+%  The format of the NTCloseDirectory method is:
+%
+%      int NTCloseDirectory(DIR *entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+*/
+MagickExport int NTCloseDirectory(DIR *entry)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(entry != (DIR *) NULL);
+  FindClose(entry->hSearch);
+  entry=(DIR *) RelinquishMagickMemory(entry);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T C l o s e L i b r a r y                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTCloseLibrary() unloads the module associated with the passed handle.
+%
+%  The format of the NTCloseLibrary method is:
+%
+%      void NTCloseLibrary(void *handle)
+%
+%  A description of each parameter follows:
+%
+%    o handle: Specifies a handle to a previously loaded dynamic module.
+%
+*/
+MagickExport int NTCloseLibrary(void *handle)
+{
+  if (IsWindows95())
+    return(FreeLibrary((HINSTANCE) handle));
+  return(!(FreeLibrary((HINSTANCE) handle)));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T C o n t r o l H a n d l e r                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTControlHandler() registers a control handler that is activated when, for
+%  example, a ctrl-c is received.
+%
+%  The format of the NTControlHandler method is:
+%
+%      int NTControlHandler(void)
+%
+*/
+
+static BOOL ControlHandler(DWORD type)
+{
+  (void) type;
+  AsynchronousResourceComponentTerminus();
+  return(FALSE);
+}
+
+MagickExport int NTControlHandler(void)
+{
+  return(SetConsoleCtrlHandler((PHANDLER_ROUTINE) ControlHandler,TRUE));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T E l a p s e d T i m e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTElapsedTime() returns the elapsed time (in seconds) since the last call to
+%  StartTimer().
+%
+%  The format of the ElapsedTime method is:
+%
+%      double NTElapsedTime(void)
+%
+*/
+MagickExport double NTElapsedTime(void)
+{
+  union
+  {
+    FILETIME
+      filetime;
+
+    __int64
+      filetime64;
+  } elapsed_time;
+
+  SYSTEMTIME
+    system_time;
+
+  GetSystemTime(&system_time);
+  SystemTimeToFileTime(&system_time,&elapsed_time.filetime);
+  return((double) 1.0e-7*elapsed_time.filetime64);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   N T E r r o r H a n d l e r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTErrorHandler() displays an error reason and then terminates the program.
+%
+%  The format of the NTErrorHandler method is:
+%
+%      void NTErrorHandler(const ExceptionType severity,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o severity: Specifies the numeric error category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+MagickExport void NTErrorHandler(const ExceptionType severity,
+  const char *reason,const char *description)
+{
+  char
+    buffer[3*MaxTextExtent],
+    *message;
+
+  (void) severity;
+  if (reason == (char *) NULL)
+    {
+      MagickCoreTerminus();
+      exit(0);
+    }
+  message=GetExceptionMessage(errno);
+  if ((description != (char *) NULL) && errno)
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s (%s) [%s].\n",
+      GetClientName(),reason,description,message);
+  else
+    if (description != (char *) NULL)
+      (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s (%s).\n",
+        GetClientName(),reason,description);
+    else
+      if (errno != 0)
+        (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s [%s].\n",
+          GetClientName(),reason,message);
+      else
+        (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s.\n",
+          GetClientName(),reason);
+  message=DestroyString(message);
+  (void) MessageBox(NULL,buffer,"ImageMagick Exception",MB_OK | MB_TASKMODAL |
+    MB_SETFOREGROUND | MB_ICONEXCLAMATION);
+  MagickCoreTerminus();
+  exit(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T E x i t L i b r a r y                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTExitLibrary() exits the dynamic module loading subsystem.
+%
+%  The format of the NTExitLibrary method is:
+%
+%      int NTExitLibrary(void)
+%
+*/
+MagickExport int NTExitLibrary(void)
+{
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G a t h e r R a n d o m D a t a                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGatherRandomData() gathers random data and returns it.
+%
+%  The format of the GatherRandomData method is:
+%
+%      MagickBooleanType NTGatherRandomData(const size_t length,
+%        unsigned char *random)
+%
+%  A description of each parameter follows:
+%
+%    length: the length of random data buffer
+%
+%    random: the random data is returned here.
+%
+*/
+MagickExport MagickBooleanType NTGatherRandomData(const size_t length,
+  unsigned char *random)
+{
+#if defined(MAGICKCORE_CIPHER_SUPPORT) && defined(_MSC_VER) && (_MSC_VER > 1200)
+  HCRYPTPROV
+    handle;
+
+  int
+    status;
+
+  handle=(HCRYPTPROV) NULL;
+  status=CryptAcquireContext(&handle,NULL,MS_DEF_PROV,PROV_RSA_FULL,
+    (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
+  if (status == 0)
+    status=CryptAcquireContext(&handle,NULL,MS_DEF_PROV,PROV_RSA_FULL,
+      (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET));
+  if (status == 0)
+    return(MagickFalse);
+  status=CryptGenRandom(handle,(DWORD) length,random);
+  if (status == 0)
+    {
+      status=CryptReleaseContext(handle,0);
+      return(MagickFalse);
+    }
+  status=CryptReleaseContext(handle,0);
+  if (status == 0)
+    return(MagickFalse);
+#else
+  (void) random;
+  (void) length;
+#endif
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G e t E x e c u t i o n P a t h                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGetExecutionPath() returns the execution path of a program.
+%
+%  The format of the GetExecutionPath method is:
+%
+%      MagickBooleanType NTGetExecutionPath(char *path,const size_t extent)
+%
+%  A description of each parameter follows:
+%
+%    o path: the pathname of the executable that started the process.
+%
+%    o extent: the maximum extent of the path.
+%
+*/
+MagickExport MagickBooleanType NTGetExecutionPath(char *path,
+  const size_t extent)
+{
+  GetModuleFileName(0,path,(DWORD) extent);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G e t L a s t E r r o r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGetLastError() returns the last error that occurred.
+%
+%  The format of the NTGetLastError method is:
+%
+%      char *NTGetLastError(void)
+%
+*/
+char *NTGetLastError(void)
+{
+  char
+    *reason;
+
+  int
+    status;
+
+  LPVOID
+    buffer;
+
+  status=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+    FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),
+    MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &buffer,0,NULL);
+  if (!status)
+    reason=AcquireString("An unknown error occurred");
+  else
+    {
+      reason=AcquireString((const char *) buffer);
+      LocalFree(buffer);
+    }
+  return(reason);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G e t L i b r a r y E r r o r                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Lt_dlerror() returns a pointer to a string describing the last error
+%  associated with a lt_dl method.  Note that this function is not thread
+%  safe so it should only be used under the protection of a lock.
+%
+%  The format of the NTGetLibraryError method is:
+%
+%      const char *NTGetLibraryError(void)
+%
+*/
+MagickExport const char *NTGetLibraryError(void)
+{
+  static char
+    last_error[MaxTextExtent];
+
+  char
+    *error;
+
+  *last_error='\0';
+  error=NTGetLastError();
+  if (error)
+    (void) CopyMagickString(last_error,error,MaxTextExtent);
+  error=DestroyString(error);
+  return(last_error);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G e t L i b r a r y S y m b o l                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGetLibrarySymbol() retrieve the procedure address of the method
+%  specified by the passed character string.
+%
+%  The format of the NTGetLibrarySymbol method is:
+%
+%      void *NTGetLibrarySymbol(void *handle,const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o handle: Specifies a handle to the previously loaded dynamic module.
+%
+%    o name: Specifies the procedure entry point to be returned.
+%
+*/
+void *NTGetLibrarySymbol(void *handle,const char *name)
+{
+  LPFNDLLFUNC1
+    lpfnDllFunc1;
+
+  lpfnDllFunc1=(LPFNDLLFUNC1) GetProcAddress((HINSTANCE) handle,name);
+  if (!lpfnDllFunc1)
+    return((void *) NULL);
+  return((void *) lpfnDllFunc1);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G e t M o d u l e P a t h                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGetModulePath() returns the path of the specified module.
+%
+%  The format of the GetModulePath method is:
+%
+%      MagickBooleanType NTGetModulePath(const char *module,char *path)
+%
+%  A description of each parameter follows:
+%
+%    modith: the module name.
+%
+%    path: the module path is returned here.
+%
+*/
+MagickExport MagickBooleanType NTGetModulePath(const char *module,char *path)
+{
+  char
+    module_path[MaxTextExtent];
+
+  HMODULE
+    handle;
+
+  ssize_t
+    length;
+
+  *path='\0';
+  handle=GetModuleHandle(module);
+  if (handle == (HMODULE) NULL)
+    return(MagickFalse);
+  length=GetModuleFileName(handle,module_path,MaxTextExtent);
+  if (length != 0)
+    GetPathComponent(module_path,HeadPath,path);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t D L L                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptDLL() returns the path to the most recent Ghostscript version
+%  DLL.  The method returns TRUE on success otherwise FALSE.
+%
+%  The format of the NTGhostscriptDLL method is:
+%
+%      int NTGhostscriptDLL(char *path,int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: return the Ghostscript DLL path here.
+%
+%    o length: the buffer length.
+%
+*/
+
+static int NTGetRegistryValue(HKEY root,const char *key,const char *name,
+  char *value,int *length)
+{
+  BYTE
+    byte,
+    *p;
+
+  DWORD
+    extent,
+    type;
+
+  HKEY
+    hkey;
+
+  LONG
+    status;
+
+  /*
+    Get a registry value: key = root\\key, named value = name.
+  */
+  if (RegOpenKeyExA(root,key,0,KEY_READ,&hkey) != ERROR_SUCCESS)
+    return(1);  /* no match */
+  p=(BYTE *) value;
+  type=REG_SZ;
+  extent=(*length);
+  if (p == (BYTE *) NULL)
+    p=(&byte);  /* ERROR_MORE_DATA only if value is NULL */
+  status=RegQueryValueExA(hkey,(char *) name,0,&type,p,&extent);
+  RegCloseKey(hkey);
+  if (status == ERROR_SUCCESS)
+    {
+      *length=extent;
+      return(0);  /* return the match */
+    }
+  if (status == ERROR_MORE_DATA)
+    {
+      *length=extent;
+      return(-1);  /* buffer not large enough */
+    }
+  return(1);  /* not found */
+}
+
+static int NTLocateGhostscript(const char **product_family,int *major_version,
+  int *minor_version)
+{
+  int
+    i;
+
+  MagickBooleanType
+    status;
+
+  static const char
+    *products[4] =
+    {
+      "GPL Ghostscript",
+      "GNU Ghostscript",
+      "AFPL Ghostscript",
+      "Aladdin Ghostscript"
+    };
+
+  /*
+    Find the most recent version of Ghostscript.
+  */
+  status=FALSE;
+  *product_family=NULL;
+  *major_version=5;
+  *minor_version=49; /* min version of Ghostscript is 5.50 */
+  for (i=0; i < (ssize_t) (sizeof(products)/sizeof(products[0])); i++)
+  {
+    char
+      key[MaxTextExtent];
+
+    HKEY
+      hkey,
+      root;
+
+    REGSAM
+      mode;
+
+    (void) FormatLocaleString(key,MaxTextExtent,"SOFTWARE\\%s",products[i]);
+    root=HKEY_LOCAL_MACHINE;
+    mode=KEY_READ;
+#if defined(KEY_WOW64_32KEY)
+    mode|=KEY_WOW64_32KEY;
+#endif
+    if (RegOpenKeyExA(root,key,0,mode,&hkey) == ERROR_SUCCESS)
+      {
+        DWORD
+          extent;
+
+        int
+          j;
+
+        /*
+          Now enumerate the keys.
+        */
+        extent=sizeof(key)/sizeof(char);
+        for (j=0; RegEnumKeyA(hkey,j,key,extent) == ERROR_SUCCESS; j++)
+        {
+          int
+            major,
+            minor;
+
+          major=0;
+          minor=0;
+          if (sscanf(key,"%d.%d",&major,&minor) != 2)
+            continue;
+          if ((major > *major_version) || ((major == *major_version) &&
+              (minor > *minor_version)))
+            {
+              *product_family=products[i];
+              *major_version=major;
+              *minor_version=minor;
+              status=TRUE;
+            }
+       }
+       (void) RegCloseKey(hkey);
+     }
+  }
+  if (status == FALSE)
+    {
+      *major_version=0;
+      *minor_version=0;
+    }
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),"Ghostscript (%s) "
+    "version %d.%02d",*product_family,*major_version,*minor_version);
+  return(status);
+}
+
+static int NTGhostscriptGetString(const char *name,char *value,
+  const size_t length)
+{
+  char
+    key[MaxTextExtent];
+
+  int
+    i,
+    extent;
+
+  static const char
+    *product_family = (const char *) NULL;
+
+  static int
+    major_version=0,
+    minor_version=0;
+
+  struct
+  {
+    const HKEY
+      hkey;
+
+    const char
+      *name;
+  }
+  hkeys[2] =
+  {
+    { HKEY_CURRENT_USER,  "HKEY_CURRENT_USER"  },
+    { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" }
+  };
+
+  /*
+    Get a string from the installed Ghostscript.
+  */
+  *value='\0';
+  if (product_family == NULL)
+    (void) NTLocateGhostscript(&product_family,&major_version,&minor_version);
+  if (product_family == NULL)
+    return(FALSE);
+  (void) FormatLocaleString(key,MaxTextExtent,"SOFTWARE\\%s\\%d.%02d",
+    product_family,major_version,minor_version);
+  for (i=0; i < (ssize_t) (sizeof(hkeys)/sizeof(hkeys[0])); i++)
+  {
+    extent=(int) length;
+    if (NTGetRegistryValue(hkeys[i].hkey,key,name,value,&extent) == 0)
+      {
+        (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+          "registry: \"%s\\%s\\%s\"=\"%s\"",hkeys[i].name,key,name,value);
+        return(TRUE);
+      }
+    (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+      "registry: \"%s\\%s\\%s\" (failed)",hkeys[i].name,key,name);
+  }
+  return(FALSE);
+}
+
+MagickExport int NTGhostscriptDLL(char *path,int length)
+{
+  static char
+    dll[MaxTextExtent] = { "" };
+
+  *path='\0';
+  if ((*dll == '\0') &&
+      (NTGhostscriptGetString("GS_DLL",dll,sizeof(dll)) == FALSE))
+    return(FALSE);
+  (void) CopyMagickString(path,dll,length);
+  return(TRUE);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t D L L V e c t o r s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptDLLVectors() returns a GhostInfo structure that includes
+%  function vectors to invoke Ghostscript DLL functions. A null pointer is
+%  returned if there is an error when loading the DLL or retrieving the
+%  function vectors.
+%
+%  The format of the NTGhostscriptDLLVectors method is:
+%
+%      const GhostInfo *NTGhostscriptDLLVectors(void)
+%
+*/
+MagickExport const GhostInfo *NTGhostscriptDLLVectors(void)
+{
+  if (NTGhostscriptLoadDLL() == FALSE)
+    return((GhostInfo *) NULL);
+  return(&ghost_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t E X E                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptEXE() obtains the path to the latest Ghostscript executable.
+%  The method returns FALSE if a full path value is not obtained and returns
+%  a default path of gswin32c.exe.
+%
+%  The format of the NTGhostscriptEXE method is:
+%
+%      int NTGhostscriptEXE(char *path,int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: return the Ghostscript executable path here.
+%
+%    o length: length of buffer.
+%
+*/
+MagickExport int NTGhostscriptEXE(char *path,int length)
+{
+  register char
+    *p;
+
+  static char
+    program[MaxTextExtent] = { "" };
+
+  (void) CopyMagickString(path,"gswin32c.exe",length);
+  if ((*program == '\0') &&
+      (NTGhostscriptGetString("GS_DLL",program,sizeof(program)) == FALSE))
+    return(FALSE);
+  p=strrchr(program,'\\');
+  if (p != (char *) NULL)
+    {
+      p++;
+      *p='\0';
+      (void) ConcatenateMagickString(program,"gswin32c.exe",sizeof(program));
+    }
+  (void) CopyMagickString(path,program,length);
+  return(TRUE);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t F o n t s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptFonts() obtains the path to the Ghostscript fonts.  The method
+%  returns FALSE if it cannot determine the font path.
+%
+%  The format of the NTGhostscriptFonts method is:
+%
+%      int NTGhostscriptFonts(char *path, int length)
+%
+%  A description of each parameter follows:
+%
+%    o path: return the font path here.
+%
+%    o length: length of the path buffer.
+%
+*/
+MagickExport int NTGhostscriptFonts(char *path,int length)
+{
+  char
+    buffer[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  register char
+    *p,
+    *q;
+
+  *path='\0';
+  if (NTGhostscriptGetString("GS_LIB",buffer,MaxTextExtent) == FALSE)
+    return(FALSE);
+  for (p=buffer-1; p != (char *) NULL; p=strchr(p+1,DirectoryListSeparator))
+  {
+    (void) CopyMagickString(path,p+1,length+1);
+    q=strchr(path,DirectoryListSeparator);
+    if (q != (char *) NULL)
+      *q='\0';
+    (void) FormatLocaleString(filename,MaxTextExtent,"%s%sfonts.dir",path,
+      DirectorySeparator);
+    if (IsPathAccessible(filename) != MagickFalse)
+      return(TRUE);
+  }
+  return(FALSE);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t L o a d D L L                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptLoadDLL() attempts to load the Ghostscript DLL and returns
+%  TRUE if it succeeds.
+%
+%  The format of the NTGhostscriptLoadDLL method is:
+%
+%      int NTGhostscriptLoadDLL(void)
+%
+*/
+MagickExport int NTGhostscriptLoadDLL(void)
+{
+  char
+    path[MaxTextExtent];
+
+  if (ghost_handle != (void *) NULL)
+    return(TRUE);
+  if (NTGhostscriptDLL(path,sizeof(path)) == FALSE)
+    return(FALSE);
+  ghost_handle=lt_dlopen(path);
+  if (ghost_handle == (void *) NULL)
+    return(FALSE);
+  (void) ResetMagickMemory((void *) &ghost_info,0,sizeof(GhostInfo));
+  ghost_info.exit=(int (MagickDLLCall *)(gs_main_instance*))
+    lt_dlsym(ghost_handle,"gsapi_exit");
+  ghost_info.init_with_args=(int (MagickDLLCall *)(gs_main_instance *,int,
+    char **)) (lt_dlsym(ghost_handle,"gsapi_init_with_args"));
+  ghost_info.new_instance=(int (MagickDLLCall *)(gs_main_instance **,void *)) (
+    lt_dlsym(ghost_handle,"gsapi_new_instance"));
+  ghost_info.run_string=(int (MagickDLLCall *)(gs_main_instance *,const char *,
+    int,int *)) (lt_dlsym(ghost_handle,"gsapi_run_string"));
+  ghost_info.delete_instance=(void (MagickDLLCall *) (gs_main_instance *)) (
+    lt_dlsym(ghost_handle,"gsapi_delete_instance"));
+  if ((ghost_info.exit == NULL) || (ghost_info.init_with_args == NULL) ||
+      (ghost_info.new_instance == NULL) || (ghost_info.run_string == NULL) ||
+      (ghost_info.delete_instance == NULL))
+    return(FALSE);
+  return(TRUE);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T G h o s t s c r i p t U n L o a d D L L                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTGhostscriptUnLoadDLL() unloads the Ghostscript DLL and returns TRUE if
+%  it succeeds.
+%
+%  The format of the NTGhostscriptUnLoadDLL method is:
+%
+%      int NTGhostscriptUnLoadDLL(void)
+%
+*/
+MagickExport int NTGhostscriptUnLoadDLL(void)
+{
+  int
+    status;
+
+  if (ghost_handle == (void *) NULL)
+    return(FALSE);
+  status=lt_dlclose(ghost_handle);
+  ghost_handle=(void *) NULL;
+  (void) ResetMagickMemory((void *) &ghost_info,0,sizeof(GhostInfo));
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T I n i t i a l i z e L i b r a r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTInitializeLibrary() initializes the dynamic module loading subsystem.
+%
+%  The format of the NTInitializeLibrary method is:
+%
+%      int NTInitializeLibrary(void)
+%
+*/
+MagickExport int NTInitializeLibrary(void)
+{
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  N T M a p M e m o r y                                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Mmap() emulates the Unix method of the same name.
+%
+%  The format of the NTMapMemory method is:
+%
+%    MagickExport void *NTMapMemory(char *address,size_t length,int protection,
+%      int access,int file,MagickOffsetType offset)
+%
+*/
+MagickExport void *NTMapMemory(char *address,size_t length,int protection,
+  int flags,int file,MagickOffsetType offset)
+{
+  DWORD
+    access_mode,
+    high_length,
+    high_offset,
+    low_length,
+    low_offset,
+    protection_mode;
+
+  HANDLE
+    file_handle,
+    map_handle;
+
+  void
+    *map;
+
+  (void) address;
+  access_mode=0;
+  file_handle=INVALID_HANDLE_VALUE;
+  low_length=(DWORD) (length & 0xFFFFFFFFUL);
+  high_length=(DWORD) ((((MagickOffsetType) length) >> 32) & 0xFFFFFFFFUL);
+  map_handle=INVALID_HANDLE_VALUE;
+  map=(void *) NULL;
+  low_offset=(DWORD) (offset & 0xFFFFFFFFUL);
+  high_offset=(DWORD) ((offset >> 32) & 0xFFFFFFFFUL);
+  protection_mode=0;
+  if (protection & PROT_WRITE)
+    {
+      access_mode=FILE_MAP_WRITE;
+      if (!(flags & MAP_PRIVATE))
+        protection_mode=PAGE_READWRITE;
+      else
+        {
+          access_mode=FILE_MAP_COPY;
+          protection_mode=PAGE_WRITECOPY;
+        }
+    }
+  else
+    if (protection & PROT_READ)
+      {
+        access_mode=FILE_MAP_READ;
+        protection_mode=PAGE_READONLY;
+      }
+  if ((file == -1) && (flags & MAP_ANONYMOUS))
+    file_handle=INVALID_HANDLE_VALUE;
+  else
+    file_handle=(HANDLE) _get_osfhandle(file);
+  map_handle=CreateFileMapping(file_handle,0,protection_mode,high_length,
+    low_length,0);
+  if (map_handle)
+    {
+      map=(void *) MapViewOfFile(map_handle,access_mode,high_offset,low_offset,
+        length);
+      CloseHandle(map_handle);
+    }
+  if (map == (void *) NULL)
+    return((void *) MAP_FAILED);
+  return((void *) ((char *) map));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T O p e n D i r e c t o r y                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTOpenDirectory() opens the directory named by filename and associates a
+%  directory stream with it.
+%
+%  The format of the NTOpenDirectory method is:
+%
+%      DIR *NTOpenDirectory(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+*/
+MagickExport DIR *NTOpenDirectory(const char *path)
+{
+  char
+    file_specification[MaxTextExtent];
+
+  DIR
+    *entry;
+
+  size_t
+    length;
+
+  assert(path != (const char *) NULL);
+  length=CopyMagickString(file_specification,path,MaxTextExtent);
+  if (length >= (MaxTextExtent-1))
+    return((DIR *) NULL);
+  length=ConcatenateMagickString(file_specification,DirectorySeparator,
+    MaxTextExtent);
+  if (length >= (MaxTextExtent-1))
+    return((DIR *) NULL);
+  entry=(DIR *) AcquireMagickMemory(sizeof(DIR));
+  if (entry != (DIR *) NULL)
+    {
+      entry->firsttime=TRUE;
+      entry->hSearch=FindFirstFile(file_specification,&entry->Win32FindData);
+    }
+  if (entry->hSearch == INVALID_HANDLE_VALUE)
+    {
+      length=ConcatenateMagickString(file_specification,"\\*.*",MaxTextExtent);
+      if (length >= (MaxTextExtent-1))
+        {
+          entry=(DIR *) RelinquishMagickMemory(entry);
+          return((DIR *) NULL);
+        }
+      entry->hSearch=FindFirstFile(file_specification,&entry->Win32FindData);
+      if (entry->hSearch == INVALID_HANDLE_VALUE)
+        {
+          entry=(DIR *) RelinquishMagickMemory(entry);
+          return((DIR *) NULL);
+        }
+    }
+  return(entry);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T O p e n L i b r a r y                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTOpenLibrary() loads a dynamic module into memory and returns a handle that
+%  can be used to access the various procedures in the module.
+%
+%  The format of the NTOpenLibrary method is:
+%
+%      void *NTOpenLibrary(const char *filename)
+%
+%  A description of each parameter follows:
+%
+%    o path: Specifies a pointer to string representing dynamic module that
+%      is to be loaded.
+%
+*/
+
+static const char *GetSearchPath( void )
+{
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+  return(lt_dlgetsearchpath());
+#else
+  return(lt_slsearchpath);
+#endif
+}
+
+MagickExport void *NTOpenLibrary(const char *filename)
+{
+#define MaxPathElements  31
+
+  char
+    buffer[MaxTextExtent];
+
+  int
+    index;
+
+  register const char
+    *p,
+    *q;
+
+  register int
+    i;
+
+  UINT
+    mode;
+
+  void
+    *handle;
+
+  mode=SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+  handle=(void *) LoadLibraryEx(filename,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
+  if ((handle != (void *) NULL) || (GetSearchPath() == (char *) NULL))
+    {
+      SetErrorMode(mode);
+      return(handle);
+    }
+  p=(char *) GetSearchPath();
+  index=0;
+  while (index < MaxPathElements)
+  {
+    q=strchr(p,DirectoryListSeparator);
+    if (q == (char *) NULL)
+      {
+        (void) CopyMagickString(buffer,p,MaxTextExtent);
+        (void) ConcatenateMagickString(buffer,"\\",MaxTextExtent);
+        (void) ConcatenateMagickString(buffer,filename,MaxTextExtent);
+        handle=(void *) LoadLibraryEx(buffer,NULL,
+          LOAD_WITH_ALTERED_SEARCH_PATH);
+        break;
+      }
+    i=q-p;
+    (void) CopyMagickString(buffer,p,i+1);
+    (void) ConcatenateMagickString(buffer,"\\",MaxTextExtent);
+    (void) ConcatenateMagickString(buffer,filename,MaxTextExtent);
+    handle=(void *) LoadLibraryEx(buffer,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
+    if (handle != (void *) NULL)
+      break;
+    p=q+1;
+  }
+  SetErrorMode(mode);
+  return(handle);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%    N T R e a d D i r e c t o r y                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTReadDirectory() returns a pointer to a structure representing the
+%  directory entry at the current position in the directory stream to which
+%  entry refers.
+%
+%  The format of the NTReadDirectory
+%
+%      NTReadDirectory(entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+*/
+MagickExport struct dirent *NTReadDirectory(DIR *entry)
+{
+  int
+    status;
+
+  size_t
+    length;
+
+  if (entry == (DIR *) NULL)
+    return((struct dirent *) NULL);
+  if (!entry->firsttime)
+    {
+      status=FindNextFile(entry->hSearch,&entry->Win32FindData);
+      if (status == 0)
+        return((struct dirent *) NULL);
+    }
+  length=CopyMagickString(entry->file_info.d_name,
+    entry->Win32FindData.cFileName,sizeof(entry->file_info.d_name));
+  if (length >= sizeof(entry->file_info.d_name))
+    return((struct dirent *) NULL);
+  entry->firsttime=FALSE;
+  entry->file_info.d_namlen=(int) strlen(entry->file_info.d_name);
+  return(&entry->file_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T R e g i s t r y K e y L o o k u p                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTRegistryKeyLookup() returns ImageMagick installation path settings
+%  stored in the Windows Registry.  Path settings are specific to the
+%  installed ImageMagick version so that multiple Image Magick installations
+%  may coexist.
+%
+%  Values are stored in the registry under a base path path similar to
+%  "HKEY_LOCAL_MACHINE/SOFTWARE\ImageMagick\5.5.7\Q:16". The provided subkey
+%  is appended to this base path to form the full key.
+%
+%  The format of the NTRegistryKeyLookup method is:
+%
+%      unsigned char *NTRegistryKeyLookup(const char *subkey)
+%
+%  A description of each parameter follows:
+%
+%    o subkey: Specifies a string that identifies the registry object.
+%      Currently supported sub-keys include: "BinPath", "ConfigurePath",
+%      "LibPath", "CoderModulesPath", "FilterModulesPath", "SharePath".
+%
+*/
+MagickExport unsigned char *NTRegistryKeyLookup(const char *subkey)
+{
+  char
+    package_key[MaxTextExtent];
+
+  DWORD
+    size,
+    type;
+
+  HKEY
+    registry_key;
+
+  LONG
+    status;
+
+  unsigned char
+    *value;
+
+  /*
+    Look-up base key.
+  */
+  (void) FormatLocaleString(package_key,MaxTextExtent,"SOFTWARE\\%s\\%s\\Q:%d",
+    MagickPackageName,MagickLibVersionText,MAGICKCORE_QUANTUM_DEPTH);
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),"%s",package_key);
+  registry_key=(HKEY) INVALID_HANDLE_VALUE;
+  status=RegOpenKeyExA(HKEY_LOCAL_MACHINE,package_key,0,KEY_READ,&registry_key);
+  if (status != ERROR_SUCCESS)
+    {
+      registry_key=(HKEY) INVALID_HANDLE_VALUE;
+      return((unsigned char *) NULL);
+    }
+  /*
+    Look-up sub key.
+  */
+  size=32;
+  value=(unsigned char *) AcquireQuantumMemory(size,sizeof(*value));
+  if (value == (unsigned char *) NULL)
+    {
+      RegCloseKey(registry_key);
+      return((unsigned char *) NULL);
+    }
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),"%s",subkey);
+  status=RegQueryValueExA(registry_key,subkey,0,&type,value,&size);
+  if ((status == ERROR_MORE_DATA) && (type == REG_SZ))
+    {
+      value=(unsigned char *) ResizeQuantumMemory(value,size,sizeof(*value));
+      if (value == (BYTE *) NULL)
+        {
+          RegCloseKey(registry_key);
+          return((unsigned char *) NULL);
+        }
+      status=RegQueryValueExA(registry_key,subkey,0,&type,value,&size);
+    }
+  RegCloseKey(registry_key);
+  if ((type != REG_SZ) || (status != ERROR_SUCCESS))
+    value=(unsigned char *) RelinquishMagickMemory(value);
+  return((unsigned char *) value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T R e p o r t E v e n t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTReportEvent() reports an event.
+%
+%  The format of the NTReportEvent method is:
+%
+%      MagickBooleanType NTReportEvent(const char *event,
+%        const MagickBooleanType error)
+%
+%  A description of each parameter follows:
+%
+%    o event: the event.
+%
+%    o error: MagickTrue the event is an error.
+%
+*/
+MagickExport MagickBooleanType NTReportEvent(const char *event,
+  const MagickBooleanType error)
+{
+  const char
+    *events[1];
+
+  HANDLE
+    handle;
+
+  WORD
+    type;
+
+  handle=RegisterEventSource(NULL,MAGICKCORE_PACKAGE_NAME);
+  if (handle == NULL)
+    return(MagickFalse);
+  events[0]=event;
+  type=error ? EVENTLOG_ERROR_TYPE : EVENTLOG_WARNING_TYPE;
+  ReportEvent(handle,type,0,0,NULL,1,0,events,NULL);
+  DeregisterEventSource(handle);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T R e s o u r c e T o B l o b                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTResourceToBlob() returns a blob containing the contents of the resource
+%  in the current executable specified by the id parameter. This currently
+%  used to retrieve MGK files tha have been embedded into the various command
+%  line utilities.
+%
+%  The format of the NTResourceToBlob method is:
+%
+%      unsigned char *NTResourceToBlob(const char *id)
+%
+%  A description of each parameter follows:
+%
+%    o id: Specifies a string that identifies the resource.
+%
+*/
+MagickExport unsigned char *NTResourceToBlob(const char *id)
+{
+  char
+    path[MaxTextExtent];
+
+  DWORD
+    length;
+
+  HGLOBAL
+    global;
+
+  HMODULE
+    handle;
+
+  HRSRC
+    resource;
+
+  unsigned char
+    *blob,
+    *value;
+
+  assert(id != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",id);
+  (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",GetClientPath(),
+    DirectorySeparator,GetClientName());
+  if (IsPathAccessible(path) != MagickFalse)
+    handle=GetModuleHandle(path);
+  else
+    handle=GetModuleHandle(0);
+  if (!handle)
+    return((unsigned char *) NULL);
+  resource=FindResource(handle,id,"IMAGEMAGICK");
+  if (!resource)
+    return((unsigned char *) NULL);
+  global=LoadResource(handle,resource);
+  if (!global)
+    return((unsigned char *) NULL);
+  length=SizeofResource(handle,resource);
+  value=(unsigned char *) LockResource(global);
+  if (!value)
+    {
+      FreeResource(global);
+      return((unsigned char *) NULL);
+    }
+  blob=(unsigned char *) AcquireQuantumMemory(length+MaxTextExtent,
+    sizeof(*blob));
+  if (blob != (unsigned char *) NULL)
+    {
+      (void) CopyMagickMemory(blob,value,length);
+      blob[length]='\0';
+    }
+  UnlockResource(global);
+  FreeResource(global);
+  return(blob);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T S e e k D i r e c t o r y                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTSeekDirectory() sets the position of the next NTReadDirectory() operation
+%  on the directory stream.
+%
+%  The format of the NTSeekDirectory method is:
+%
+%      void NTSeekDirectory(DIR *entry,ssize_t position)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%    o position: specifies the position associated with the directory
+%      stream.
+%
+*/
+MagickExport void NTSeekDirectory(DIR *entry,ssize_t position)
+{
+  (void) position;
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(entry != (DIR *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T S e t S e a r c h P a t h                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTSetSearchPath() sets the current locations that the subsystem should
+%  look at to find dynamically loadable modules.
+%
+%  The format of the NTSetSearchPath method is:
+%
+%      int NTSetSearchPath(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: Specifies a pointer to string representing the search path
+%      for DLL's that can be dynamically loaded.
+%
+*/
+MagickExport int NTSetSearchPath(const char *path)
+{
+#if defined(MAGICKCORE_LTDL_DELEGATE)
+  lt_dlsetsearchpath(path);
+#else
+  if (lt_slsearchpath != (char *) NULL)
+    lt_slsearchpath=DestroyString(lt_slsearchpath);
+  if (path != (char *) NULL)
+    lt_slsearchpath=AcquireString(path);
+#endif
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  N T S y n c M e m o r y                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTSyncMemory() emulates the Unix method of the same name.
+%
+%  The format of the NTSyncMemory method is:
+%
+%      int NTSyncMemory(void *address,size_t length,int flags)
+%
+%  A description of each parameter follows:
+%
+%    o address: the address of the binary large object.
+%
+%    o length: the length of the binary large object.
+%
+%    o flags: Option flags (ignored for Windows).
+%
+*/
+MagickExport int NTSyncMemory(void *address,size_t length,int flags)
+{
+  (void) flags;
+  if (FlushViewOfFile(address,length) == MagickFalse)
+    return(-1);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T S y s t e m C o m m a n d                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTSystemCommand() executes the specified command and waits until it
+%  terminates.  The returned value is the exit status of the command.
+%
+%  The format of the NTSystemCommand method is:
+%
+%      int NTSystemCommand(MagickFalse,const char *command)
+%
+%  A description of each parameter follows:
+%
+%    o command: This string is the command to execute.
+%
+*/
+MagickExport int NTSystemCommand(const char *command)
+{
+  char
+    local_command[MaxTextExtent];
+
+  DWORD
+    child_status;
+
+  int
+    status;
+
+  MagickBooleanType
+    background_process;
+
+  PROCESS_INFORMATION
+    process_info;
+
+  STARTUPINFO
+    startup_info;
+
+  if (command == (char *) NULL)
+    return(-1);
+  GetStartupInfo(&startup_info);
+  startup_info.dwFlags=STARTF_USESHOWWINDOW;
+  startup_info.wShowWindow=SW_SHOWMINNOACTIVE;
+  (void) CopyMagickString(local_command,command,MaxTextExtent);
+  background_process=command[strlen(command)-1] == '&' ? MagickTrue :
+    MagickFalse;
+  if (background_process)
+    local_command[strlen(command)-1]='\0';
+  if (command[strlen(command)-1] == '|')
+     local_command[strlen(command)-1]='\0';
+   else
+     startup_info.wShowWindow=SW_SHOWDEFAULT;
+  status=CreateProcess((LPCTSTR) NULL,local_command,
+    (LPSECURITY_ATTRIBUTES) NULL,(LPSECURITY_ATTRIBUTES) NULL,(BOOL) FALSE,
+    (DWORD) NORMAL_PRIORITY_CLASS,(LPVOID) NULL,(LPCSTR) NULL,&startup_info,
+    &process_info);
+  if (status == 0)
+    return(-1);
+  if (background_process)
+    return(status == 0);
+  status=WaitForSingleObject(process_info.hProcess,INFINITE);
+  if (status != WAIT_OBJECT_0)
+    return(status);
+  status=GetExitCodeProcess(process_info.hProcess,&child_status);
+  if (status == 0)
+    return(-1);
+  CloseHandle(process_info.hProcess);
+  CloseHandle(process_info.hThread);
+  return((int) child_status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T S y s t e m C o n i f i g u r a t i o n                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTSystemConfiguration() provides a way for the application to determine
+%  values for system limits or options at runtime.
+%
+%  The format of the exit method is:
+%
+%      ssize_t NTSystemConfiguration(int name)
+%
+%  A description of each parameter follows:
+%
+%    o name: _SC_PAGE_SIZE or _SC_PHYS_PAGES.
+%
+*/
+MagickExport ssize_t NTSystemConfiguration(int name)
+{
+  switch (name)
+  {
+    case _SC_PAGESIZE:
+    {
+      SYSTEM_INFO
+        system_info;
+
+      GetSystemInfo(&system_info);
+      return(system_info.dwPageSize);
+    }
+    case _SC_PHYS_PAGES:
+    {
+      HMODULE
+        handle;
+
+      LPFNDLLFUNC2
+        module;
+
+      NTMEMORYSTATUSEX
+        status;
+
+      SYSTEM_INFO
+        system_info;
+
+      handle=GetModuleHandle("kernel32.dll");
+      if (handle == (HMODULE) NULL)
+        return(0L);
+      GetSystemInfo(&system_info);
+      module=(LPFNDLLFUNC2) NTGetLibrarySymbol(handle,"GlobalMemoryStatusEx");
+      if (module == (LPFNDLLFUNC2) NULL)
+        {
+          MEMORYSTATUS
+            status;
+
+          GlobalMemoryStatus(&status);
+          return((ssize_t) status.dwTotalPhys/system_info.dwPageSize);
+        }
+      status.dwLength=sizeof(status);
+      if (module(&status) == 0)
+        return(0L);
+      return((ssize_t) status.ullTotalPhys/system_info.dwPageSize);
+    }
+    case _SC_OPEN_MAX:
+      return(2048);
+    default:
+      break;
+  }
+  return(-1);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T T e l l D i r e c t o r y                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTTellDirectory() returns the current location associated with the named
+%  directory stream.
+%
+%  The format of the NTTellDirectory method is:
+%
+%      ssize_t NTTellDirectory(DIR *entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+*/
+MagickExport ssize_t NTTellDirectory(DIR *entry)
+{
+  assert(entry != (DIR *) NULL);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T T r u n c a t e F i l e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTTruncateFile() truncates a file to a specified length.
+%
+%  The format of the NTTruncateFile method is:
+%
+%      int NTTruncateFile(int file,off_t length)
+%
+%  A description of each parameter follows:
+%
+%    o file: the file.
+%
+%    o length: the file length.
+%
+*/
+MagickExport int NTTruncateFile(int file,off_t length)
+{
+  DWORD
+    file_pointer;
+
+  long
+    file_handle,
+    high,
+    low;
+
+  file_handle=_get_osfhandle(file);
+  if (file_handle == -1L)
+    return(-1);
+  low=(long) (length & 0xffffffffUL);
+  high=(long) ((((MagickOffsetType) length) >> 32) & 0xffffffffUL);
+  file_pointer=SetFilePointer((HANDLE) file_handle,low,&high,FILE_BEGIN);
+  if ((file_pointer == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
+    return(-1);
+  if (SetEndOfFile((HANDLE) file_handle) == 0)
+    return(-1);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  N T U n m a p M e m o r y                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTUnmapMemory() emulates the Unix munmap method.
+%
+%  The format of the NTUnmapMemory method is:
+%
+%      int NTUnmapMemory(void *map,size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o map: the address of the binary large object.
+%
+%    o length: the length of the binary large object.
+%
+*/
+MagickExport int NTUnmapMemory(void *map,size_t length)
+{
+  (void) length;
+  if (UnmapViewOfFile(map) == 0)
+    return(-1);
+  return(0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T U s e r T i m e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTUserTime() returns the total time the process has been scheduled (e.g.
+%  seconds) since the last call to StartTimer().
+%
+%  The format of the UserTime method is:
+%
+%      double NTUserTime(void)
+%
+*/
+MagickExport double NTUserTime(void)
+{
+  DWORD
+    status;
+
+  FILETIME
+    create_time,
+    exit_time;
+
+  OSVERSIONINFO
+    OsVersionInfo;
+
+  union
+  {
+    FILETIME
+      filetime;
+
+    __int64
+      filetime64;
+  } kernel_time;
+
+  union
+  {
+    FILETIME
+      filetime;
+
+    __int64
+      filetime64;
+  } user_time;
+
+  OsVersionInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
+  GetVersionEx(&OsVersionInfo);
+  if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
+    return(NTElapsedTime());
+  status=GetProcessTimes(GetCurrentProcess(),&create_time,&exit_time,
+    &kernel_time.filetime,&user_time.filetime);
+  if (status != TRUE)
+    return(0.0);
+  return((double) 1.0e-7*(kernel_time.filetime64+user_time.filetime64));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N T W a r n i n g H a n d l e r                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTWarningHandler() displays a warning reason.
+%
+%  The format of the NTWarningHandler method is:
+%
+%      void NTWarningHandler(const ExceptionType severity,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o severity: Specifies the numeric warning category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+MagickExport void NTWarningHandler(const ExceptionType severity,
+  const char *reason,const char *description)
+{
+  char
+    buffer[2*MaxTextExtent];
+
+  (void) severity;
+  if (reason == (char *) NULL)
+    return;
+  if (description == (char *) NULL)
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s.\n",GetClientName(),
+      reason);
+  else
+    (void) FormatLocaleString(buffer,MaxTextExtent,"%s: %s (%s).\n",
+      GetClientName(),reason,description);
+  (void) MessageBox(NULL,buffer,"ImageMagick Warning",MB_OK | MB_TASKMODAL |
+    MB_SETFOREGROUND | MB_ICONINFORMATION);
+}
+#endif
diff --git a/MagickCore/nt-base.h b/MagickCore/nt-base.h
new file mode 100644
index 0000000..b6778ac
--- /dev/null
+++ b/MagickCore/nt-base.h
@@ -0,0 +1,427 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore Windows NT utility methods.
+*/
+#ifndef _MAGICKCORE_NT_BASE_H
+#define _MAGICKCORE_NT_BASE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/delegate.h"
+#include "MagickCore/delegate-private.h"
+#include "MagickCore/exception.h"
+
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+#define _CRT_SECURE_NO_DEPRECATE  1
+#include <windows.h>
+#include <wchar.h>
+#include <winuser.h>
+#include <wingdi.h>
+#include <io.h>
+#include <process.h>
+#include <errno.h>
+#if defined(_DEBUG) && !defined(__MINGW32__)
+#include <crtdbg.h>
+#endif
+
+#define PROT_READ  0x01
+#define PROT_WRITE  0x02
+#define MAP_SHARED  0x01
+#define MAP_PRIVATE  0x02
+#define MAP_ANONYMOUS  0x20
+#define F_OK 0
+#define R_OK 4
+#define W_OK 2
+#define RW_OK 6
+#define _SC_PAGESIZE 1
+#define _SC_PHYS_PAGES 2
+#define _SC_OPEN_MAX 3
+#if !defined(SSIZE_MAX)
+#define SSIZE_MAX  0x7fffffffL
+#endif
+
+/*
+  _MSC_VER values:
+    1100 MSVC 5.0
+    1200 MSVC 6.0
+    1300 MSVC 7.0 Visual C++ .NET 2002
+    1310 Visual c++ .NET 2003
+    1400 Visual C++ 2005
+    1500 Visual C++ 2008
+*/
+
+#if !defined(chsize)
+# if defined(__BORLANDC__)
+#   define chsize(file,length)  chsize(file,length)
+# else
+#   define chsize(file,length)  _chsize(file,length)
+# endif
+#endif
+
+#if !defined(access)
+#  define access(path,mode)  _access_s(path,mode)
+#endif
+#if !defined(chdir)
+#  define chdir  _chdir
+#endif
+#if !defined(close)
+#  define close  _close
+#endif
+#if !defined(closedir)
+#  define closedir(directory)  NTCloseDirectory(directory)
+#endif
+#if !defined(fdopen)
+#  define fdopen  _fdopen
+#endif
+#if !defined(fileno)
+#  define fileno  _fileno
+#endif
+#if !defined(fseek) && !defined(__MINGW32__)
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define fseek  _fseeki64
+#else
+#  define fseek  _fseek
+#endif
+#endif
+#if !defined(fstat) && !defined(__BORLANDC__)
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define fstat  _fstati64
+#else
+#  define fstat  _fstat
+#endif
+#endif
+#if !defined(fsync)
+#  define fsync  _commit
+#endif
+#if !defined(ftell) && !defined(__MINGW32__)
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define ftell  _ftelli64
+#else
+#  define ftell  _ftell
+#endif
+#endif
+#if !defined(ftruncate)
+#  define ftruncate(file,length)  NTTruncateFile(file,length)
+#endif
+#if !defined(getcwd)
+#  define getcwd  _getcwd
+#endif
+#if !defined(getpid)
+#  define getpid  _getpid
+#endif
+#if !defined(hypot)
+#  define hypot  _hypot
+#endif
+#if !defined(inline)
+#  define inline __inline
+#endif
+#if !defined(isatty)
+#  define isatty _isatty
+#endif
+#if !defined(locale_t)
+#define locale_t _locale_t
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define lseek  _lseeki64
+#else
+#  define lseek  _lseek
+#endif
+#if !defined(MAGICKCORE_LTDL_DELEGATE)
+#if !defined(lt_dlclose)
+#  define lt_dlclose(handle)  NTCloseLibrary(handle)
+#endif
+#if !defined(lt_dlerror)
+#  define lt_dlerror()  NTGetLibraryError()
+#endif
+#if !defined(lt_dlexit)
+#  define lt_dlexit()  NTExitLibrary()
+#endif
+#if !defined(lt_dlinit)
+#  define lt_dlinit()  NTInitializeLibrary()
+#endif
+#if !defined(lt_dlopen)
+#  define lt_dlopen(filename)  NTOpenLibrary(filename)
+#endif
+#if !defined(lt_dlsetsearchpath)
+#  define lt_dlsetsearchpath(path)  NTSetSearchPath(path)
+#endif
+#if !defined(lt_dlsym)
+#  define lt_dlsym(handle,name)  NTGetLibrarySymbol(handle,name)
+#endif
+#endif
+#if !defined(mkdir)
+#  define mkdir  _mkdir
+#endif
+#if !defined(mmap)
+#  define mmap(address,length,protection,access,file,offset) \
+  NTMapMemory(address,length,protection,access,file,offset)
+#endif
+#if !defined(msync)
+#  define msync(address,length,flags)  NTSyncMemory(address,length,flags)
+#endif
+#if !defined(munmap)
+#  define munmap(address,length)  NTUnmapMemory(address,length)
+#endif
+#if !defined(opendir)
+#  define opendir(directory)  NTOpenDirectory(directory)
+#endif
+#if !defined(open)
+#  define open  _open
+#endif
+#if !defined(pclose)
+#  define pclose  _pclose
+#endif
+#if !defined(popen)
+#  define popen  _popen
+#endif
+#if !defined(fprintf_l)
+#define fprintf_l  _fprintf_s_l
+#endif
+#if !defined(read)
+#  define read  _read
+#endif
+#if !defined(readdir)
+#  define readdir(directory)  NTReadDirectory(directory)
+#endif
+#if !defined(seekdir)
+#  define seekdir(directory,offset)  NTSeekDirectory(directory,offset)
+#endif
+#if !defined(setmode)
+#  define setmode  _setmode
+#endif
+#if !defined(spawnvp)
+#  define spawnvp  _spawnvp
+#endif
+#if !defined(strtod_l)
+#define strtod_l  _strtod_l
+#endif
+#if !defined(stat) && !defined(__BORLANDC__)
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define stat  _stati64
+#else
+#  define stat  _stat
+#endif
+#endif
+#if !defined(strcasecmp)
+#  define strcasecmp  _strcmpi
+#endif
+#if !defined(strncasecmp)
+#  define strncasecmp  _strnicmp
+#endif
+#if !defined(sysconf)
+#  define sysconf(name)  NTSystemConfiguration(name)
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define tell  _telli64
+#else
+#  define tell  _tell
+#endif
+#if !defined(telldir)
+#  define telldir(directory)  NTTellDirectory(directory)
+#endif
+#if !defined(tempnam)
+#  define tempnam  _tempnam_s
+#endif
+#if !defined(vfprintf_l)
+#define vfprintf_l  _vfprintf_l
+#endif
+#if !defined(vsnprintf)
+#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1500)
+#define vsnprintf _vsnprintf 
+#endif
+#endif
+#if !defined(vsnprintf_l)
+#define vsnprintf_l  _vsnprintf_l
+#endif
+#if !defined(write)
+#  define write  _write
+#endif
+#if !defined(wstat) && !defined(__BORLANDC__)
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(Windows95) && \
+  !(defined(_MSC_VER) && (_MSC_VER < 1400)) && (__MSVCRT_VERSION__ < 0x800)
+#  define wstat  _wstati64
+#else
+#  define wstat  _wstat
+#endif
+#endif
+
+#if defined(_MT) && defined(MAGICKCORE_WINDOWS_SUPPORT)
+#  define SAFE_GLOBAL  __declspec(thread)
+#else
+#  define SAFE_GLOBAL
+#endif
+
+#if defined(__BORLANDC__)
+#undef _O_RANDOM
+#define _O_RANDOM 0
+#undef _O_SEQUENTIAL
+#define _O_SEQUENTIAL 0
+#undef _O_SHORT_LIVED
+#define _O_SHORT_LIVED 0
+#undef _O_TEMPORARY
+#define _O_TEMPORARY 0
+#endif
+
+#if !defined(XS_VERSION)
+struct dirent
+{
+  char
+    d_name[2048];
+
+  int
+    d_namlen;
+};
+
+typedef struct _DIR
+{
+  HANDLE
+    hSearch;
+
+  WIN32_FIND_DATA
+    Win32FindData;
+
+  BOOL
+    firsttime;
+
+  struct dirent
+    file_info;
+} DIR;
+
+typedef struct _NTMEMORYSTATUSEX
+{
+  DWORD
+    dwLength,
+    dwMemoryLoad;
+
+  DWORDLONG
+    ullTotalPhys,
+    ullAvailPhys,
+    ullTotalPageFile,
+    ullAvailPageFile,
+    ullTotalVirtual,
+    ullAvailVirtual,
+    ullAvailExtendedVirtual;
+} NTMEMORYSTATUSEX;
+
+#if !defined(__MINGW32__)
+struct timezone
+{
+  int
+    tz_minuteswest,
+    tz_dsttime;
+};
+#endif
+
+typedef UINT
+  (CALLBACK *LPFNDLLFUNC1)(DWORD,UINT);
+
+typedef UINT
+  (CALLBACK *LPFNDLLFUNC2)(NTMEMORYSTATUSEX *);
+
+#endif
+
+#if defined(MAGICKCORE_BZLIB_DELEGATE)
+#  if defined(_WIN32)
+#    define BZ_IMPORT 1
+#  endif
+#endif
+
+extern MagickExport char
+  *NTGetLastError(void);
+
+extern MagickExport const GhostInfo
+  *NTGhostscriptDLLVectors(void);
+
+#if !defined(MAGICKCORE_LTDL_DELEGATE)
+extern MagickExport const char
+  *NTGetLibraryError(void);
+#endif
+
+#if !defined(XS_VERSION)
+extern MagickExport const char
+  *NTGetLibraryError(void);
+
+extern MagickExport DIR
+  *NTOpenDirectory(const char *);
+
+extern MagickExport double
+  NTElapsedTime(void),
+  NTUserTime(void);
+
+extern MagickExport int
+  Exit(int),
+#if !defined(__MINGW32__)
+  gettimeofday(struct timeval *,struct timezone *),
+#endif
+  IsWindows95(),
+  NTCloseDirectory(DIR *),
+  NTCloseLibrary(void *),
+  NTControlHandler(void),
+  NTExitLibrary(void),
+  NTTruncateFile(int,off_t),
+  NTGhostscriptDLL(char *,int),
+  NTGhostscriptEXE(char *,int),
+  NTGhostscriptFonts(char *,int),
+  NTGhostscriptLoadDLL(void),
+  NTGhostscriptUnLoadDLL(void),
+  NTInitializeLibrary(void),
+  NTSetSearchPath(const char *),
+  NTSyncMemory(void *,size_t,int),
+  NTUnmapMemory(void *,size_t),
+  NTSystemCommand(const char *);
+
+extern MagickExport ssize_t
+  NTSystemConfiguration(int),
+  NTTellDirectory(DIR *);
+
+extern MagickExport MagickBooleanType
+  NTGatherRandomData(const size_t,unsigned char *),
+  NTGetExecutionPath(char *,const size_t),
+  NTGetModulePath(const char *,char *),
+  NTReportEvent(const char *,const MagickBooleanType),
+  NTReportException(const char *,const MagickBooleanType);
+
+extern MagickExport struct dirent
+  *NTReadDirectory(DIR *);
+
+extern MagickExport unsigned char
+  *NTRegistryKeyLookup(const char *),
+  *NTResourceToBlob(const char *);
+
+extern MagickExport void
+  NTErrorHandler(const ExceptionType,const char *,const char *),
+  *NTGetLibrarySymbol(void *,const char *),
+  *NTMapMemory(char *,size_t,int,int,int,MagickOffsetType),
+  *NTOpenLibrary(const char *),
+  NTSeekDirectory(DIR *,ssize_t),
+  NTWarningHandler(const ExceptionType,const char *,const char *);
+
+#endif /* !XS_VERSION */
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif /* !C++ */
+
+#endif /* !_MAGICKCORE_NT_BASE_H */
diff --git a/MagickCore/nt-feature.c b/MagickCore/nt-feature.c
new file mode 100644
index 0000000..98391ab
--- /dev/null
+++ b/MagickCore/nt-feature.c
@@ -0,0 +1,672 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                 N   N  TTTTT                                %
+%                                 NN  N    T                                  %
+%                                 N N N    T                                  %
+%                                 N  NN    T                                  %
+%                                 N   N    T                                  %
+%                                                                             %
+%                                                                             %
+%                   Windows NT Feature Methods for MagickCore                 %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                December 1996                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+#include <windows.h>
+#include "MagickCore/cache.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/nt-feature.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C r o p I m a g e T o H B i t m a p                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CropImageToHBITMAP() extracts a specified region of the image and returns
+%  it as a Windows HBITMAP. While the same functionality can be accomplished by
+%  invoking CropImage() followed by ImageToHBITMAP(), this method is more
+%  efficient since it copies pixels directly to the HBITMAP.
+%
+%  The format of the CropImageToHBITMAP method is:
+%
+%      HBITMAP CropImageToHBITMAP(Image* image,const RectangleInfo *geometry,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o geometry: Define the region of the image to crop with members
+%      x, y, width, and height.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport void *CropImageToHBITMAP(Image *image,
+  const RectangleInfo *geometry,ExceptionInfo *exception)
+{
+#define CropImageTag  "Crop/Image"
+
+  BITMAP
+    bitmap;
+
+  HBITMAP
+    bitmapH;
+
+  HANDLE
+    bitmap_bitsH;
+
+  MagickBooleanType
+    proceed;
+
+  RectangleInfo
+    page;
+
+  register const Quantum
+    *p;
+
+  register RGBQUAD
+    *q;
+
+  RGBQUAD
+    *bitmap_bits;
+
+  ssize_t
+    y;
+
+  /*
+    Check crop geometry.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(geometry != (const RectangleInfo *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (((geometry->x+(ssize_t) geometry->width) < 0) ||
+      ((geometry->y+(ssize_t) geometry->height) < 0) ||
+      (geometry->x >= (ssize_t) image->columns) ||
+      (geometry->y >= (ssize_t) image->rows))
+    ThrowImageException(OptionError,"GeometryDoesNotContainImage");
+  page=(*geometry);
+  if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
+    page.width=image->columns-page.x;
+  if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
+    page.height=image->rows-page.y;
+  if (page.x < 0)
+    {
+      page.width+=page.x;
+      page.x=0;
+    }
+  if (page.y < 0)
+    {
+      page.height+=page.y;
+      page.y=0;
+    }
+
+  if ((page.width == 0) || (page.height == 0))
+    ThrowImageException(OptionError,"GeometryDimensionsAreZero");
+  /*
+    Initialize crop image attributes.
+  */
+  bitmap.bmType         = 0;
+  bitmap.bmWidth        = (LONG) page.width;
+  bitmap.bmHeight       = (LONG) page.height;
+  bitmap.bmWidthBytes   = bitmap.bmWidth * 4;
+  bitmap.bmPlanes       = 1;
+  bitmap.bmBitsPixel    = 32;
+  bitmap.bmBits         = NULL;
+
+  bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,page.width*
+    page.height*bitmap.bmBitsPixel);
+  if (bitmap_bitsH == NULL)
+    return(NULL);
+  bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
+  if ( bitmap.bmBits == NULL )
+    bitmap.bmBits = bitmap_bits;
+  if (image->colorspace != RGBColorspace)
+    TransformImageColorspace(image,RGBColorspace);
+  /*
+    Extract crop image.
+  */
+  q=bitmap_bits;
+  for (y=0; y < (ssize_t) page.height; y++)
+  {
+    p=GetVirtualPixels(image,page.x,page.y+y,page.width,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+
+#if MAGICKCORE_QUANTUM_DEPTH == 8
+      /* Form of PixelPacket is identical to RGBQUAD when MAGICKCORE_QUANTUM_DEPTH==8 */
+      CopyMagickMemory((void*)q,(const void*)p,page.width*sizeof(PixelPacket));
+      q += page.width;
+
+#else  /* 16 or 32 bit Quantum */
+      {
+        ssize_t
+          x;
+
+        /* Transfer pixels, scaling to Quantum */
+        for( x=(ssize_t) page.width ; x> 0 ; x-- )
+          {
+            q->rgbRed = ScaleQuantumToChar(GetPixelRed(image,p));
+            q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image,p));
+            q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image,p));
+            q->rgbReserved = 0;
+            ++q;
+            ++p;
+          }
+      }
+#endif
+    proceed=SetImageProgress(image,CropImageTag,y,page.height);
+    if (proceed == MagickFalse)
+      break;
+  }
+  if (y < (ssize_t) page.height)
+    {
+      GlobalUnlock((HGLOBAL) bitmap_bitsH);
+      GlobalFree((HGLOBAL) bitmap_bitsH);
+      return((void *) NULL);
+    }
+  bitmap.bmBits=bitmap_bits;
+  bitmapH=CreateBitmapIndirect(&bitmap);
+  GlobalUnlock((HGLOBAL) bitmap_bitsH);
+  GlobalFree((HGLOBAL) bitmap_bitsH);
+  return((void *) bitmapH);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s M a g i c k C o n f l i c t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMagickConflict() returns true if the image format conflicts with a logical
+%  drive (.e.g. X:).
+%
+%  The format of the IsMagickConflict method is:
+%
+%      MagickBooleanType IsMagickConflict(const char *magick)
+%
+%  A description of each parameter follows:
+%
+%    o magick: Specifies the image format.
+%
+*/
+MagickExport MagickBooleanType NTIsMagickConflict(const char *magick)
+{
+  MagickBooleanType
+    status;
+
+  assert(magick != (char *) NULL);
+  if (strlen(magick) > 1)
+    return(MagickFalse);
+  status=(GetLogicalDrives() & (1 << ((toupper((int) (*magick)))-'A'))) != 0 ?
+    MagickTrue : MagickFalse;
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   N T G e t T y pe L i s t                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NTLoadTypeLists() loads a Windows TrueType fonts.
+%
+%  The format of the NTLoadTypeLists method is:
+%
+%      MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list)
+%
+%  A description of each parameter follows:
+%
+%    o type_list: A linked list of fonts.
+%
+*/
+MagickExport MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list,
+  ExceptionInfo *exception)
+{
+  HKEY
+    reg_key = (HKEY) INVALID_HANDLE_VALUE;
+
+  LONG
+    res;
+
+
+  int
+    list_entries = 0;
+
+  char
+    buffer[MaxTextExtent],
+    system_root[MaxTextExtent],
+    font_root[MaxTextExtent];
+
+  DWORD
+    type,
+    system_root_length;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Try to find the right Windows*\CurrentVersion key, the SystemRoot and
+    then the Fonts key
+  */
+  res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
+    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &reg_key);
+  if (res == ERROR_SUCCESS) {
+    system_root_length=sizeof(system_root)-1;
+    res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type,
+      (BYTE*) system_root, &system_root_length);
+  }
+  if (res != ERROR_SUCCESS) {
+    res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
+      "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &reg_key);
+    if (res == ERROR_SUCCESS) {
+      system_root_length=sizeof(system_root)-1;
+      res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type,
+        (BYTE*)system_root, &system_root_length);
+    }
+  }
+  if (res == ERROR_SUCCESS)
+    res = RegOpenKeyExA (reg_key, "Fonts",0, KEY_READ, &reg_key);
+  if (res != ERROR_SUCCESS)
+    return(MagickFalse);
+  *font_root='\0';
+  (void) CopyMagickString(buffer,system_root,MaxTextExtent);
+  (void) ConcatenateMagickString(buffer,"\\fonts\\arial.ttf",MaxTextExtent);
+  if (IsPathAccessible(buffer) != MagickFalse)
+    {
+      (void) CopyMagickString(font_root,system_root,MaxTextExtent);
+      (void) ConcatenateMagickString(font_root,"\\fonts\\",MaxTextExtent);
+    }
+  else
+    {
+      (void) CopyMagickString(font_root,system_root,MaxTextExtent);
+      (void) ConcatenateMagickString(font_root,"\\",MaxTextExtent);
+    }
+
+  {
+    TypeInfo
+      *type_info;
+
+    DWORD
+      registry_index = 0,
+      type,
+      value_data_size,
+      value_name_length;
+
+    char
+      value_data[MaxTextExtent],
+      value_name[MaxTextExtent];
+
+    res = ERROR_SUCCESS;
+
+    while (res != ERROR_NO_MORE_ITEMS)
+      {
+        char
+          *family_extent,
+          token[MaxTextExtent],
+          *pos,
+          *q;
+
+        value_name_length = sizeof(value_name) - 1;
+        value_data_size = sizeof(value_data) - 1;
+        res = RegEnumValueA ( reg_key, registry_index, value_name,
+          &value_name_length, 0, &type, (BYTE*)value_data, &value_data_size);
+        registry_index++;
+        if (res != ERROR_SUCCESS)
+          continue;
+        if ( (pos = strstr(value_name, " (TrueType)")) == (char*) NULL )
+          continue;
+        *pos='\0'; /* Remove (TrueType) from string */
+
+        type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
+        if (type_info == (TypeInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(type_info,0,sizeof(TypeInfo));
+
+        type_info->path=ConstantString("Windows Fonts");
+        type_info->signature=MagickSignature;
+
+        /* Name */
+        (void) CopyMagickString(buffer,value_name,MaxTextExtent);
+        for(pos = buffer; *pos != 0 ; pos++)
+          if (*pos == ' ')
+            *pos = '-';
+        type_info->name=ConstantString(buffer);
+
+        /* Fullname */
+        type_info->description=ConstantString(value_name);
+
+        /* Format */
+        type_info->format=ConstantString("truetype");
+
+        /* Glyphs */
+        if (strchr(value_data,'\\') != (char *) NULL)
+          (void) CopyMagickString(buffer,value_data,MaxTextExtent);
+        else
+          {
+            (void) CopyMagickString(buffer,font_root,MaxTextExtent);
+            (void) ConcatenateMagickString(buffer,value_data,MaxTextExtent);
+          }
+
+        LocaleLower(buffer);
+        type_info->glyphs=ConstantString(buffer);
+
+        type_info->stretch=NormalStretch;
+        type_info->style=NormalStyle;
+        type_info->weight=400;
+
+        /* Some fonts are known to require special encodings */
+        if ( (LocaleCompare(type_info->name, "Symbol") == 0 ) ||
+             (LocaleCompare(type_info->name, "Wingdings") == 0 ) ||
+             (LocaleCompare(type_info->name, "Wingdings-2") == 0 ) ||
+             (LocaleCompare(type_info->name, "Wingdings-3") == 0 ) )
+          type_info->encoding=ConstantString("AppleRoman");
+
+        family_extent=value_name;
+
+        for (q=value_name; *q != '\0'; )
+          {
+            GetMagickToken(q,(const char **) &q,token);
+            if (*token == '\0')
+              break;
+
+            if (LocaleCompare(token,"Italic") == 0)
+              {
+                type_info->style=ItalicStyle;
+              }
+
+            else if (LocaleCompare(token,"Oblique") == 0)
+              {
+                type_info->style=ObliqueStyle;
+              }
+
+            else if (LocaleCompare(token,"Bold") == 0)
+              {
+                type_info->weight=700;
+              }
+
+            else if (LocaleCompare(token,"Thin") == 0)
+              {
+                type_info->weight=100;
+              }
+
+            else if ( (LocaleCompare(token,"ExtraLight") == 0) ||
+                      (LocaleCompare(token,"UltraLight") == 0) )
+              {
+                type_info->weight=200;
+              }
+
+            else if (LocaleCompare(token,"Light") == 0)
+              {
+                type_info->weight=300;
+              }
+
+            else if ( (LocaleCompare(token,"Normal") == 0) ||
+                      (LocaleCompare(token,"Regular") == 0) )
+              {
+                type_info->weight=400;
+              }
+
+            else if (LocaleCompare(token,"Medium") == 0)
+              {
+                type_info->weight=500;
+              }
+
+            else if ( (LocaleCompare(token,"SemiBold") == 0) ||
+                      (LocaleCompare(token,"DemiBold") == 0) )
+              {
+                type_info->weight=600;
+              }
+
+            else if ( (LocaleCompare(token,"ExtraBold") == 0) ||
+                      (LocaleCompare(token,"UltraBold") == 0) )
+              {
+                type_info->weight=800;
+              }
+
+            else if ( (LocaleCompare(token,"Heavy") == 0) ||
+                      (LocaleCompare(token,"Black") == 0) )
+              {
+                type_info->weight=900;
+              }
+
+            else if (LocaleCompare(token,"Condensed") == 0)
+              {
+                type_info->stretch = CondensedStretch;
+              }
+
+            else if (LocaleCompare(token,"Expanded") == 0)
+              {
+                type_info->stretch = ExpandedStretch;
+              }
+
+            else if (LocaleCompare(token,"ExtraCondensed") == 0)
+              {
+                type_info->stretch = ExtraCondensedStretch;
+              }
+
+            else if (LocaleCompare(token,"ExtraExpanded") == 0)
+              {
+                type_info->stretch = ExtraExpandedStretch;
+              }
+
+            else if (LocaleCompare(token,"SemiCondensed") == 0)
+              {
+                type_info->stretch = SemiCondensedStretch;
+              }
+
+            else if (LocaleCompare(token,"SemiExpanded") == 0)
+              {
+                type_info->stretch = SemiExpandedStretch;
+              }
+
+            else if (LocaleCompare(token,"UltraCondensed") == 0)
+              {
+                type_info->stretch = UltraCondensedStretch;
+              }
+
+            else if (LocaleCompare(token,"UltraExpanded") == 0)
+              {
+                type_info->stretch = UltraExpandedStretch;
+              }
+
+            else
+              {
+                family_extent=q;
+              }
+          }
+
+        (void) CopyMagickString(buffer,value_name,family_extent-value_name+1);
+        StripString(buffer);
+        type_info->family=ConstantString(buffer);
+
+        list_entries++;
+        status=AddValueToSplayTree(type_list,ConstantString(type_info->name),
+          type_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
+      }
+  }
+  RegCloseKey ( reg_key );
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I m a g e T o H B i t m a p                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImageToHBITMAP() creates a Windows HBITMAP from an image.
+%
+%  The format of the ImageToHBITMAP method is:
+%
+%      HBITMAP ImageToHBITMAP(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to convert.
+%
+*/
+MagickExport void *ImageToHBITMAP(Image *image)
+{
+  BITMAP
+    bitmap;
+
+  ExceptionInfo
+    *exception;
+
+  HANDLE
+    bitmap_bitsH;
+
+  HBITMAP
+    bitmapH;
+
+  register ssize_t
+    x;
+
+  register const Quantum
+    *p;
+
+  register RGBQUAD
+    *q;
+
+  RGBQUAD
+    *bitmap_bits;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  (void) ResetMagickMemory(&bitmap,0,sizeof(bitmap));
+  bitmap.bmType=0;
+  bitmap.bmWidth=(LONG) image->columns;
+  bitmap.bmHeight=(LONG) image->rows;
+  bitmap.bmWidthBytes=4*bitmap.bmWidth;
+  bitmap.bmPlanes=1;
+  bitmap.bmBitsPixel=32;
+  bitmap.bmBits=NULL;
+  length=bitmap.bmWidthBytes*bitmap.bmHeight;
+  bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,length);
+  if (bitmap_bitsH == NULL)
+    {
+      char
+        *message;
+
+      message=GetExceptionMessage(errno);
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
+      message=DestroyString(message);
+      return(NULL);
+    }
+  bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
+  q=bitmap_bits;
+  if (bitmap.bmBits == NULL)
+    bitmap.bmBits=bitmap_bits;
+  (void) TransformImageColorspace(image,RGBColorspace);
+  exception=(&image->exception);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      q->rgbRed=ScaleQuantumToChar(GetPixelRed(image,p));
+      q->rgbGreen=ScaleQuantumToChar(GetPixelGreen(image,p));
+      q->rgbBlue=ScaleQuantumToChar(GetPixelBlue(image,p));
+      q->rgbReserved=0;
+      p+=GetPixelChannels(image);
+      q++;
+    }
+  }
+  bitmap.bmBits=bitmap_bits;
+  bitmapH=CreateBitmapIndirect(&bitmap);
+  if (bitmapH == NULL)
+    {
+      char
+        *message;
+
+      message=GetExceptionMessage(errno);
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
+      message=DestroyString(message);
+    }
+  GlobalUnlock((HGLOBAL) bitmap_bitsH);
+  GlobalFree((HGLOBAL) bitmap_bitsH);
+  return((void *) bitmapH);
+}
+
+#endif
diff --git a/MagickCore/nt-feature.h b/MagickCore/nt-feature.h
new file mode 100644
index 0000000..3a44263
--- /dev/null
+++ b/MagickCore/nt-feature.h
@@ -0,0 +1,43 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore Windows NT utility methods.
+*/
+#ifndef _MAGICKCORE_NT_FEATURE_H
+#define _MAGICKCORE_NT_FEATURE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/splay-tree.h"
+
+extern MagickExport void
+  *CropImageToHBITMAP(Image *,const RectangleInfo *,ExceptionInfo *),
+  *ImageToHBITMAP(Image *);
+
+#if !defined(XS_VERSION)
+
+extern MagickExport MagickBooleanType
+  NTIsMagickConflict(const char *),
+  NTLoadTypeLists(SplayTreeInfo *,ExceptionInfo *);
+
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/option.c b/MagickCore/option.c
new file mode 100644
index 0000000..37cfb26
--- /dev/null
+++ b/MagickCore/option.c
@@ -0,0 +1,2528 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                   OOO   PPPP   TTTTT  IIIII   OOO   N   N                   %
+%                  O   O  P   P    T      I    O   O  NN  N                   %
+%                  O   O  PPPP     T      I    O   O  N N N                   %
+%                  O   O  P        T      I    O   O  N  NN                   %
+%                   OOO   P        T    IIIII   OOO   N   N                   %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Option Methods                           %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 March 2000                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/compare.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/distort.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/mime-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/morphology.h"
+#include "MagickCore/option.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+
+/*
+  ImageMagick options.
+*/
+static const OptionInfo
+  AlignOptions[] =
+  {
+    { "Undefined", UndefinedAlign, UndefinedOptionFlag, MagickTrue },
+    { "Center", CenterAlign, UndefinedOptionFlag, MagickFalse },
+    { "End", RightAlign, UndefinedOptionFlag, MagickFalse },
+    { "Left", LeftAlign, UndefinedOptionFlag, MagickFalse },
+    { "Middle", CenterAlign, UndefinedOptionFlag, MagickFalse },
+    { "Right", RightAlign, UndefinedOptionFlag, MagickFalse },
+    { "Start", LeftAlign, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedAlign, UndefinedOptionFlag, MagickFalse }
+  },
+  AlphaOptions[] =
+  {
+    { "Undefined", UndefinedAlphaChannel, UndefinedOptionFlag, MagickTrue },
+    { "Activate", ActivateAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Background", BackgroundAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Copy", CopyAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Deactivate", DeactivateAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Extract", ExtractAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Off", DeactivateAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "On", ActivateAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Opaque", OpaqueAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Set", SetAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Shape", ShapeAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Reset", SetAlphaChannel, DeprecateOptionFlag, MagickTrue },
+    { "Transparent", TransparentAlphaChannel, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedAlphaChannel, UndefinedOptionFlag, MagickFalse }
+  },
+  BooleanOptions[] =
+  {
+    { "False", 0L, UndefinedOptionFlag, MagickFalse },
+    { "True", 1L, UndefinedOptionFlag, MagickFalse },
+    { "0", 0L, UndefinedOptionFlag, MagickFalse },
+    { "1", 1L, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, 0L, UndefinedOptionFlag, MagickFalse }
+  },
+  ChannelOptions[] =
+  {
+    { "Undefined", UndefinedChannel, UndefinedOptionFlag, MagickTrue },
+    { "All", CompositeChannels, UndefinedOptionFlag, MagickFalse },
+    { "Alpha", OpacityChannel, UndefinedOptionFlag, MagickFalse },
+    { "Black", BlackChannel, UndefinedOptionFlag, MagickFalse },
+    { "Blue", BlueChannel, UndefinedOptionFlag, MagickFalse },
+    { "Cyan", CyanChannel, UndefinedOptionFlag, MagickFalse },
+    { "Default", DefaultChannels, UndefinedOptionFlag, MagickFalse },
+    { "Gray", GrayChannel, UndefinedOptionFlag, MagickFalse },
+    { "Green", GreenChannel, UndefinedOptionFlag, MagickFalse },
+    { "Hue", RedChannel, UndefinedOptionFlag, MagickFalse },
+    { "Lightness", BlueChannel, UndefinedOptionFlag, MagickFalse },
+    { "Luminance", BlueChannel, UndefinedOptionFlag, MagickFalse },
+    { "Luminosity", BlueChannel, DeprecateOptionFlag, MagickTrue },
+    { "Magenta", MagentaChannel, UndefinedOptionFlag, MagickFalse },
+    { "Matte", OpacityChannel, UndefinedOptionFlag, MagickFalse },
+    { "Opacity", OpacityChannel, UndefinedOptionFlag, MagickFalse },
+    { "Red", RedChannel, UndefinedOptionFlag, MagickFalse },
+    { "Saturation", GreenChannel, UndefinedOptionFlag, MagickFalse },
+    { "Yellow", YellowChannel, UndefinedOptionFlag, MagickFalse },
+    { "Sync", SyncChannels, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedChannel, UndefinedOptionFlag, MagickFalse }
+  },
+  ClassOptions[] =
+  {
+    { "Undefined", UndefinedClass, UndefinedOptionFlag, MagickTrue },
+    { "DirectClass", DirectClass, UndefinedOptionFlag, MagickFalse },
+    { "PseudoClass", PseudoClass, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedClass, UndefinedOptionFlag, MagickFalse }
+  },
+  ClipPathOptions[] =
+  {
+    { "Undefined", UndefinedPathUnits, UndefinedOptionFlag, MagickTrue },
+    { "ObjectBoundingBox", ObjectBoundingBox, UndefinedOptionFlag, MagickFalse },
+    { "UserSpace", UserSpace, UndefinedOptionFlag, MagickFalse },
+    { "UserSpaceOnUse", UserSpaceOnUse, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedPathUnits, UndefinedOptionFlag, MagickFalse }
+  },
+  CommandOptions[] =
+  {
+    { "+adjoin", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-adjoin", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+adaptive-blur", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-adaptive-blur", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+adaptive-resize", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-adaptive-resize", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+adaptive-sharpen", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-adaptive-sharpen", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+affine", 0L, DrawInfoOptionFlag, MagickFalse },
+    { "-affine", 1L, DrawInfoOptionFlag, MagickFalse },
+    { "+affinity", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-affinity", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "+alpha", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-alpha", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+annotate", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-annotate", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+antialias", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-antialias", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+append", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-append", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+attenuate", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-attenuate", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+authenticate", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-authenticate", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+auto-gamma", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-auto-gamma", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+auto-level", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-auto-level", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+auto-orient", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-auto-orient", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+average", 0L, ListOperatorOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-average", 0L, ListOperatorOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+backdrop", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-backdrop", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+background", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-background", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+bench", 0L, GenesisOptionFlag, MagickFalse },
+    { "-bench", 1L, GenesisOptionFlag, MagickFalse },
+    { "+bias", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-bias", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+black-point-compensation", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-black-point-compensation", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+black-threshold", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-black-threshold", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+blend", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-blend", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+blue-primary", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-blue-primary", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+blue-shift", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-blue-shift", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+blur", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-blur", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+border", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-border", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+bordercolor", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-bordercolor", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+borderwidth", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-borderwidth", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+box", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-box", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+brightness-contrast", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-brightness-contrast", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+cache", 0L, GlobalOptionFlag, MagickFalse },
+    { "-cache", 1L, GlobalOptionFlag, MagickFalse },
+    { "+cdl", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-cdl", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+channel", 0L, ImageInfoOptionFlag | ListOperatorOptionFlag, MagickFalse },
+    { "-channel", 1L, ImageInfoOptionFlag | ListOperatorOptionFlag, MagickFalse },
+    { "+charcoal", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-charcoal", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+chop", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-chop", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+clamp", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-clamp", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+clip", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-clip", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+clip-mask", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-clip-mask", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+clip-path", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-clip-path", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+clone", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-clone", 1L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+clut", 0L, FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-clut", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+coalesce", 0L, FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-coalesce", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+colorize", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-colorize", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+colormap", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-colormap", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+color-matrix", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-color-matrix", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+colors", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-colors", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+colorspace", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "-colorspace", 1L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "+combine", 0L, FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-combine", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+comment", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-comment", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+compose", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-compose", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+composite", 0L, FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-composite", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+compress", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-compress", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+concurrent", 0L, GenesisOptionFlag, MagickTrue },
+    { "-concurrent", 0L, GenesisOptionFlag, MagickTrue },
+    { "+contrast", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-contrast", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+contrast-stretch", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-contrast-stretch", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+convolve", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-convolve", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+crop", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-crop", 1L, SimpleOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+cycle", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-cycle", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+debug", 0L, GlobalOptionFlag|GenesisOptionFlag | FireOptionFlag, MagickFalse },
+    { "-debug", 1L, GlobalOptionFlag|GenesisOptionFlag | FireOptionFlag, MagickFalse },
+    { "+decipher", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-decipher", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+deconstruct", 0L, FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-deconstruct", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+define", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "-define", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+delay", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-delay", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+delete", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-delete", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+density", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-density", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+depth", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-depth", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+descend", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-descend", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+deskew", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-deskew", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+despeckle", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-despeckle", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+direction", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-direction", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+displace", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-displace", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+display", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "-display", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+dispose", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-dispose", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+dissolve", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-dissolve", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+distort", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-distort", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+dither", 0L, ListOperatorOptionFlag | ImageInfoOptionFlag | QuantizeInfoOptionFlag, MagickFalse },
+    { "-dither", 1L, ListOperatorOptionFlag | ImageInfoOptionFlag | QuantizeInfoOptionFlag, MagickFalse },
+    { "+draw", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-draw", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+duplicate", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-duplicate", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+duration", 1L, GenesisOptionFlag, MagickFalse },
+    { "-duration", 1L, GenesisOptionFlag, MagickFalse },
+    { "+edge", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-edge", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+emboss", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-emboss", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+encipher", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-encipher", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+encoding", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-encoding", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+endian", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-endian", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+enhance", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-enhance", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+equalize", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-equalize", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+evaluate", 2L, DeprecateOptionFlag, MagickFalse },
+    { "-evaluate", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+evaluate-sequence", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-evaluate-sequence", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+extent", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-extent", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+extract", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-extract", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+family", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-family", 1L, DrawInfoOptionFlag, MagickFalse },
+    { "+features", 0L, SimpleOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-features", 1L, SimpleOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+fft", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-fft", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+fill", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-fill", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+filter", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-filter", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+flatten", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-flatten", 0L, ListOperatorOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+flip", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-flip", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+flop", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-flop", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+floodfill", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-floodfill", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+font", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-font", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+foreground", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-foreground", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+format", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-format", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+frame", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-frame", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+fuzz", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-fuzz", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+fx", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-fx", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+gamma", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-gamma", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+gaussian", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-gaussian", 1L, SimpleOperatorOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+gaussian-blur", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-gaussian-blur", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+geometry", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-geometry", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+gravity", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-gravity", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+green-primary", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-green-primary", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+hald-clut", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-hald-clut", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+help", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-help", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+highlight-color", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-highlight-color", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+iconGeometry", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-iconGeometry", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+iconic", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-iconic", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+identify", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-identify", 0L, SimpleOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+ift", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-ift", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+immutable", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-immutable", 0L, NonConvertOptionFlag, MagickFalse },
+    { "+implode", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-implode", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+insert", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-insert", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+intent", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-intent", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+interlace", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-interlace", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+interline-spacing", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-interline-spacing", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+interpolate", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-interpolate", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+interword-spacing", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-interword-spacing", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+kerning", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-kerning", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+label", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-label", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+lat", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-lat", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+layers", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-layers", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+level", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-level", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+level-colors", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-level-colors", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+limit", 0L, GlobalOptionFlag | FireOptionFlag, MagickFalse },
+    { "-limit", 2L, GlobalOptionFlag | FireOptionFlag, MagickFalse },
+    { "+linear-stretch", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-linear-stretch", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+linewidth", 0L, DrawInfoOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-linewidth", 1L, DrawInfoOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+liquid-rescale", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-liquid-rescale", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+list", 0L, GlobalOptionFlag, MagickFalse },
+    { "-list", 1L, GlobalOptionFlag, MagickFalse },
+    { "+log", 0L, GlobalOptionFlag, MagickFalse },
+    { "-log", 1L, GlobalOptionFlag, MagickFalse },
+    { "+loop", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-loop", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+lowlight-color", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-lowlight-color", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+magnify", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-magnify", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+map", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-map", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+mask", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-mask", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+matte", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-matte", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+mattecolor", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-mattecolor", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+maximum", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-maximum", 0L, ListOperatorOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+median", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-median", 1L, SimpleOperatorOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+metric", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-metric", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+minimum", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-minimum", 0L, ImageInfoOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+mode", 1L, NonConvertOptionFlag, MagickFalse },
+    { "-mode", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+modulate", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-modulate", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+monitor", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "-monitor", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "+monochrome", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-monochrome", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "+morph", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-morph", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+morphology", 2L, DeprecateOptionFlag, MagickFalse },
+    { "-morphology", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+mosaic", 0L, ListOperatorOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-mosaic", 0L, ListOperatorOptionFlag | FireOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+motion-blur", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-motion-blur", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+name", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-name", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+negate", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-negate", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+noise", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-noise", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+noop", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-noop", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+normalize", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-normalize", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+opaque", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-opaque", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+ordered-dither", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-ordered-dither", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+orient", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-orient", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+origin", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-origin", 1L, DeprecateOptionFlag, MagickFalse },
+    { "+page", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-page", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+paint", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-paint", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+path", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-path", 1L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+pause", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-pause", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+passphrase", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-passphrase", 1L, DeprecateOptionFlag, MagickFalse },
+    { "+pen", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "-pen", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+ping", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-ping", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+pointsize", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-pointsize", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+polaroid", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-polaroid", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+posterize", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-posterize", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+preview", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-preview", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+print", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-print", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+process", 1L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-process", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+profile", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-profile", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+quality", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-quality", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+quantize", 0L, QuantizeInfoOptionFlag, MagickFalse },
+    { "-quantize", 1L, QuantizeInfoOptionFlag, MagickFalse },
+    { "+quiet", 0L, GlobalOptionFlag | FireOptionFlag, MagickFalse },
+    { "-quiet", 0L, GlobalOptionFlag | FireOptionFlag, MagickFalse },
+    { "+radial-blur", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-radial-blur", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+raise", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-raise", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+random-threshold", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-random-threshold", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+recolor", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-recolor", 1L, SimpleOperatorOptionFlag | DeprecateOptionFlag, MagickFalse },
+    { "+red-primary", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-red-primary", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+regard-warnings", 0L, GenesisOptionFlag, MagickFalse },
+    { "-regard-warnings", 0L, GenesisOptionFlag, MagickFalse },
+    { "+region", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-region", 1L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+remote", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-remote", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+render", 0L, DrawInfoOptionFlag, MagickFalse },
+    { "-render", 0L, DrawInfoOptionFlag, MagickFalse },
+    { "+remap", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-remap", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+repage", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-repage", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+resample", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-resample", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+resize", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-resize", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+respect-parenthesis", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-respect-parenthesis", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+reverse", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-reverse", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+roll", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-roll", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+rotate", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-rotate", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+sample", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-sample", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+sampling-factor", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-sampling-factor", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+sans", 1L, NonConvertOptionFlag, MagickTrue },
+    { "-sans", 1L, NonConvertOptionFlag, MagickTrue },
+    { "+sans0", 0L, NonConvertOptionFlag, MagickTrue },
+    { "-sans0", 0L, NonConvertOptionFlag, MagickTrue },
+    { "+sans2", 2L, NonConvertOptionFlag, MagickTrue },
+    { "-sans2", 2L, NonConvertOptionFlag, MagickTrue },
+    { "+scale", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-scale", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+scene", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-scene", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+scenes", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-scenes", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+screen", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-screen", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+seed", 0L, GlobalOptionFlag, MagickFalse },
+    { "-seed", 1L, GlobalOptionFlag, MagickFalse },
+    { "+segment", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-segment", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+selective-blur", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-selective-blur", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+separate", 0L, DeprecateOptionFlag | FireOptionFlag, MagickFalse },
+    { "-separate", 0L, SimpleOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+sepia-tone", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-sepia-tone", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+set", 1L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "-set", 2L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "+shade", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-shade", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+shadow", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-shadow", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+shared-memory", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-shared-memory", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+sharpen", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-sharpen", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+shave", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-shave", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+shear", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-shear", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+sigmoidal-contrast", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-sigmoidal-contrast", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+silent", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-silent", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+size", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-size", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+sketch", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-sketch", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+smush", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-smush", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+snaps", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-snaps", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+solarize", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-solarize", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+sparse-color", 2L, DeprecateOptionFlag, MagickFalse },
+    { "-sparse-color", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+splice", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-splice", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+spread", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-spread", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+statistic", 2L, DeprecateOptionFlag, MagickFalse },
+    { "-statistic", 2L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+stegano", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-stegano", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+stereo", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-stereo", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+stretch", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-stretch", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+strip", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-strip", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+stroke", 0L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "-stroke", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+strokewidth", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "-strokewidth", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+style", 0L, DrawInfoOptionFlag, MagickFalse },
+    { "-style", 1L, DrawInfoOptionFlag, MagickFalse },
+    { "+subimage-search", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-subimage-search", 0L, NonConvertOptionFlag, MagickFalse },
+    { "+swap", 0L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-swap", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "+swirl", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-swirl", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+synchronize", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-synchronize", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+taint", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-taint", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+text-font", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-text-font", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+texture", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-texture", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+threshold", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-threshold", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+thumbnail", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-thumbnail", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+tile", 0L, DrawInfoOptionFlag, MagickFalse },
+    { "-tile", 1L, DrawInfoOptionFlag, MagickFalse },
+    { "+tile-offset", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-tile-offset", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+tint", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-tint", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+title", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-title", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+transform", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-transform", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+transparent", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "-transparent", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+transparent-color", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "-transparent-color", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+transpose", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-transpose", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+transverse", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-transverse", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+treedepth", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-treedepth", 1L, QuantizeInfoOptionFlag, MagickFalse },
+    { "+trim", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-trim", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+type", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "-type", 1L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "+undercolor", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-undercolor", 1L, ImageInfoOptionFlag | DrawInfoOptionFlag, MagickFalse },
+    { "+unique", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-unique", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+unique-colors", 0L, DeprecateOptionFlag, MagickFalse },
+    { "-unique-colors", 0L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+units", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-units", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+unsharp", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-unsharp", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+update", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-update", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+use-pixmap", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-use-pixmap", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+verbose", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-verbose", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "+version", 0L, SpecialOperatorOptionFlag, MagickFalse },
+    { "-version", 1L, SpecialOperatorOptionFlag, MagickFalse },
+    { "+view", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-view", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+vignette", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-vignette", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+virtual-pixel", 0L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "-virtual-pixel", 1L, ImageInfoOptionFlag | SimpleOperatorOptionFlag, MagickFalse },
+    { "+visual", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-visual", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+watermark", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-watermark", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+wave", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-wave", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+weight", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-weight", 1L, DrawInfoOptionFlag, MagickFalse },
+    { "+white-point", 0L, ImageInfoOptionFlag, MagickFalse },
+    { "-white-point", 1L, ImageInfoOptionFlag, MagickFalse },
+    { "+white-threshold", 1L, DeprecateOptionFlag, MagickFalse },
+    { "-white-threshold", 1L, SimpleOperatorOptionFlag, MagickFalse },
+    { "+window", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-window", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+window-group", 0L, NonConvertOptionFlag, MagickFalse },
+    { "-window-group", 1L, NonConvertOptionFlag, MagickFalse },
+    { "+write", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { "-write", 1L, ListOperatorOptionFlag | FireOptionFlag, MagickFalse },
+    { (char *) NULL, 0L, UndefinedOptionFlag, MagickFalse }
+  },
+  ComposeOptions[] =
+  {
+    { "Undefined", UndefinedCompositeOp, UndefinedOptionFlag, MagickTrue },
+    { "Atop", AtopCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Blend", BlendCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Blur", BlurCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Bumpmap", BumpmapCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "ChangeMask", ChangeMaskCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Clear", ClearCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "ColorBurn", ColorBurnCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "ColorDodge", ColorDodgeCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Colorize", ColorizeCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyBlack", CopyBlackCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyBlue", CopyBlueCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyCyan", CopyCyanCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyGreen", CopyGreenCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Copy", CopyCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyMagenta", CopyMagentaCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyOpacity", CopyOpacityCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyRed", CopyRedCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "CopyYellow", CopyYellowCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Darken", DarkenCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DarkenIntensity", DarkenIntensityCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DivideDst", DivideDstCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DivideSrc", DivideSrcCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Dst", DstCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Difference", DifferenceCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Displace", DisplaceCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Dissolve", DissolveCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Distort", DistortCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DstAtop", DstAtopCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DstIn", DstInCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DstOut", DstOutCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "DstOver", DstOverCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Dst", DstCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Exclusion", ExclusionCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "HardLight", HardLightCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Hue", HueCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "In", InCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Lighten", LightenCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "LightenIntensity", LightenIntensityCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "LinearBurn", LinearBurnCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "LinearDodge", LinearDodgeCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "LinearLight", LinearLightCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Luminize", LuminizeCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Mathematics", MathematicsCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "MinusDst", MinusDstCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "MinusSrc", MinusSrcCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Modulate", ModulateCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "ModulusAdd", ModulusAddCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "ModulusSubtract", ModulusSubtractCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Multiply", MultiplyCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "None", NoCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Out", OutCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Overlay", OverlayCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Over", OverCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "PegtopLight", PegtopLightCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "PinLight", PinLightCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Plus", PlusCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Replace", ReplaceCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Saturate", SaturateCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Screen", ScreenCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "SoftLight", SoftLightCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Src", SrcCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "SrcAtop", SrcAtopCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "SrcIn", SrcInCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "SrcOut", SrcOutCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "SrcOver", SrcOverCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Src", SrcCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "VividLight", VividLightCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Xor", XorCompositeOp, UndefinedOptionFlag, MagickFalse },
+    { "Divide", DivideDstCompositeOp, DeprecateOptionFlag, MagickTrue },
+    { "Minus", MinusDstCompositeOp, DeprecateOptionFlag, MagickTrue },
+    { "Threshold", ThresholdCompositeOp, DeprecateOptionFlag, MagickTrue },
+    { (char *) NULL, UndefinedCompositeOp, UndefinedOptionFlag, MagickFalse }
+  },
+  CompressOptions[] =
+  {
+    { "Undefined", UndefinedCompression, UndefinedOptionFlag, MagickTrue },
+    { "B44", B44Compression, UndefinedOptionFlag, MagickFalse },
+    { "B44A", B44ACompression, UndefinedOptionFlag, MagickFalse },
+    { "BZip", BZipCompression, UndefinedOptionFlag, MagickFalse },
+    { "DXT1", DXT1Compression, UndefinedOptionFlag, MagickFalse },
+    { "DXT3", DXT3Compression, UndefinedOptionFlag, MagickFalse },
+    { "DXT5", DXT5Compression, UndefinedOptionFlag, MagickFalse },
+    { "Fax", FaxCompression, UndefinedOptionFlag, MagickFalse },
+    { "Group4", Group4Compression, UndefinedOptionFlag, MagickFalse },
+    { "JBIG1", JBIG1Compression, UndefinedOptionFlag, MagickFalse },
+    { "JBIG2", JBIG2Compression, UndefinedOptionFlag, MagickFalse },
+    { "JPEG", JPEGCompression, UndefinedOptionFlag, MagickFalse },
+    { "JPEG2000", JPEG2000Compression, UndefinedOptionFlag, MagickFalse },
+    { "Lossless", LosslessJPEGCompression, UndefinedOptionFlag, MagickFalse },
+    { "LosslessJPEG", LosslessJPEGCompression, UndefinedOptionFlag, MagickFalse },
+    { "LZMA", LZMACompression, UndefinedOptionFlag, MagickFalse },
+    { "LZW", LZWCompression, UndefinedOptionFlag, MagickFalse },
+    { "None", NoCompression, UndefinedOptionFlag, MagickFalse },
+    { "Piz", PizCompression, UndefinedOptionFlag, MagickFalse },
+    { "Pxr24", Pxr24Compression, UndefinedOptionFlag, MagickFalse },
+    { "RLE", RLECompression, UndefinedOptionFlag, MagickFalse },
+    { "Zip", ZipCompression, UndefinedOptionFlag, MagickFalse },
+    { "RunlengthEncoded", RLECompression, UndefinedOptionFlag, MagickFalse },
+    { "ZipS", ZipSCompression, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedCompression, UndefinedOptionFlag, MagickFalse }
+  },
+  ColorspaceOptions[] =
+  {
+    { "Undefined", UndefinedColorspace, UndefinedOptionFlag, MagickTrue },
+    { "CMY", CMYColorspace, UndefinedOptionFlag, MagickFalse },
+    { "CMYK", CMYKColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Gray", GRAYColorspace, UndefinedOptionFlag, MagickFalse },
+    { "HSB", HSBColorspace, UndefinedOptionFlag, MagickFalse },
+    { "HSL", HSLColorspace, UndefinedOptionFlag, MagickFalse },
+    { "HWB", HWBColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Lab", LabColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Log", LogColorspace, UndefinedOptionFlag, MagickFalse },
+    { "OHTA", OHTAColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Rec601Luma", Rec601LumaColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Rec601YCbCr", Rec601YCbCrColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Rec709Luma", Rec709LumaColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Rec709YCbCr", Rec709YCbCrColorspace, UndefinedOptionFlag, MagickFalse },
+    { "RGB", RGBColorspace, UndefinedOptionFlag, MagickFalse },
+    { "sRGB", sRGBColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Transparent", TransparentColorspace, UndefinedOptionFlag, MagickFalse },
+    { "XYZ", XYZColorspace, UndefinedOptionFlag, MagickFalse },
+    { "YCbCr", YCbCrColorspace, UndefinedOptionFlag, MagickFalse },
+    { "YCC", YCCColorspace, UndefinedOptionFlag, MagickFalse },
+    { "YIQ", YIQColorspace, UndefinedOptionFlag, MagickFalse },
+    { "YPbPr", YPbPrColorspace, UndefinedOptionFlag, MagickFalse },
+    { "YUV", YUVColorspace, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedColorspace, UndefinedOptionFlag, MagickFalse }
+  },
+  DataTypeOptions[] =
+  {
+    { "Undefined", UndefinedData, UndefinedOptionFlag, MagickTrue },
+    { "Byte", ByteData, UndefinedOptionFlag, MagickFalse },
+    { "Long", LongData, UndefinedOptionFlag, MagickFalse },
+    { "Short", ShortData, UndefinedOptionFlag, MagickFalse },
+    { "String", StringData, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedData, UndefinedOptionFlag, MagickFalse }
+  },
+  DecorateOptions[] =
+  {
+    { "Undefined", UndefinedDecoration, UndefinedOptionFlag, MagickTrue },
+    { "LineThrough", LineThroughDecoration, UndefinedOptionFlag, MagickFalse },
+    { "None", NoDecoration, UndefinedOptionFlag, MagickFalse },
+    { "Overline", OverlineDecoration, UndefinedOptionFlag, MagickFalse },
+    { "Underline", UnderlineDecoration, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedDecoration, UndefinedOptionFlag, MagickFalse }
+  },
+  DirectionOptions[] =
+  {
+    { "Undefined", UndefinedDirection, UndefinedOptionFlag, MagickTrue },
+    { "right-to-left", RightToLeftDirection, UndefinedOptionFlag, MagickFalse },
+    { "left-to-right", LeftToRightDirection, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedDirection, UndefinedOptionFlag, MagickFalse }
+  },
+  DisposeOptions[] =
+  {
+    { "Undefined", UndefinedDispose, UndefinedOptionFlag, MagickTrue },
+    { "Background", BackgroundDispose, UndefinedOptionFlag, MagickFalse },
+    { "None", NoneDispose, UndefinedOptionFlag, MagickFalse },
+    { "Previous", PreviousDispose, UndefinedOptionFlag, MagickFalse },
+    { "Undefined", UndefinedDispose, UndefinedOptionFlag, MagickFalse },
+    { "0", UndefinedDispose, UndefinedOptionFlag, MagickFalse },
+    { "1", NoneDispose, UndefinedOptionFlag, MagickFalse },
+    { "2", BackgroundDispose, UndefinedOptionFlag, MagickFalse },
+    { "3", PreviousDispose, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedDispose, UndefinedOptionFlag, MagickFalse }
+  },
+  DistortOptions[] =
+  {
+    { "Undefined", UndefinedDistortion, UndefinedOptionFlag, MagickTrue },
+    { "Affine", AffineDistortion, UndefinedOptionFlag, MagickFalse },
+    { "AffineProjection", AffineProjectionDistortion, UndefinedOptionFlag, MagickFalse },
+    { "ScaleRotateTranslate", ScaleRotateTranslateDistortion, UndefinedOptionFlag, MagickFalse },
+    { "SRT", ScaleRotateTranslateDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Perspective", PerspectiveDistortion, UndefinedOptionFlag, MagickFalse },
+    { "PerspectiveProjection", PerspectiveProjectionDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Bilinear", BilinearForwardDistortion, UndefinedOptionFlag, MagickTrue },
+    { "BilinearForward", BilinearForwardDistortion, UndefinedOptionFlag, MagickFalse },
+    { "BilinearReverse", BilinearReverseDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Polynomial", PolynomialDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Arc", ArcDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Polar", PolarDistortion, UndefinedOptionFlag, MagickFalse },
+    { "DePolar", DePolarDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Barrel", BarrelDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Cylinder2Plane", Cylinder2PlaneDistortion, UndefinedOptionFlag, MagickTrue },
+    { "Plane2Cylinder", Plane2CylinderDistortion, UndefinedOptionFlag, MagickTrue },
+    { "BarrelInverse", BarrelInverseDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Shepards", ShepardsDistortion, UndefinedOptionFlag, MagickFalse },
+    { "Resize", ResizeDistortion, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedDistortion, UndefinedOptionFlag, MagickFalse }
+  },
+  DitherOptions[] =
+  {
+    { "Undefined", UndefinedDitherMethod, UndefinedOptionFlag, MagickTrue },
+    { "None", NoDitherMethod, UndefinedOptionFlag, MagickFalse },
+    { "FloydSteinberg", FloydSteinbergDitherMethod, UndefinedOptionFlag, MagickFalse },
+    { "Riemersma", RiemersmaDitherMethod, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedEndian, UndefinedOptionFlag, MagickFalse }
+  },
+  EndianOptions[] =
+  {
+    { "Undefined", UndefinedEndian, UndefinedOptionFlag, MagickTrue },
+    { "LSB", LSBEndian, UndefinedOptionFlag, MagickFalse },
+    { "MSB", MSBEndian, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedEndian, UndefinedOptionFlag, MagickFalse }
+  },
+  EvaluateOptions[] =
+  {
+    { "Undefined", UndefinedEvaluateOperator, UndefinedOptionFlag, MagickTrue },
+    { "Abs", AbsEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Add", AddEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "AddModulus", AddModulusEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "And", AndEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Cos", CosineEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Cosine", CosineEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Divide", DivideEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Exp", ExponentialEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Exponential", ExponentialEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "GaussianNoise", GaussianNoiseEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "ImpulseNoise", ImpulseNoiseEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "LaplacianNoise", LaplacianNoiseEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "LeftShift", LeftShiftEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Log", LogEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Max", MaxEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Mean", MeanEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Median", MedianEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Min", MinEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "MultiplicativeNoise", MultiplicativeNoiseEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Multiply", MultiplyEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Or", OrEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "PoissonNoise", PoissonNoiseEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Pow", PowEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "RightShift", RightShiftEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Set", SetEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Sin", SineEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Sine", SineEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Subtract", SubtractEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Threshold", ThresholdEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "ThresholdBlack", ThresholdBlackEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "ThresholdWhite", ThresholdWhiteEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "UniformNoise", UniformNoiseEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { "Xor", XorEvaluateOperator, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedEvaluateOperator, UndefinedOptionFlag, MagickFalse }
+  },
+  FillRuleOptions[] =
+  {
+    { "Undefined", UndefinedRule, UndefinedOptionFlag, MagickTrue },
+    { "Evenodd", EvenOddRule, UndefinedOptionFlag, MagickFalse },
+    { "NonZero", NonZeroRule, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedRule, UndefinedOptionFlag, MagickFalse }
+  },
+  FilterOptions[] =
+  {
+    { "Undefined", UndefinedFilter, UndefinedOptionFlag, MagickTrue },
+    { "Bartlett", BartlettFilter, UndefinedOptionFlag, MagickFalse },
+    { "Blackman", BlackmanFilter, UndefinedOptionFlag, MagickFalse },
+    { "Bohman", BohmanFilter, UndefinedOptionFlag, MagickFalse },
+    { "Box", BoxFilter, UndefinedOptionFlag, MagickFalse },
+    { "Catrom", CatromFilter, UndefinedOptionFlag, MagickFalse },
+    { "Cubic", CubicFilter, UndefinedOptionFlag, MagickFalse },
+    { "Gaussian", GaussianFilter, UndefinedOptionFlag, MagickFalse },
+    { "Hamming", HammingFilter, UndefinedOptionFlag, MagickFalse },
+    { "Hanning", HanningFilter, UndefinedOptionFlag, MagickFalse },
+    { "Hermite", HermiteFilter, UndefinedOptionFlag, MagickFalse },
+    { "Jinc", JincFilter, UndefinedOptionFlag, MagickFalse },
+    { "Kaiser", KaiserFilter, UndefinedOptionFlag, MagickFalse },
+    { "Lagrange", LagrangeFilter, UndefinedOptionFlag, MagickFalse },
+    { "Lanczos", LanczosFilter, UndefinedOptionFlag, MagickFalse },
+    { "LanczosSharp", LanczosSharpFilter, UndefinedOptionFlag, MagickFalse },
+    { "Lanczos2", Lanczos2Filter, UndefinedOptionFlag, MagickFalse },
+    { "Lanczos2Sharp", Lanczos2SharpFilter, UndefinedOptionFlag, MagickFalse },
+    { "Mitchell", MitchellFilter, UndefinedOptionFlag, MagickFalse },
+    { "Parzen", ParzenFilter, UndefinedOptionFlag, MagickFalse },
+    { "Point", PointFilter, UndefinedOptionFlag, MagickFalse },
+    { "Quadratic", QuadraticFilter, UndefinedOptionFlag, MagickFalse },
+    { "Robidoux", RobidouxFilter, UndefinedOptionFlag, MagickFalse },
+    { "Sinc", SincFilter, UndefinedOptionFlag, MagickFalse },
+    { "SincFast", SincFastFilter, UndefinedOptionFlag, MagickFalse },
+    { "Triangle", TriangleFilter, UndefinedOptionFlag, MagickFalse },
+    { "Welsh", WelshFilter, UndefinedOptionFlag, MagickFalse },
+    /* For backward compatibility - must be after "Jinc" */
+    { "Bessel", JincFilter, UndefinedOptionFlag, MagickTrue },
+    { (char *) NULL, UndefinedFilter, UndefinedOptionFlag, MagickFalse }
+  },
+  FunctionOptions[] =
+  {
+    { "Undefined", UndefinedFunction, UndefinedOptionFlag, MagickTrue },
+    { "Polynomial", PolynomialFunction, UndefinedOptionFlag, MagickFalse },
+    { "Sinusoid", SinusoidFunction, UndefinedOptionFlag, MagickFalse },
+    { "ArcSin", ArcsinFunction, UndefinedOptionFlag, MagickFalse },
+    { "ArcTan", ArctanFunction, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedFunction, UndefinedOptionFlag, MagickFalse }
+  },
+  GravityOptions[] =
+  {
+    { "Undefined", UndefinedGravity, UndefinedOptionFlag, MagickTrue },
+    { "None", UndefinedGravity, UndefinedOptionFlag, MagickFalse },
+    { "Center", CenterGravity, UndefinedOptionFlag, MagickFalse },
+    { "East", EastGravity, UndefinedOptionFlag, MagickFalse },
+    { "Forget", ForgetGravity, UndefinedOptionFlag, MagickFalse },
+    { "NorthEast", NorthEastGravity, UndefinedOptionFlag, MagickFalse },
+    { "North", NorthGravity, UndefinedOptionFlag, MagickFalse },
+    { "NorthWest", NorthWestGravity, UndefinedOptionFlag, MagickFalse },
+    { "SouthEast", SouthEastGravity, UndefinedOptionFlag, MagickFalse },
+    { "South", SouthGravity, UndefinedOptionFlag, MagickFalse },
+    { "SouthWest", SouthWestGravity, UndefinedOptionFlag, MagickFalse },
+    { "West", WestGravity, UndefinedOptionFlag, MagickFalse },
+    { "Static", StaticGravity, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedGravity, UndefinedOptionFlag, MagickFalse }
+  },
+  IntentOptions[] =
+  {
+    { "Undefined", UndefinedIntent, UndefinedOptionFlag, MagickTrue },
+    { "Absolute", AbsoluteIntent, UndefinedOptionFlag, MagickFalse },
+    { "Perceptual", PerceptualIntent, UndefinedOptionFlag, MagickFalse },
+    { "Relative", RelativeIntent, UndefinedOptionFlag, MagickFalse },
+    { "Saturation", SaturationIntent, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedIntent, UndefinedOptionFlag, MagickFalse }
+  },
+  InterlaceOptions[] =
+  {
+    { "Undefined", UndefinedInterlace, UndefinedOptionFlag, MagickTrue },
+    { "Line", LineInterlace, UndefinedOptionFlag, MagickFalse },
+    { "None", NoInterlace, UndefinedOptionFlag, MagickFalse },
+    { "Plane", PlaneInterlace, UndefinedOptionFlag, MagickFalse },
+    { "Partition", PartitionInterlace, UndefinedOptionFlag, MagickFalse },
+    { "GIF", GIFInterlace, UndefinedOptionFlag, MagickFalse },
+    { "JPEG", JPEGInterlace, UndefinedOptionFlag, MagickFalse },
+    { "PNG", PNGInterlace, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedInterlace, UndefinedOptionFlag, MagickFalse }
+  },
+  InterpolateOptions[] =
+  {
+    { "Undefined", UndefinedInterpolatePixel, UndefinedOptionFlag, MagickTrue },
+    { "Average", AverageInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "Bicubic", BicubicInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "Bilinear", BilinearInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "filter", FilterInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "Integer", IntegerInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "Mesh", MeshInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "NearestNeighbor", NearestNeighborInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { "Spline", SplineInterpolatePixel, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedInterpolatePixel, UndefinedOptionFlag, MagickFalse }
+  },
+  KernelOptions[] =
+  {
+    { "Undefined", UndefinedKernel, UndefinedOptionFlag, MagickTrue },
+    { "Unity", UnityKernel, UndefinedOptionFlag, MagickFalse },
+    { "Gaussian", GaussianKernel, UndefinedOptionFlag, MagickFalse },
+    { "DoG", DoGKernel, UndefinedOptionFlag, MagickFalse },
+    { "LoG", LoGKernel, UndefinedOptionFlag, MagickFalse },
+    { "Blur", BlurKernel, UndefinedOptionFlag, MagickFalse },
+    { "Comet", CometKernel, UndefinedOptionFlag, MagickFalse },
+    { "Laplacian", LaplacianKernel, UndefinedOptionFlag, MagickFalse },
+    { "Sobel", SobelKernel, UndefinedOptionFlag, MagickFalse },
+    { "FreiChen", FreiChenKernel, UndefinedOptionFlag, MagickFalse },
+    { "Roberts", RobertsKernel, UndefinedOptionFlag, MagickFalse },
+    { "Prewitt", PrewittKernel, UndefinedOptionFlag, MagickFalse },
+    { "Compass", CompassKernel, UndefinedOptionFlag, MagickFalse },
+    { "Kirsch", KirschKernel, UndefinedOptionFlag, MagickFalse },
+    { "Diamond", DiamondKernel, UndefinedOptionFlag, MagickFalse },
+    { "Square", SquareKernel, UndefinedOptionFlag, MagickFalse },
+    { "Rectangle", RectangleKernel, UndefinedOptionFlag, MagickFalse },
+    { "Disk", DiskKernel, UndefinedOptionFlag, MagickFalse },
+    { "Octagon", OctagonKernel, UndefinedOptionFlag, MagickFalse },
+    { "Plus", PlusKernel, UndefinedOptionFlag, MagickFalse },
+    { "Cross", CrossKernel, UndefinedOptionFlag, MagickFalse },
+    { "Ring", RingKernel, UndefinedOptionFlag, MagickFalse },
+    { "Peaks", PeaksKernel, UndefinedOptionFlag, MagickFalse },
+    { "Edges", EdgesKernel, UndefinedOptionFlag, MagickFalse },
+    { "Corners", CornersKernel, UndefinedOptionFlag, MagickFalse },
+    { "Diagonals", DiagonalsKernel, UndefinedOptionFlag, MagickFalse },
+    { "ThinDiagonals", DiagonalsKernel, DeprecateOptionFlag, MagickTrue },
+    { "LineEnds", LineEndsKernel, UndefinedOptionFlag, MagickFalse },
+    { "LineJunctions", LineJunctionsKernel, UndefinedOptionFlag, MagickFalse },
+    { "Ridges", RidgesKernel, UndefinedOptionFlag, MagickFalse },
+    { "ConvexHull", ConvexHullKernel, UndefinedOptionFlag, MagickFalse },
+    { "ThinSe", ThinSEKernel, UndefinedOptionFlag, MagickFalse },
+    { "Skeleton", SkeletonKernel, UndefinedOptionFlag, MagickFalse },
+    { "Chebyshev", ChebyshevKernel, UndefinedOptionFlag, MagickFalse },
+    { "Manhattan", ManhattanKernel, UndefinedOptionFlag, MagickFalse },
+    { "Octagonal", OctagonalKernel, UndefinedOptionFlag, MagickFalse },
+    { "Euclidean", EuclideanKernel, UndefinedOptionFlag, MagickFalse },
+    { "User Defined", UserDefinedKernel, UndefinedOptionFlag, MagickTrue },
+    { (char *) NULL, UndefinedKernel, UndefinedOptionFlag, MagickFalse }
+  },
+  LayerOptions[] =
+  {
+    { "Undefined", UndefinedLayer, UndefinedOptionFlag, MagickTrue },
+    { "Coalesce", CoalesceLayer, UndefinedOptionFlag, MagickFalse },
+    { "CompareAny", CompareAnyLayer, UndefinedOptionFlag, MagickFalse },
+    { "CompareClear", CompareClearLayer, UndefinedOptionFlag, MagickFalse },
+    { "CompareOverlay", CompareOverlayLayer, UndefinedOptionFlag, MagickFalse },
+    { "Dispose", DisposeLayer, UndefinedOptionFlag, MagickFalse },
+    { "Optimize", OptimizeLayer, UndefinedOptionFlag, MagickFalse },
+    { "OptimizeFrame", OptimizeImageLayer, UndefinedOptionFlag, MagickFalse },
+    { "OptimizePlus", OptimizePlusLayer, UndefinedOptionFlag, MagickFalse },
+    { "OptimizeTransparency", OptimizeTransLayer, UndefinedOptionFlag, MagickFalse },
+    { "RemoveDups", RemoveDupsLayer, UndefinedOptionFlag, MagickFalse },
+    { "RemoveZero", RemoveZeroLayer, UndefinedOptionFlag, MagickFalse },
+    { "Composite", CompositeLayer, UndefinedOptionFlag, MagickFalse },
+    { "Merge", MergeLayer, UndefinedOptionFlag, MagickFalse },
+    { "Flatten", FlattenLayer, UndefinedOptionFlag, MagickFalse },
+    { "Mosaic", MosaicLayer, UndefinedOptionFlag, MagickFalse },
+    { "TrimBounds", TrimBoundsLayer, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedLayer, UndefinedOptionFlag, MagickFalse }
+  },
+  LineCapOptions[] =
+  {
+    { "Undefined", UndefinedCap, UndefinedOptionFlag, MagickTrue },
+    { "Butt", ButtCap, UndefinedOptionFlag, MagickFalse },
+    { "Round", RoundCap, UndefinedOptionFlag, MagickFalse },
+    { "Square", SquareCap, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedCap, UndefinedOptionFlag, MagickFalse }
+  },
+  LineJoinOptions[] =
+  {
+    { "Undefined", UndefinedJoin, UndefinedOptionFlag, MagickTrue },
+    { "Bevel", BevelJoin, UndefinedOptionFlag, MagickFalse },
+    { "Miter", MiterJoin, UndefinedOptionFlag, MagickFalse },
+    { "Round", RoundJoin, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedJoin, UndefinedOptionFlag, MagickFalse }
+  },
+  ListOptions[] =
+  {
+    { "Align", MagickAlignOptions, UndefinedOptionFlag, MagickFalse },
+    { "Alpha", MagickAlphaOptions, UndefinedOptionFlag, MagickFalse },
+    { "Boolean", MagickBooleanOptions, UndefinedOptionFlag, MagickFalse },
+    { "Channel", MagickChannelOptions, UndefinedOptionFlag, MagickFalse },
+    { "Class", MagickClassOptions, UndefinedOptionFlag, MagickFalse },
+    { "ClipPath", MagickClipPathOptions, UndefinedOptionFlag, MagickFalse },
+    { "Coder", MagickCoderOptions, UndefinedOptionFlag, MagickFalse },
+    { "Color", MagickColorOptions, UndefinedOptionFlag, MagickFalse },
+    { "Colorspace", MagickColorspaceOptions, UndefinedOptionFlag, MagickFalse },
+    { "Command", MagickCommandOptions, UndefinedOptionFlag, MagickFalse },
+    { "Compose", MagickComposeOptions, UndefinedOptionFlag, MagickFalse },
+    { "Compress", MagickCompressOptions, UndefinedOptionFlag, MagickFalse },
+    { "Configure", MagickConfigureOptions, UndefinedOptionFlag, MagickFalse },
+    { "DataType", MagickDataTypeOptions, UndefinedOptionFlag, MagickFalse },
+    { "Debug", MagickDebugOptions, UndefinedOptionFlag, MagickFalse },
+    { "Decoration", MagickDecorateOptions, UndefinedOptionFlag, MagickFalse },
+    { "Delegate", MagickDelegateOptions, UndefinedOptionFlag, MagickFalse },
+    { "Direction", MagickDirectionOptions, UndefinedOptionFlag, MagickFalse },
+    { "Dispose", MagickDisposeOptions, UndefinedOptionFlag, MagickFalse },
+    { "Distort", MagickDistortOptions, UndefinedOptionFlag, MagickFalse },
+    { "Dither", MagickDitherOptions, UndefinedOptionFlag, MagickFalse },
+    { "Endian", MagickEndianOptions, UndefinedOptionFlag, MagickFalse },
+    { "Evaluate", MagickEvaluateOptions, UndefinedOptionFlag, MagickFalse },
+    { "FillRule", MagickFillRuleOptions, UndefinedOptionFlag, MagickFalse },
+    { "Filter", MagickFilterOptions, UndefinedOptionFlag, MagickFalse },
+    { "Font", MagickFontOptions, UndefinedOptionFlag, MagickFalse },
+    { "Format", MagickFormatOptions, UndefinedOptionFlag, MagickFalse },
+    { "Function", MagickFunctionOptions, UndefinedOptionFlag, MagickFalse },
+    { "Gravity", MagickGravityOptions, UndefinedOptionFlag, MagickFalse },
+    { "Intent", MagickIntentOptions, UndefinedOptionFlag, MagickFalse },
+    { "Interlace", MagickInterlaceOptions, UndefinedOptionFlag, MagickFalse },
+    { "Interpolate", MagickInterpolateOptions, UndefinedOptionFlag, MagickFalse },
+    { "Kernel", MagickKernelOptions, UndefinedOptionFlag, MagickFalse },
+    { "Layers", MagickLayerOptions, UndefinedOptionFlag, MagickFalse },
+    { "LineCap", MagickLineCapOptions, UndefinedOptionFlag, MagickFalse },
+    { "LineJoin", MagickLineJoinOptions, UndefinedOptionFlag, MagickFalse },
+    { "List", MagickListOptions, UndefinedOptionFlag, MagickFalse },
+    { "Locale", MagickLocaleOptions, UndefinedOptionFlag, MagickFalse },
+    { "LogEvent", MagickLogEventOptions, UndefinedOptionFlag, MagickFalse },
+    { "Log", MagickLogOptions, UndefinedOptionFlag, MagickFalse },
+    { "Magic", MagickMagicOptions, UndefinedOptionFlag, MagickFalse },
+    { "Method", MagickMethodOptions, UndefinedOptionFlag, MagickFalse },
+    { "Metric", MagickMetricOptions, UndefinedOptionFlag, MagickFalse },
+    { "Mime", MagickMimeOptions, UndefinedOptionFlag, MagickFalse },
+    { "Mode", MagickModeOptions, UndefinedOptionFlag, MagickFalse },
+    { "Morphology", MagickMorphologyOptions, UndefinedOptionFlag, MagickFalse },
+    { "Module", MagickModuleOptions, UndefinedOptionFlag, MagickFalse },
+    { "Noise", MagickNoiseOptions, UndefinedOptionFlag, MagickFalse },
+    { "Orientation", MagickOrientationOptions, UndefinedOptionFlag, MagickFalse },
+    { "Policy", MagickPolicyOptions, UndefinedOptionFlag, MagickFalse },
+    { "PolicyDomain", MagickPolicyDomainOptions, UndefinedOptionFlag, MagickFalse },
+    { "PolicyRights", MagickPolicyRightsOptions, UndefinedOptionFlag, MagickFalse },
+    { "Preview", MagickPreviewOptions, UndefinedOptionFlag, MagickFalse },
+    { "Primitive", MagickPrimitiveOptions, UndefinedOptionFlag, MagickFalse },
+    { "QuantumFormat", MagickQuantumFormatOptions, UndefinedOptionFlag, MagickFalse },
+    { "Resource", MagickResourceOptions, UndefinedOptionFlag, MagickFalse },
+    { "SparseColor", MagickSparseColorOptions, UndefinedOptionFlag, MagickFalse },
+    { "Statistic", MagickStatisticOptions, UndefinedOptionFlag, MagickFalse },
+    { "Storage", MagickStorageOptions, UndefinedOptionFlag, MagickFalse },
+    { "Stretch", MagickStretchOptions, UndefinedOptionFlag, MagickFalse },
+    { "Style", MagickStyleOptions, UndefinedOptionFlag, MagickFalse },
+    { "Threshold", MagickThresholdOptions, UndefinedOptionFlag, MagickFalse },
+    { "Type", MagickTypeOptions, UndefinedOptionFlag, MagickFalse },
+    { "Units", MagickResolutionOptions, UndefinedOptionFlag, MagickFalse },
+    { "Undefined", MagickUndefinedOptions, UndefinedOptionFlag, MagickTrue },
+    { "Validate", MagickValidateOptions, UndefinedOptionFlag, MagickFalse },
+    { "VirtualPixel", MagickVirtualPixelOptions, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, MagickUndefinedOptions, UndefinedOptionFlag, MagickFalse }
+  },
+  LogEventOptions[] =
+  {
+    { "Undefined", UndefinedEvents, UndefinedOptionFlag, MagickTrue },
+    { "All", (AllEvents &~ TraceEvent), UndefinedOptionFlag, MagickFalse },
+    { "Annotate", AnnotateEvent, UndefinedOptionFlag, MagickFalse },
+    { "Blob", BlobEvent, UndefinedOptionFlag, MagickFalse },
+    { "Cache", CacheEvent, UndefinedOptionFlag, MagickFalse },
+    { "Coder", CoderEvent, UndefinedOptionFlag, MagickFalse },
+    { "Configure", ConfigureEvent, UndefinedOptionFlag, MagickFalse },
+    { "Deprecate", DeprecateEvent, UndefinedOptionFlag, MagickFalse },
+    { "Draw", DrawEvent, UndefinedOptionFlag, MagickFalse },
+    { "Exception", ExceptionEvent, UndefinedOptionFlag, MagickFalse },
+    { "Locale", LocaleEvent, UndefinedOptionFlag, MagickFalse },
+    { "Module", ModuleEvent, UndefinedOptionFlag, MagickFalse },
+    { "None", NoEvents, UndefinedOptionFlag, MagickFalse },
+    { "Policy", PolicyEvent, UndefinedOptionFlag, MagickFalse },
+    { "Resource", ResourceEvent, UndefinedOptionFlag, MagickFalse },
+    { "Trace", TraceEvent, UndefinedOptionFlag, MagickFalse },
+    { "Transform", TransformEvent, UndefinedOptionFlag, MagickFalse },
+    { "User", UserEvent, UndefinedOptionFlag, MagickFalse },
+    { "Wand", WandEvent, UndefinedOptionFlag, MagickFalse },
+    { "X11", X11Event, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedEvents, UndefinedOptionFlag, MagickFalse }
+  },
+  MetricOptions[] =
+  {
+    { "Undefined", UndefinedMetric, UndefinedOptionFlag, MagickTrue },
+    { "AE", AbsoluteErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { "Fuzz", FuzzErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { "MAE", MeanAbsoluteErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { "MEPP", MeanErrorPerPixelMetric, UndefinedOptionFlag, MagickFalse },
+    { "MSE", MeanSquaredErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { "NCC", NormalizedCrossCorrelationErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { "PAE", PeakAbsoluteErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { "PSNR", PeakSignalToNoiseRatioMetric, UndefinedOptionFlag, MagickFalse },
+    { "RMSE", RootMeanSquaredErrorMetric, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedMetric, UndefinedOptionFlag, MagickFalse }
+  },
+  MethodOptions[] =
+  {
+    { "Undefined", UndefinedMethod, UndefinedOptionFlag, MagickTrue },
+    { "FillToBorder", FillToBorderMethod, UndefinedOptionFlag, MagickFalse },
+    { "Floodfill", FloodfillMethod, UndefinedOptionFlag, MagickFalse },
+    { "Point", PointMethod, UndefinedOptionFlag, MagickFalse },
+    { "Replace", ReplaceMethod, UndefinedOptionFlag, MagickFalse },
+    { "Reset", ResetMethod, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedMethod, UndefinedOptionFlag, MagickFalse }
+  },
+  ModeOptions[] =
+  {
+    { "Undefined", UndefinedMode, UndefinedOptionFlag, MagickTrue },
+    { "Concatenate", ConcatenateMode, UndefinedOptionFlag, MagickFalse },
+    { "Frame", FrameMode, UndefinedOptionFlag, MagickFalse },
+    { "Unframe", UnframeMode, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedMode, UndefinedOptionFlag, MagickFalse }
+  },
+  MorphologyOptions[] =
+  {
+    { "Undefined", UndefinedMorphology, UndefinedOptionFlag, MagickTrue },
+    { "Correlate", CorrelateMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Convolve", ConvolveMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Dilate", DilateMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Erode", ErodeMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Close", CloseMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Open", OpenMorphology, UndefinedOptionFlag, MagickFalse },
+    { "DilateIntensity", DilateIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "ErodeIntensity", ErodeIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "CloseIntensity", CloseIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "OpenIntensity", OpenIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "DilateI", DilateIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "ErodeI", ErodeIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "CloseI", CloseIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "OpenI", OpenIntensityMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Smooth", SmoothMorphology, UndefinedOptionFlag, MagickFalse },
+    { "EdgeOut", EdgeOutMorphology, UndefinedOptionFlag, MagickFalse },
+    { "EdgeIn", EdgeInMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Edge", EdgeMorphology, UndefinedOptionFlag, MagickFalse },
+    { "TopHat", TopHatMorphology, UndefinedOptionFlag, MagickFalse },
+    { "BottomHat", BottomHatMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Distance", DistanceMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Hmt", HitAndMissMorphology, UndefinedOptionFlag, MagickFalse },
+    { "HitNMiss", HitAndMissMorphology, UndefinedOptionFlag, MagickFalse },
+    { "HitAndMiss", HitAndMissMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Thinning", ThinningMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Thicken", ThickenMorphology, UndefinedOptionFlag, MagickFalse },
+    { "Voronoi", VoronoiMorphology, UndefinedOptionFlag, MagickTrue },
+    { (char *) NULL, UndefinedMorphology, UndefinedOptionFlag, MagickFalse }
+  },
+  NoiseOptions[] =
+  {
+    { "Undefined", UndefinedNoise, UndefinedOptionFlag, MagickTrue },
+    { "Gaussian", GaussianNoise, UndefinedOptionFlag, MagickFalse },
+    { "Impulse", ImpulseNoise, UndefinedOptionFlag, MagickFalse },
+    { "Laplacian", LaplacianNoise, UndefinedOptionFlag, MagickFalse },
+    { "Multiplicative", MultiplicativeGaussianNoise, UndefinedOptionFlag, MagickFalse },
+    { "Poisson", PoissonNoise, UndefinedOptionFlag, MagickFalse },
+    { "Random", RandomNoise, UndefinedOptionFlag, MagickFalse },
+    { "Uniform", UniformNoise, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedNoise, UndefinedOptionFlag, MagickFalse }
+  },
+  OrientationOptions[] =
+  {
+    { "Undefined", UndefinedOrientation, UndefinedOptionFlag, MagickTrue },
+    { "TopLeft", TopLeftOrientation, UndefinedOptionFlag, MagickFalse },
+    { "TopRight", TopRightOrientation, UndefinedOptionFlag, MagickFalse },
+    { "BottomRight", BottomRightOrientation, UndefinedOptionFlag, MagickFalse },
+    { "BottomLeft", BottomLeftOrientation, UndefinedOptionFlag, MagickFalse },
+    { "LeftTop", LeftTopOrientation, UndefinedOptionFlag, MagickFalse },
+    { "RightTop", RightTopOrientation, UndefinedOptionFlag, MagickFalse },
+    { "RightBottom", RightBottomOrientation, UndefinedOptionFlag, MagickFalse },
+    { "LeftBottom", LeftBottomOrientation, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedOrientation, UndefinedOptionFlag, MagickFalse }
+  },
+  PolicyDomainOptions[] =
+  {
+    { "Undefined", UndefinedPolicyDomain, UndefinedOptionFlag, MagickTrue },
+    { "Coder", CoderPolicyDomain, UndefinedOptionFlag, MagickFalse },
+    { "Delegate", DelegatePolicyDomain, UndefinedOptionFlag, MagickFalse },
+    { "Filter", FilterPolicyDomain, UndefinedOptionFlag, MagickFalse },
+    { "Path", PathPolicyDomain, UndefinedOptionFlag, MagickFalse },
+    { "Resource", ResourcePolicyDomain, UndefinedOptionFlag, MagickFalse },
+    { "System", SystemPolicyDomain, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedPolicyDomain, UndefinedOptionFlag, MagickFalse }
+  },
+  PolicyRightsOptions[] =
+  {
+    { "Undefined", UndefinedPolicyRights, UndefinedOptionFlag, MagickTrue },
+    { "None", NoPolicyRights, UndefinedOptionFlag, MagickFalse },
+    { "Read", ReadPolicyRights, UndefinedOptionFlag, MagickFalse },
+    { "Write", WritePolicyRights, UndefinedOptionFlag, MagickFalse },
+    { "Execute", ExecutePolicyRights, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedPolicyRights, UndefinedOptionFlag, MagickFalse }
+  },
+  PreviewOptions[] =
+  {
+    { "Undefined", UndefinedPreview, UndefinedOptionFlag, MagickTrue },
+    { "AddNoise", AddNoisePreview, UndefinedOptionFlag, MagickFalse },
+    { "Blur", BlurPreview, UndefinedOptionFlag, MagickFalse },
+    { "Brightness", BrightnessPreview, UndefinedOptionFlag, MagickFalse },
+    { "Charcoal", CharcoalDrawingPreview, UndefinedOptionFlag, MagickFalse },
+    { "Despeckle", DespecklePreview, UndefinedOptionFlag, MagickFalse },
+    { "Dull", DullPreview, UndefinedOptionFlag, MagickFalse },
+    { "EdgeDetect", EdgeDetectPreview, UndefinedOptionFlag, MagickFalse },
+    { "Gamma", GammaPreview, UndefinedOptionFlag, MagickFalse },
+    { "Grayscale", GrayscalePreview, UndefinedOptionFlag, MagickFalse },
+    { "Hue", HuePreview, UndefinedOptionFlag, MagickFalse },
+    { "Implode", ImplodePreview, UndefinedOptionFlag, MagickFalse },
+    { "JPEG", JPEGPreview, UndefinedOptionFlag, MagickFalse },
+    { "OilPaint", OilPaintPreview, UndefinedOptionFlag, MagickFalse },
+    { "Quantize", QuantizePreview, UndefinedOptionFlag, MagickFalse },
+    { "Raise", RaisePreview, UndefinedOptionFlag, MagickFalse },
+    { "ReduceNoise", ReduceNoisePreview, UndefinedOptionFlag, MagickFalse },
+    { "Roll", RollPreview, UndefinedOptionFlag, MagickFalse },
+    { "Rotate", RotatePreview, UndefinedOptionFlag, MagickFalse },
+    { "Saturation", SaturationPreview, UndefinedOptionFlag, MagickFalse },
+    { "Segment", SegmentPreview, UndefinedOptionFlag, MagickFalse },
+    { "Shade", ShadePreview, UndefinedOptionFlag, MagickFalse },
+    { "Sharpen", SharpenPreview, UndefinedOptionFlag, MagickFalse },
+    { "Shear", ShearPreview, UndefinedOptionFlag, MagickFalse },
+    { "Solarize", SolarizePreview, UndefinedOptionFlag, MagickFalse },
+    { "Spiff", SpiffPreview, UndefinedOptionFlag, MagickFalse },
+    { "Spread", SpreadPreview, UndefinedOptionFlag, MagickFalse },
+    { "Swirl", SwirlPreview, UndefinedOptionFlag, MagickFalse },
+    { "Threshold", ThresholdPreview, UndefinedOptionFlag, MagickFalse },
+    { "Wave", WavePreview, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedPreview, UndefinedOptionFlag, MagickFalse }
+  },
+  PrimitiveOptions[] =
+  {
+    { "Undefined", UndefinedPrimitive, UndefinedOptionFlag, MagickTrue },
+    { "Arc", ArcPrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Bezier", BezierPrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Circle", CirclePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Color", ColorPrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Ellipse", EllipsePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Image", ImagePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Line", LinePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Matte", MattePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Path", PathPrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Point", PointPrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Polygon", PolygonPrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Polyline", PolylinePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Rectangle", RectanglePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "RoundRectangle", RoundRectanglePrimitive, UndefinedOptionFlag, MagickFalse },
+    { "Text", TextPrimitive, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedPrimitive, UndefinedOptionFlag, MagickFalse }
+  },
+  QuantumFormatOptions[] =
+  {
+    { "Undefined", UndefinedQuantumFormat, UndefinedOptionFlag, MagickTrue },
+    { "FloatingPoint", FloatingPointQuantumFormat, UndefinedOptionFlag, MagickFalse },
+    { "Signed", SignedQuantumFormat, UndefinedOptionFlag, MagickFalse },
+    { "Unsigned", UnsignedQuantumFormat, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, FloatingPointQuantumFormat, UndefinedOptionFlag, MagickFalse }
+  },
+  ResolutionOptions[] =
+  {
+    { "Undefined", UndefinedResolution, UndefinedOptionFlag, MagickTrue },
+    { "PixelsPerInch", PixelsPerInchResolution, UndefinedOptionFlag, MagickFalse },
+    { "PixelsPerCentimeter", PixelsPerCentimeterResolution, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedResolution, UndefinedOptionFlag, MagickFalse }
+  },
+  ResourceOptions[] =
+  {
+    { "Undefined", UndefinedResource, UndefinedOptionFlag, MagickTrue },
+    { "Area", AreaResource, UndefinedOptionFlag, MagickFalse },
+    { "Disk", DiskResource, UndefinedOptionFlag, MagickFalse },
+    { "File", FileResource, UndefinedOptionFlag, MagickFalse },
+    { "Map", MapResource, UndefinedOptionFlag, MagickFalse },
+    { "Memory", MemoryResource, UndefinedOptionFlag, MagickFalse },
+    { "Thread", ThreadResource, UndefinedOptionFlag, MagickFalse },
+    { "Time", TimeResource, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedResource, UndefinedOptionFlag, MagickFalse }
+  },
+  SparseColorOptions[] =
+  {
+    { "Undefined", UndefinedDistortion, UndefinedOptionFlag, MagickTrue },
+    { "Barycentric", BarycentricColorInterpolate, UndefinedOptionFlag, MagickFalse },
+    { "Bilinear", BilinearColorInterpolate, UndefinedOptionFlag, MagickFalse },
+    { "Inverse", InverseColorInterpolate, UndefinedOptionFlag, MagickFalse },
+    { "Shepards", ShepardsColorInterpolate, UndefinedOptionFlag, MagickFalse },
+    { "Voronoi", VoronoiColorInterpolate, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedResource, UndefinedOptionFlag, MagickFalse }
+  },
+  StatisticOptions[] =
+  {
+    { "Undefined", UndefinedStatistic, UndefinedOptionFlag, MagickTrue },
+    { "Gradient", GradientStatistic, UndefinedOptionFlag, MagickFalse },
+    { "Maximum", MaximumStatistic, UndefinedOptionFlag, MagickFalse },
+    { "Mean", MeanStatistic, UndefinedOptionFlag, MagickFalse },
+    { "Median", MedianStatistic, UndefinedOptionFlag, MagickFalse },
+    { "Minimum", MinimumStatistic, UndefinedOptionFlag, MagickFalse },
+    { "Mode", ModeStatistic, UndefinedOptionFlag, MagickFalse },
+    { "Nonpeak", NonpeakStatistic, UndefinedOptionFlag, MagickFalse },
+    { "StandardDeviation", StandardDeviationStatistic, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedMethod, UndefinedOptionFlag, MagickFalse }
+  },
+  StorageOptions[] =
+  {
+    { "Undefined", UndefinedPixel, UndefinedOptionFlag, MagickTrue },
+    { "Char", CharPixel, UndefinedOptionFlag, MagickFalse },
+    { "Double", DoublePixel, UndefinedOptionFlag, MagickFalse },
+    { "Float", FloatPixel, UndefinedOptionFlag, MagickFalse },
+    { "Integer", IntegerPixel, UndefinedOptionFlag, MagickFalse },
+    { "Long", LongPixel, UndefinedOptionFlag, MagickFalse },
+    { "Quantum", QuantumPixel, UndefinedOptionFlag, MagickFalse },
+    { "Short", ShortPixel, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedResource, UndefinedOptionFlag, MagickFalse }
+  },
+  StretchOptions[] =
+  {
+    { "Undefined", UndefinedStretch, UndefinedOptionFlag, MagickTrue },
+    { "Any", AnyStretch, UndefinedOptionFlag, MagickFalse },
+    { "Condensed", CondensedStretch, UndefinedOptionFlag, MagickFalse },
+    { "Expanded", ExpandedStretch, UndefinedOptionFlag, MagickFalse },
+    { "ExtraCondensed", ExtraCondensedStretch, UndefinedOptionFlag, MagickFalse },
+    { "ExtraExpanded", ExtraExpandedStretch, UndefinedOptionFlag, MagickFalse },
+    { "Normal", NormalStretch, UndefinedOptionFlag, MagickFalse },
+    { "SemiCondensed", SemiCondensedStretch, UndefinedOptionFlag, MagickFalse },
+    { "SemiExpanded", SemiExpandedStretch, UndefinedOptionFlag, MagickFalse },
+    { "UltraCondensed", UltraCondensedStretch, UndefinedOptionFlag, MagickFalse },
+    { "UltraExpanded", UltraExpandedStretch, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedStretch, UndefinedOptionFlag, MagickFalse }
+  },
+  StyleOptions[] =
+  {
+    { "Undefined", UndefinedStyle, UndefinedOptionFlag, MagickTrue },
+    { "Any", AnyStyle, UndefinedOptionFlag, MagickFalse },
+    { "Italic", ItalicStyle, UndefinedOptionFlag, MagickFalse },
+    { "Normal", NormalStyle, UndefinedOptionFlag, MagickFalse },
+    { "Oblique", ObliqueStyle, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedStyle, UndefinedOptionFlag, MagickFalse }
+  },
+  TypeOptions[] =
+  {
+    { "Undefined", UndefinedType, UndefinedOptionFlag, MagickTrue },
+    { "Bilevel", BilevelType, UndefinedOptionFlag, MagickFalse },
+    { "ColorSeparation", ColorSeparationType, UndefinedOptionFlag, MagickFalse },
+    { "ColorSeparationMatte", ColorSeparationMatteType, UndefinedOptionFlag, MagickFalse },
+    { "Grayscale", GrayscaleType, UndefinedOptionFlag, MagickFalse },
+    { "GrayscaleMatte", GrayscaleMatteType, UndefinedOptionFlag, MagickFalse },
+    { "Optimize", OptimizeType, UndefinedOptionFlag, MagickFalse },
+    { "Palette", PaletteType, UndefinedOptionFlag, MagickFalse },
+    { "PaletteBilevelMatte", PaletteBilevelMatteType, UndefinedOptionFlag, MagickFalse },
+    { "PaletteMatte", PaletteMatteType, UndefinedOptionFlag, MagickFalse },
+    { "TrueColorMatte", TrueColorMatteType, UndefinedOptionFlag, MagickFalse },
+    { "TrueColor", TrueColorType, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedType, UndefinedOptionFlag, MagickFalse }
+  },
+  ValidateOptions[] =
+  {
+    { "Undefined", UndefinedValidate, UndefinedOptionFlag, MagickTrue },
+    { "All", AllValidate, UndefinedOptionFlag, MagickFalse },
+    { "Compare", CompareValidate, UndefinedOptionFlag, MagickFalse },
+    { "Composite", CompositeValidate, UndefinedOptionFlag, MagickFalse },
+    { "Convert", ConvertValidate, UndefinedOptionFlag, MagickFalse },
+    { "FormatsInMemory", FormatsInMemoryValidate, UndefinedOptionFlag, MagickFalse },
+    { "FormatsOnDisk", FormatsOnDiskValidate, UndefinedOptionFlag, MagickFalse },
+    { "Identify", IdentifyValidate, UndefinedOptionFlag, MagickFalse },
+    { "ImportExport", ImportExportValidate, UndefinedOptionFlag, MagickFalse },
+    { "Montage", MontageValidate, UndefinedOptionFlag, MagickFalse },
+    { "Stream", StreamValidate, UndefinedOptionFlag, MagickFalse },
+    { "None", NoValidate, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedValidate, UndefinedOptionFlag, MagickFalse }
+  },
+  VirtualPixelOptions[] =
+  {
+    { "Undefined", UndefinedVirtualPixelMethod, UndefinedOptionFlag, MagickTrue },
+    { "Background", BackgroundVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Black", BlackVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Constant", BackgroundVirtualPixelMethod, DeprecateOptionFlag, MagickTrue },
+    { "CheckerTile", CheckerTileVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Dither", DitherVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Edge", EdgeVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Gray", GrayVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "HorizontalTile", HorizontalTileVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "HorizontalTileEdge", HorizontalTileEdgeVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Mirror", MirrorVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Random", RandomVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Tile", TileVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "Transparent", TransparentVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "VerticalTile", VerticalTileVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "VerticalTileEdge", VerticalTileEdgeVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { "White", WhiteVirtualPixelMethod, UndefinedOptionFlag, MagickFalse },
+    { (char *) NULL, UndefinedVirtualPixelMethod, UndefinedOptionFlag, MagickFalse }
+  };
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e O p t i o n s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageOptions() clones one or more image options.
+%
+%  The format of the CloneImageOptions method is:
+%
+%      MagickBooleanType CloneImageOptions(ImageInfo *image_info,
+%        const ImageInfo *clone_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o clone_info: the clone image info.
+%
+*/
+MagickExport MagickBooleanType CloneImageOptions(ImageInfo *image_info,
+  const ImageInfo *clone_info)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(clone_info != (const ImageInfo *) NULL);
+  assert(clone_info->signature == MagickSignature);
+  if (clone_info->options != (void *) NULL)
+    image_info->options=CloneSplayTree((SplayTreeInfo *) clone_info->options,
+      (void *(*)(void *)) ConstantString,(void *(*)(void *)) ConstantString);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e f i n e I m a g e O p t i o n                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineImageOption() associates a key/value pair with an image option.
+%
+%  The format of the DefineImageOption method is:
+%
+%      MagickBooleanType DefineImageOption(ImageInfo *image_info,
+%        const char *option)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o option: the image option.
+%
+*/
+MagickExport MagickBooleanType DefineImageOption(ImageInfo *image_info,
+  const char *option)
+{
+  char
+    key[MaxTextExtent],
+    value[MaxTextExtent];
+
+  register char
+    *p;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(option != (const char *) NULL);
+  (void) CopyMagickString(key,option,MaxTextExtent);
+  for (p=key; *p != '\0'; p++)
+    if (*p == '=')
+      break;
+  *value='\0';
+  if (*p == '=')
+    (void) CopyMagickString(value,p+1,MaxTextExtent);
+  *p='\0';
+  return(SetImageOption(image_info,key,value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e O p t i o n                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageOption() deletes an key from the image map.
+%
+%  The format of the DeleteImageOption method is:
+%
+%      MagickBooleanType DeleteImageOption(ImageInfo *image_info,
+%        const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o option: the image option.
+%
+*/
+MagickExport MagickBooleanType DeleteImageOption(ImageInfo *image_info,
+  const char *option)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options == (void *) NULL)
+    return(MagickFalse);
+  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image_info->options,option));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e O p t i o n s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageOptions() releases memory associated with image option values.
+%
+%  The format of the DestroyDefines method is:
+%
+%      void DestroyImageOptions(ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport void DestroyImageOptions(ImageInfo *image_info)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options != (void *) NULL)
+    image_info->options=DestroySplayTree((SplayTreeInfo *) image_info->options);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e O p t i o n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageOption() gets a value associated with an image option.
+%
+%  The format of the GetImageOption method is:
+%
+%      const char *GetImageOption(const ImageInfo *image_info,
+%        const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o key: the key.
+%
+*/
+MagickExport const char *GetImageOption(const ImageInfo *image_info,
+  const char *key)
+{
+  const char
+    *option;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options == (void *) NULL)
+    return((const char *) NULL);
+  option=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+    image_info->options,key);
+  return(option);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o m m a n d O p t i o n F l a g s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCommandOptionFlags() parses a string and returns an enumerated option
+%  flags(s).  Return a value of -1 if no such option is found.
+%
+%  The format of the GetCommandOptionFlags method is:
+%
+%      ssize_t GetCommandOptionFlags(const CommandOption option,
+%        const MagickBooleanType list,const char *options)
+%
+%  A description of each parameter follows:
+%
+%    o option: Index to the option table to lookup
+%
+%    o list: A option other than zero permits more than one option separated by
+%      a comma or pipe.
+%
+%    o options: One or more options separated by commas.
+%
+*/
+
+static const OptionInfo *GetOptionInfo(const CommandOption option)
+{
+  switch (option)
+  {
+    case MagickAlignOptions: return(AlignOptions);
+    case MagickAlphaOptions: return(AlphaOptions);
+    case MagickBooleanOptions: return(BooleanOptions);
+    case MagickChannelOptions: return(ChannelOptions);
+    case MagickClassOptions: return(ClassOptions);
+    case MagickClipPathOptions: return(ClipPathOptions);
+    case MagickColorspaceOptions: return(ColorspaceOptions);
+    case MagickCommandOptions: return(CommandOptions);
+    case MagickComposeOptions: return(ComposeOptions);
+    case MagickCompressOptions: return(CompressOptions);
+    case MagickDataTypeOptions: return(DataTypeOptions);
+    case MagickDebugOptions: return(LogEventOptions);
+    case MagickDecorateOptions: return(DecorateOptions);
+    case MagickDirectionOptions: return(DirectionOptions);
+    case MagickDisposeOptions: return(DisposeOptions);
+    case MagickDistortOptions: return(DistortOptions);
+    case MagickDitherOptions: return(DitherOptions);
+    case MagickEndianOptions: return(EndianOptions);
+    case MagickEvaluateOptions: return(EvaluateOptions);
+    case MagickFillRuleOptions: return(FillRuleOptions);
+    case MagickFilterOptions: return(FilterOptions);
+    case MagickFunctionOptions: return(FunctionOptions);
+    case MagickGravityOptions: return(GravityOptions);
+/*  case MagickImageListOptions: return(ImageListOptions); */
+    case MagickIntentOptions: return(IntentOptions);
+    case MagickInterlaceOptions: return(InterlaceOptions);
+    case MagickInterpolateOptions: return(InterpolateOptions);
+    case MagickKernelOptions: return(KernelOptions);
+    case MagickLayerOptions: return(LayerOptions);
+    case MagickLineCapOptions: return(LineCapOptions);
+    case MagickLineJoinOptions: return(LineJoinOptions);
+    case MagickListOptions: return(ListOptions);
+    case MagickLogEventOptions: return(LogEventOptions);
+    case MagickMetricOptions: return(MetricOptions);
+    case MagickMethodOptions: return(MethodOptions);
+    case MagickModeOptions: return(ModeOptions);
+    case MagickMorphologyOptions: return(MorphologyOptions);
+    case MagickNoiseOptions: return(NoiseOptions);
+    case MagickOrientationOptions: return(OrientationOptions);
+    case MagickPolicyDomainOptions: return(PolicyDomainOptions);
+    case MagickPolicyRightsOptions: return(PolicyRightsOptions);
+    case MagickPreviewOptions: return(PreviewOptions);
+    case MagickPrimitiveOptions: return(PrimitiveOptions);
+    case MagickQuantumFormatOptions: return(QuantumFormatOptions);
+    case MagickResolutionOptions: return(ResolutionOptions);
+    case MagickResourceOptions: return(ResourceOptions);
+    case MagickSparseColorOptions: return(SparseColorOptions);
+    case MagickStatisticOptions: return(StatisticOptions);
+    case MagickStorageOptions: return(StorageOptions);
+    case MagickStretchOptions: return(StretchOptions);
+    case MagickStyleOptions: return(StyleOptions);
+    case MagickTypeOptions: return(TypeOptions);
+    case MagickValidateOptions: return(ValidateOptions);
+    case MagickVirtualPixelOptions: return(VirtualPixelOptions);
+    default: break;
+  }
+  return((const OptionInfo *) NULL);
+}
+
+MagickExport ssize_t GetCommandOptionFlags(const CommandOption option,
+  const MagickBooleanType list,const char *options)
+{
+  char
+    token[MaxTextExtent];
+
+  const OptionInfo
+    *option_info;
+
+  int
+    sentinel;
+
+  MagickBooleanType
+    negate;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    option_types;
+
+  option_info=GetOptionInfo(option);
+  if (option_info == (const OptionInfo *) NULL)
+    return(-1);
+  option_types=0;
+  sentinel=',';
+  if (strchr(options,'|') != (char *) NULL)
+    sentinel='|';
+  for (p=options; p != (char *) NULL; p=strchr(p,sentinel))
+  {
+    while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == sentinel)) &&
+           (*p != '\0'))
+      p++;
+    negate=(*p == '!') ? MagickTrue : MagickFalse;
+    if (negate != MagickFalse)
+      p++;
+    q=token;
+    while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != sentinel)) &&
+           (*p != '\0'))
+    {
+      if ((q-token) >= (MaxTextExtent-1))
+        break;
+      *q++=(*p++);
+    }
+    *q='\0';
+    for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
+      if (LocaleCompare(token,option_info[i].mnemonic) == 0)
+        {
+          if (*token == '!')
+            option_types=option_types &~ option_info[i].flags;
+          else
+            option_types=option_types | option_info[i].flags;
+          break;
+        }
+    if ((option_info[i].mnemonic == (char *) NULL) &&
+        ((strchr(token+1,'-') != (char *) NULL) ||
+         (strchr(token+1,'_') != (char *) NULL)))
+      {
+        while ((q=strchr(token+1,'-')) != (char *) NULL)
+          (void) CopyMagickString(q,q+1,MaxTextExtent-strlen(q));
+        while ((q=strchr(token+1,'_')) != (char *) NULL)
+          (void) CopyMagickString(q,q+1,MaxTextExtent-strlen(q));
+        for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
+          if (LocaleCompare(token,option_info[i].mnemonic) == 0)
+            {
+              if (*token == '!')
+                option_types=option_types &~ option_info[i].flags;
+              else
+                option_types=option_types | option_info[i].flags;
+              break;
+            }
+      }
+    if (option_info[i].mnemonic == (char *) NULL)
+      return(-1);
+    if (list == MagickFalse)
+      break;
+  }
+  return(option_types);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t C o m m a n d O p t i o n s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCommandOptions() returns a list of values.
+%
+%  The format of the GetCommandOptions method is:
+%
+%      const char **GetCommandOptions(const CommandOption value)
+%
+%  A description of each parameter follows:
+%
+%    o value: the value.
+%
+*/
+MagickExport char **GetCommandOptions(const CommandOption value)
+{
+  char
+    **values;
+
+  const OptionInfo
+    *option_info;
+
+  register ssize_t
+    i;
+
+  option_info=GetOptionInfo(value);
+  if (option_info == (const OptionInfo *) NULL)
+    return((char **) NULL);
+  for (i=0; option_info[i].mnemonic != (const char *) NULL; i++) ;
+  values=(char **) AcquireQuantumMemory((size_t) i+1UL,sizeof(*values));
+  if (values == (char **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  for (i=0; option_info[i].mnemonic != (const char *) NULL; i++)
+    values[i]=AcquireString(option_info[i].mnemonic);
+  values[i]=(char *) NULL;
+  return(values);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e O p t i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageOption() gets the next image option value.
+%
+%  The format of the GetNextImageOption method is:
+%
+%      char *GetNextImageOption(const ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport char *GetNextImageOption(const ImageInfo *image_info)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options == (void *) NULL)
+    return((char *) NULL);
+  return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image_info->options));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     I s C o m m a n d O p t i o n                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsCommandOption() returns MagickTrue if the option begins with a - or + and
+%  the first character that follows is alphanumeric.
+%
+%  The format of the IsCommandOption method is:
+%
+%      MagickBooleanType IsCommandOption(const char *option)
+%
+%  A description of each parameter follows:
+%
+%    o option: the option.
+%
+*/
+MagickExport MagickBooleanType IsCommandOption(const char *option)
+{
+  assert(option != (const char *) NULL);
+  if ((*option != '-') && (*option != '+'))
+    return(MagickFalse);
+  if (strlen(option) == 1)
+    return(MagickFalse);
+  option++;
+  if (isalpha((int) ((unsigned char) *option)) == 0)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m m a n d O p t i o n T o M n e m o n i c                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CommandOptionToMnemonic() returns an enumerated value as a mnemonic.
+%
+%  The format of the CommandOptionToMnemonic method is:
+%
+%      const char *CommandOptionToMnemonic(const CommandOption option,
+%        const ssize_t type)
+%
+%  A description of each parameter follows:
+%
+%    o option: the option.
+%
+%    o type: one or more values separated by commas.
+%
+*/
+MagickExport const char *CommandOptionToMnemonic(const CommandOption option,
+  const ssize_t type)
+{
+  const OptionInfo
+    *option_info;
+
+  register ssize_t
+    i;
+
+  option_info=GetOptionInfo(option);
+  if (option_info == (const OptionInfo *) NULL)
+    return((const char *) NULL);
+  for (i=0; option_info[i].mnemonic != (const char *) NULL; i++)
+    if (type == option_info[i].type)
+      break;
+  if (option_info[i].mnemonic == (const char *) NULL)
+    return("undefined");
+  return(option_info[i].mnemonic);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L i s t C o m m a n d O p t i o n s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListCommandOptions() lists the contents of enumerated option type(s).
+%
+%  The format of the ListCommandOptions method is:
+%
+%      MagickBooleanType ListCommandOptions(FILE *file,const CommandOption option,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o file:  list options to this file handle.
+%
+%    o option:  list these options.
+%
+%    o exception:  return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListCommandOptions(FILE *file,
+  const CommandOption option,ExceptionInfo *magick_unused(exception))
+{
+  const OptionInfo
+    *option_info;
+
+  register ssize_t
+    i;
+
+  if (file == (FILE *) NULL)
+    file=stdout;
+  option_info=GetOptionInfo(option);
+  if (option_info == (const OptionInfo *) NULL)
+    return(MagickFalse);
+  for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
+  {
+    if (option_info[i].stealth != MagickFalse)
+      continue;
+    (void) FormatLocaleFile(file,"%s\n",option_info[i].mnemonic);
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e C h a n n e l O p t i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseChannelOption() parses a string and returns an enumerated channel
+%  type(s).
+%
+%  The format of the ParseChannelOption method is:
+%
+%      ssize_t ParseChannelOption(const char *channels)
+%
+%  A description of each parameter follows:
+%
+%    o options: One or more values separated by commas.
+%
+*/
+MagickExport ssize_t ParseChannelOption(const char *channels)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    channel;
+
+  channel=ParseCommandOption(MagickChannelOptions,MagickTrue,channels);
+  if (channel >= 0)
+    return(channel);
+  channel=0;
+  for (i=0; i < (ssize_t) strlen(channels); i++)
+  {
+    switch (channels[i])
+    {
+      case 'A':
+      case 'a':
+      {
+        channel|=OpacityChannel;
+        break;
+      }
+      case 'B':
+      case 'b':
+      {
+        channel|=BlueChannel;
+        break;
+      }
+      case 'C':
+      case 'c':
+      {
+        channel|=CyanChannel;
+        break;
+      }
+      case 'g':
+      case 'G':
+      {
+        channel|=GreenChannel;
+        break;
+      }
+      case 'K':
+      case 'k':
+      {
+        channel|=BlackChannel;
+        break;
+      }
+      case 'M':
+      case 'm':
+      {
+        channel|=MagentaChannel;
+        break;
+      }
+      case 'o':
+      case 'O':
+      {
+        channel|=OpacityChannel;
+        break;
+      }
+      case 'R':
+      case 'r':
+      {
+        channel|=RedChannel;
+        break;
+      }
+      case 'Y':
+      case 'y':
+      {
+        channel|=YellowChannel;
+        break;
+      }
+      case ',':
+      {
+        ssize_t
+          type;
+
+        /*
+          Gather the additional channel flags and merge with shorthand.
+        */
+        type=ParseCommandOption(MagickChannelOptions,MagickTrue,channels+i+1);
+        if (type < 0)
+          return(type);
+        channel|=type;
+        return(channel);
+      }
+      default:
+        return(-1);
+    }
+  }
+  return(channel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P a r s e C o m m a n d O p t i o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ParseCommandOption() parses a string and returns an enumerated option
+%  type(s).  Return a value of -1 if no such option is found.
+%
+%  The format of the ParseCommandOption method is:
+%
+%      ssize_t ParseCommandOption(const CommandOption option,
+%        const MagickBooleanType list,const char *options)
+%
+%  A description of each parameter follows:
+%
+%    o option: Index to the option table to lookup
+%
+%    o list: A option other than zero permits more than one option separated by
+%      a comma or pipe.
+%
+%    o options: One or more options separated by commas.
+%
+*/
+MagickExport ssize_t ParseCommandOption(const CommandOption option,
+  const MagickBooleanType list,const char *options)
+{
+  char
+    token[MaxTextExtent];
+
+  const OptionInfo
+    *option_info;
+
+  int
+    sentinel;
+
+  MagickBooleanType
+    negate;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    option_types;
+
+  option_info=GetOptionInfo(option);
+  if (option_info == (const OptionInfo *) NULL)
+    return(-1);
+  option_types=0;
+  sentinel=',';
+  if (strchr(options,'|') != (char *) NULL)
+    sentinel='|';
+  for (p=options; p != (char *) NULL; p=strchr(p,sentinel))
+  {
+    while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == sentinel)) &&
+           (*p != '\0'))
+      p++;
+    negate=(*p == '!') ? MagickTrue : MagickFalse;
+    if (negate != MagickFalse)
+      p++;
+    q=token;
+    while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != sentinel)) &&
+           (*p != '\0'))
+    {
+      if ((q-token) >= (MaxTextExtent-1))
+        break;
+      *q++=(*p++);
+    }
+    *q='\0';
+    for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
+      if (LocaleCompare(token,option_info[i].mnemonic) == 0)
+        {
+          if (*token == '!')
+            option_types=option_types &~ option_info[i].type;
+          else
+            option_types=option_types | option_info[i].type;
+          break;
+        }
+    if ((option_info[i].mnemonic == (char *) NULL) &&
+        ((strchr(token+1,'-') != (char *) NULL) ||
+         (strchr(token+1,'_') != (char *) NULL)))
+      {
+        while ((q=strchr(token+1,'-')) != (char *) NULL)
+          (void) CopyMagickString(q,q+1,MaxTextExtent-strlen(q));
+        while ((q=strchr(token+1,'_')) != (char *) NULL)
+          (void) CopyMagickString(q,q+1,MaxTextExtent-strlen(q));
+        for (i=0; option_info[i].mnemonic != (char *) NULL; i++)
+          if (LocaleCompare(token,option_info[i].mnemonic) == 0)
+            {
+              if (*token == '!')
+                option_types=option_types &~ option_info[i].type;
+              else
+                option_types=option_types | option_info[i].type;
+              break;
+            }
+      }
+    if (option_info[i].mnemonic == (char *) NULL)
+      return(-1);
+    if (list == MagickFalse)
+      break;
+  }
+  return(option_types);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e I m a g e O p t i o n                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveImageOption() removes an option from the image and returns its value.
+%
+%  The format of the RemoveImageOption method is:
+%
+%      char *RemoveImageOption(ImageInfo *image_info,const char *option)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o option: the image option.
+%
+*/
+MagickExport char *RemoveImageOption(ImageInfo *image_info,const char *option)
+{
+  char
+    *value;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options == (void *) NULL)
+    return((char *) NULL);
+  value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *)
+    image_info->options,option);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e O p t i o n                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImageOptions() resets the image_info option.  That is, it deletes
+%  all options associated with the image_info structure.
+%
+%  The format of the ResetImageOptions method is:
+%
+%      ResetImageOptions(ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport void ResetImageOptions(const ImageInfo *image_info)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options == (void *) NULL)
+    return;
+  ResetSplayTree((SplayTreeInfo *) image_info->options);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e O p t i o n I t e r a t o r                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImageOptionIterator() resets the image_info values iterator.  Use it
+%  in conjunction with GetNextImageOption() to iterate over all the values
+%  associated with an image option.
+%
+%  The format of the ResetImageOptionIterator method is:
+%
+%      ResetImageOptionIterator(ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport void ResetImageOptionIterator(const ImageInfo *image_info)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (image_info->options == (void *) NULL)
+    return;
+  ResetSplayTreeIterator((SplayTreeInfo *) image_info->options);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e O p t i o n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageOption() associates an value with an image option.
+%
+%  The format of the SetImageOption method is:
+%
+%      MagickBooleanType SetImageOption(ImageInfo *image_info,
+%        const char *option,const char *value)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o option: the image option.
+%
+%    o values: the image option values.
+%
+*/
+MagickExport MagickBooleanType SetImageOption(ImageInfo *image_info,
+  const char *option,const char *value)
+{
+  MagickBooleanType
+    status;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  if (LocaleCompare(option,"size") == 0)
+    (void) CloneString(&image_info->size,value);
+  if (image_info->options == (void *) NULL)
+    image_info->options=NewSplayTree(CompareSplayTreeString,
+      RelinquishMagickMemory,RelinquishMagickMemory);
+  status=AddValueToSplayTree((SplayTreeInfo *) image_info->options,
+    ConstantString(option),ConstantString(value));
+  return(status);
+}
diff --git a/MagickCore/option.h b/MagickCore/option.h
new file mode 100644
index 0000000..732f24e
--- /dev/null
+++ b/MagickCore/option.h
@@ -0,0 +1,177 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore option methods.
+*/
+#ifndef _MAGICKCORE_OPTION_H
+#define _MAGICKCORE_OPTION_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  MagickUndefinedOptions = -1,
+  MagickAlignOptions = 0,
+  MagickAlphaOptions,
+  MagickBooleanOptions,
+  MagickChannelOptions,
+  MagickClassOptions,
+  MagickClipPathOptions,
+  MagickCoderOptions,
+  MagickColorOptions,
+  MagickColorspaceOptions,
+  MagickCommandOptions,
+  MagickComposeOptions,
+  MagickCompressOptions,
+  MagickConfigureOptions,
+  MagickDataTypeOptions,
+  MagickDebugOptions,
+  MagickDecorateOptions,
+  MagickDelegateOptions,
+  MagickDirectionOptions,
+  MagickDisposeOptions,
+  MagickDistortOptions,
+  MagickDitherOptions,
+  MagickEndianOptions,
+  MagickEvaluateOptions,
+  MagickFillRuleOptions,
+  MagickFilterOptions,
+  MagickFontOptions,
+  MagickFontsOptions,
+  MagickFormatOptions,
+  MagickFunctionOptions,
+  MagickGravityOptions,
+  MagickIntentOptions,
+  MagickInterlaceOptions,
+  MagickInterpolateOptions,
+  MagickKernelOptions,
+  MagickLayerOptions,
+  MagickLineCapOptions,
+  MagickLineJoinOptions,
+  MagickListOptions,
+  MagickLocaleOptions,
+  MagickLogEventOptions,
+  MagickLogOptions,
+  MagickMagicOptions,
+  MagickMethodOptions,
+  MagickMetricOptions,
+  MagickMimeOptions,
+  MagickModeOptions,
+  MagickModuleOptions,
+  MagickMorphologyOptions,
+  MagickNoiseOptions,
+  MagickOrientationOptions,
+  MagickPolicyOptions,
+  MagickPolicyDomainOptions,
+  MagickPolicyRightsOptions,
+  MagickPreviewOptions,
+  MagickPrimitiveOptions,
+  MagickQuantumFormatOptions,
+  MagickResolutionOptions,
+  MagickResourceOptions,
+  MagickSparseColorOptions,
+  MagickStatisticOptions,
+  MagickStorageOptions,
+  MagickStretchOptions,
+  MagickStyleOptions,
+  MagickThresholdOptions,
+  MagickTypeOptions,
+  MagickValidateOptions,
+  MagickVirtualPixelOptions
+} CommandOption;
+
+typedef enum
+{
+  UndefinedValidate,
+  NoValidate = 0x00000,
+  CompareValidate = 0x00001,
+  CompositeValidate = 0x00002,
+  ConvertValidate = 0x00004,
+  FormatsInMemoryValidate = 0x00008,
+  FormatsOnDiskValidate = 0x00010,
+  IdentifyValidate = 0x00020,
+  ImportExportValidate = 0x00040,
+  MontageValidate = 0x00080,
+  StreamValidate = 0x00100,
+  AllValidate = 0x7fffffff
+} ValidateType;
+
+typedef struct _OptionInfo
+{
+  const char
+    *mnemonic;
+
+  ssize_t
+    type,
+    flags;
+
+  MagickBooleanType
+    stealth;
+} OptionInfo;
+
+/*
+  Flags to describe classes of image processing options.
+*/
+typedef enum
+{
+  UndefinedOptionFlag       = 0x0000,
+  FireOptionFlag            = 0x0001,  /* Option sequence firing point */
+  ImageInfoOptionFlag       = 0x0002,  /* Sets ImageInfo, no image needed */
+  DrawInfoOptionFlag        = 0x0004,  /* Sets DrawInfo, no image needed */
+  QuantizeInfoOptionFlag    = 0x0008,  /* Sets QuantizeInfo, no image needed */
+  GlobalOptionFlag          = 0x0010,  /* Sets Global Option, no image needed */
+  SimpleOperatorOptionFlag  = 0x0100,  /* Simple Image processing operator */
+  ListOperatorOptionFlag    = 0x0200,  /* Multi-Image List processing operator */
+  SpecialOperatorOptionFlag = 0x0400,  /* Specially handled Operator Option */
+  GenesisOptionFlag         = 0x0400,  /* Genesis Command Wrapper Option  */
+  NonConvertOptionFlag      = 0x4000,  /* Option not used by Convert */
+  DeprecateOptionFlag       = 0x8000   /* Deprecate option, give warning */
+} CommandOptionFlags;
+
+extern MagickExport char
+  **GetCommandOptions(const CommandOption),
+  *GetNextImageOption(const ImageInfo *),
+  *RemoveImageOption(ImageInfo *,const char *);
+
+extern MagickExport const char
+  *CommandOptionToMnemonic(const CommandOption,const ssize_t),
+  *GetImageOption(const ImageInfo *,const char *);
+
+extern MagickExport MagickBooleanType
+  CloneImageOptions(ImageInfo *,const ImageInfo *),
+  DefineImageOption(ImageInfo *,const char *),
+  DeleteImageOption(ImageInfo *,const char *),
+  IsCommandOption(const char *),
+  ListCommandOptions(FILE *,const CommandOption,ExceptionInfo *),
+  SetImageOption(ImageInfo *,const char *,const char *);
+
+extern MagickExport ssize_t
+  GetCommandOptionFlags(const CommandOption,const MagickBooleanType,
+    const char *),
+  ParseChannelOption(const char *),
+  ParseCommandOption(const CommandOption,const MagickBooleanType,const char *);
+
+extern MagickExport void
+  DestroyImageOptions(ImageInfo *),
+  ResetImageOptions(const ImageInfo *),
+  ResetImageOptionIterator(const ImageInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/paint.c b/MagickCore/paint.c
new file mode 100644
index 0000000..e61431f
--- /dev/null
+++ b/MagickCore/paint.c
@@ -0,0 +1,1118 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      PPPP    AAA   IIIII  N   N  TTTTT                      %
+%                      P   P  A   A    I    NN  N    T                        %
+%                      PPPP   AAAAA    I    N N N    T                        %
+%                      P      A   A    I    N  NN    T                        %
+%                      P      A   A  IIIII  N   N    T                        %
+%                                                                             %
+%                                                                             %
+%                        Methods to Paint on an Image                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1998                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+ Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/draw-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F l o o d f i l l P a i n t I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FloodfillPaintImage() changes the color value of any pixel that matches
+%  target and is an immediate neighbor.  If the method FillToBorderMethod is
+%  specified, the color value is changed for any neighbor pixel that does not
+%  match the bordercolor member of image.
+%
+%  By default target must match a particular pixel color exactly.
+%  However, in many cases two colors may differ by a small amount.  The
+%  fuzz member of image defines how much tolerance is acceptable to
+%  consider two colors as the same.  For example, set fuzz to 10 and the
+%  color red at intensities of 100 and 102 respectively are now
+%  interpreted as the same color for the purposes of the floodfill.
+%
+%  The format of the FloodfillPaintImage method is:
+%
+%      MagickBooleanType FloodfillPaintImage(Image *image,
+%        const ChannelType channel,const DrawInfo *draw_info,
+%        const PixelInfo target,const ssize_t x_offset,
+%        const ssize_t y_offset,const MagickBooleanType invert)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel(s).
+%
+%    o draw_info: the draw info.
+%
+%    o target: the RGB value of the target color.
+%
+%    o x_offset,y_offset: the starting location of the operation.
+%
+%    o invert: paint any pixel that does not match the target color.
+%
+*/
+MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
+  const ChannelType channel,const DrawInfo *draw_info,
+  const PixelInfo *target,const ssize_t x_offset,const ssize_t y_offset,
+  const MagickBooleanType invert)
+{
+#define MaxStacksize  (1UL << 15)
+#define PushSegmentStack(up,left,right,delta) \
+{ \
+  if (s >= (segment_stack+MaxStacksize)) \
+    ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
+  else \
+    { \
+      if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \
+        { \
+          s->x1=(double) (left); \
+          s->y1=(double) (up); \
+          s->x2=(double) (right); \
+          s->y2=(double) (delta); \
+          s++; \
+        } \
+    } \
+}
+
+  CacheView
+    *floodplane_view,
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *floodplane_image;
+
+  MagickBooleanType
+    skip;
+
+  PixelInfo
+    fill,
+    pixel;
+
+  PixelPacket
+    fill_color;
+
+  register SegmentInfo
+    *s;
+
+  SegmentInfo
+    *segment_stack;
+
+  ssize_t
+    offset,
+    start,
+    x,
+    x1,
+    x2,
+    y;
+
+  /*
+    Check boundary conditions.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(draw_info != (DrawInfo *) NULL);
+  assert(draw_info->signature == MagickSignature);
+  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
+    return(MagickFalse);
+  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
+    return(MagickFalse);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  /*
+    Set floodfill state.
+  */
+  floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+  if (floodplane_image == (Image *) NULL)
+    return(MagickFalse);
+  (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
+  segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
+    sizeof(*segment_stack));
+  if (segment_stack == (SegmentInfo *) NULL)
+    {
+      floodplane_image=DestroyImage(floodplane_image);
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  /*
+    Push initial segment on stack.
+  */
+  exception=(&image->exception);
+  x=x_offset;
+  y=y_offset;
+  start=0;
+  s=segment_stack;
+  PushSegmentStack(y,x,x,1);
+  PushSegmentStack(y+1,x,x,-1);
+  GetPixelInfo(image,&fill);
+  GetPixelInfo(image,&pixel);
+  image_view=AcquireCacheView(image);
+  floodplane_view=AcquireCacheView(floodplane_image);
+  while (s > segment_stack)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    /*
+      Pop segment off stack.
+    */
+    s--;
+    x1=(ssize_t) s->x1;
+    x2=(ssize_t) s->x2;
+    offset=(ssize_t) s->y2;
+    y=(ssize_t) s->y1+offset;
+    /*
+      Recolor neighboring pixels.
+    */
+    p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception);
+    q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      break;
+    p+=x1*GetPixelChannels(image);
+    q+=x1*GetPixelChannels(floodplane_image);
+    for (x=x1; x >= 0; x--)
+    {
+      if (GetPixelAlpha(image,q) == TransparentAlpha)
+        break;
+      SetPixelInfo(image,p,&pixel);
+      if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
+        break;
+      SetPixelAlpha(floodplane_image,TransparentAlpha,q);
+      p-=GetPixelChannels(image);
+      q-=GetPixelChannels(floodplane_image);
+    }
+    if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
+      break;
+    skip=x >= x1 ? MagickTrue : MagickFalse;
+    if (skip == MagickFalse)
+      {
+        start=x+1;
+        if (start < x1)
+          PushSegmentStack(y,start,x1-1,-offset);
+        x=x1+1;
+      }
+    do
+    {
+      if (skip == MagickFalse)
+        {
+          if (x < (ssize_t) image->columns)
+            {
+              p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
+                exception);
+              q=GetCacheViewAuthenticPixels(floodplane_view,x,y,
+                image->columns-x,1,exception);
+              if ((p == (const Quantum *) NULL) ||
+                  (q == (Quantum *) NULL))
+                break;
+              for ( ; x < (ssize_t) image->columns; x++)
+              {
+                if (GetPixelAlpha(image,q) == TransparentAlpha)
+                  break;
+                SetPixelInfo(image,p,&pixel);
+                if (IsFuzzyEquivalencePixelInfo(&pixel,target) == invert)
+                  break;
+                SetPixelAlpha(floodplane_image,
+                  TransparentAlpha,q);
+                p+=GetPixelChannels(image);
+                q+=GetPixelChannels(floodplane_image);
+              }
+              if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
+                break;
+            }
+          PushSegmentStack(y,start,x-1,offset);
+          if (x > (x2+1))
+            PushSegmentStack(y,x2+1,x-1,-offset);
+        }
+      skip=MagickFalse;
+      x++;
+      if (x <= x2)
+        {
+          p=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1,
+            exception);
+          q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
+            exception);
+          if ((p == (const Quantum *) NULL) ||
+              (q == (Quantum *) NULL))
+            break;
+          for ( ; x <= x2; x++)
+          {
+            if (GetPixelAlpha(image,q) == TransparentAlpha)
+              break;
+            SetPixelInfo(image,p,&pixel);
+            if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
+              break;
+            p+=GetPixelChannels(image);
+            q+=GetPixelChannels(floodplane_image);
+          }
+        }
+      start=x;
+    } while (x <= x2);
+  }
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    /*
+      Tile fill color onto floodplane.
+    */
+    p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,
+      exception);
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (GetPixelAlpha(floodplane_image,p) != OpaqueAlpha)
+        {
+          (void) GetFillColor(draw_info,x,y,&fill_color);
+          SetPixelInfoPacket(image,&fill_color,&fill);
+          if (image->colorspace == CMYKColorspace)
+            ConvertRGBToCMYK(&fill);
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(image,ClampToQuantum(fill.red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(image,ClampToQuantum(fill.green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(image,ClampToQuantum(fill.blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(image,ClampToQuantum(fill.black),q);
+          if ((channel & AlphaChannel) != 0)
+            SetPixelAlpha(image,ClampToQuantum(fill.alpha),q);
+        }
+      p+=GetPixelChannels(floodplane_image);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      break;
+  }
+  floodplane_view=DestroyCacheView(floodplane_view);
+  image_view=DestroyCacheView(image_view);
+  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
+  floodplane_image=DestroyImage(floodplane_image);
+  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     G r a d i e n t I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GradientImage() applies a continuously smooth color transitions along a
+%  vector from one color to another.
+%
+%  Note, the interface of this method will change in the future to support
+%  more than one transistion.
+%
+%  The format of the GradientImage method is:
+%
+%      MagickBooleanType GradientImage(Image *image,const GradientType type,
+%        const SpreadMethod method,const PixelPacket *start_color,
+%        const PixelPacket *stop_color)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o type: the gradient type: linear or radial.
+%
+%    o spread: the gradient spread meathod: pad, reflect, or repeat.
+%
+%    o start_color: the start color.
+%
+%    o stop_color: the stop color.
+%
+*/
+
+static inline double MagickMax(const double x,const double y)
+{
+  return(x > y ? x : y);
+}
+
+MagickExport MagickBooleanType GradientImage(Image *image,
+  const GradientType type,const SpreadMethod method,
+  const PixelPacket *start_color,const PixelPacket *stop_color)
+{
+  DrawInfo
+    *draw_info;
+
+  GradientInfo
+    *gradient;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Set gradient start-stop end points.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(start_color != (const PixelPacket *) NULL);
+  assert(stop_color != (const PixelPacket *) NULL);
+  draw_info=AcquireDrawInfo();
+  gradient=(&draw_info->gradient);
+  gradient->type=type;
+  gradient->bounding_box.width=image->columns;
+  gradient->bounding_box.height=image->rows;
+  gradient->gradient_vector.x2=(double) image->columns-1.0;
+  gradient->gradient_vector.y2=(double) image->rows-1.0;
+  if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
+    gradient->gradient_vector.x2=0.0;
+  gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
+  gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
+  gradient->radius=MagickMax(gradient->center.x,gradient->center.y);
+  gradient->spread=method;
+  /*
+    Define the gradient to fill between the stops.
+  */
+  gradient->number_stops=2;
+  gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
+    sizeof(*gradient->stops));
+  if (gradient->stops == (StopInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  (void) ResetMagickMemory(gradient->stops,0,gradient->number_stops*
+    sizeof(*gradient->stops));
+  for (i=0; i < (ssize_t) gradient->number_stops; i++)
+    GetPixelInfo(image,&gradient->stops[i].color);
+  SetPixelInfoPacket(image,start_color,&gradient->stops[0].color);
+  gradient->stops[0].offset=0.0;
+  SetPixelInfoPacket(image,stop_color,&gradient->stops[1].color);
+  gradient->stops[1].offset=1.0;
+  /*
+    Draw a gradient on the image.
+  */
+  status=DrawGradientImage(image,draw_info);
+  draw_info=DestroyDrawInfo(draw_info);
+  if ((start_color->alpha == OpaqueAlpha) && (stop_color->alpha == OpaqueAlpha))
+    image->matte=MagickFalse;
+  if ((IsPixelPacketGray(start_color) != MagickFalse) &&
+      (IsPixelPacketGray(stop_color) != MagickFalse))
+    image->type=GrayscaleType;
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O i l P a i n t I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OilPaintImage() applies a special effect filter that simulates an oil
+%  painting.  Each pixel is replaced by the most frequent color occurring
+%  in a circular region defined by radius.
+%
+%  The format of the OilPaintImage method is:
+%
+%      Image *OilPaintImage(const Image *image,const double radius,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o radius: the radius of the circular neighborhood.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static size_t **DestroyHistogramThreadSet(size_t **histogram)
+{
+  register ssize_t
+    i;
+
+  assert(histogram != (size_t **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (histogram[i] != (size_t *) NULL)
+      histogram[i]=(size_t *) RelinquishMagickMemory(histogram[i]);
+  histogram=(size_t **) RelinquishMagickMemory(histogram);
+  return(histogram);
+}
+
+static size_t **AcquireHistogramThreadSet(const size_t count)
+{
+  register ssize_t
+    i;
+
+  size_t
+    **histogram,
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  histogram=(size_t **) AcquireQuantumMemory(number_threads,
+    sizeof(*histogram));
+  if (histogram == (size_t **) NULL)
+    return((size_t **) NULL);
+  (void) ResetMagickMemory(histogram,0,number_threads*sizeof(*histogram));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    histogram[i]=(size_t *) AcquireQuantumMemory(count,
+      sizeof(**histogram));
+    if (histogram[i] == (size_t *) NULL)
+      return(DestroyHistogramThreadSet(histogram));
+  }
+  return(histogram);
+}
+
+MagickExport Image *OilPaintImage(const Image *image,const double radius,
+  ExceptionInfo *exception)
+{
+#define NumberPaintBins  256
+#define OilPaintImageTag  "OilPaint/Image"
+
+  CacheView
+    *image_view,
+    *paint_view;
+
+  Image
+    *paint_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  size_t
+    **restrict histograms,
+    width;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize painted image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=GetOptimalKernelWidth2D(radius,0.5);
+  paint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (paint_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(paint_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&paint_image->exception);
+      paint_image=DestroyImage(paint_image);
+      return((Image *) NULL);
+    }
+  histograms=AcquireHistogramThreadSet(NumberPaintBins);
+  if (histograms == (size_t **) NULL)
+    {
+      paint_image=DestroyImage(paint_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Oil paint image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  paint_view=AcquireCacheView(paint_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    register size_t
+      *histogram;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+      (width/2L),image->columns+width,width,exception);
+    q=QueueCacheViewAuthenticPixels(paint_view,0,y,paint_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    histogram=histograms[GetOpenMPThreadId()];
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      register ssize_t
+        i,
+        u;
+
+      size_t
+        count;
+
+      ssize_t
+        j,
+        k,
+        v;
+
+      /*
+        Assign most frequent color.
+      */
+      i=0;
+      j=0;
+      count=0;
+      (void) ResetMagickMemory(histogram,0,NumberPaintBins*sizeof(*histogram));
+      for (v=0; v < (ssize_t) width; v++)
+      {
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          k=(ssize_t) ScaleQuantumToChar(GetPixelIntensity(image,p+u+i));
+          histogram[k]++;
+          if (histogram[k] > count)
+            {
+              j=i+u;
+              count=histogram[k];
+            }
+        }
+        i+=(ssize_t) (image->columns+width);
+      }
+      SetPixelRed(paint_image,GetPixelRed(image,p+j*
+        GetPixelChannels(image)),q);
+      SetPixelGreen(paint_image,GetPixelGreen(image,p+j*
+        GetPixelChannels(image)),q);
+      SetPixelBlue(paint_image,GetPixelBlue(image,p+j*
+        GetPixelChannels(image)),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(paint_image,GetPixelBlack(image,p+j*
+          GetPixelChannels(image)),q);
+      if (image->matte != MagickFalse)
+        SetPixelAlpha(paint_image,GetPixelAlpha(image,p+j*
+          GetPixelChannels(image)),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(paint_image);
+    }
+    if (SyncCacheViewAuthenticPixels(paint_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_OilPaintImage)
+#endif
+        proceed=SetImageProgress(image,OilPaintImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  paint_view=DestroyCacheView(paint_view);
+  image_view=DestroyCacheView(image_view);
+  histograms=DestroyHistogramThreadSet(histograms);
+  if (status == MagickFalse)
+    paint_image=DestroyImage(paint_image);
+  return(paint_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O p a q u e P a i n t I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpaquePaintImage() changes any pixel that matches color with the color
+%  defined by fill.
+%
+%  By default color must match a particular pixel color exactly.  However,
+%  in many cases two colors may differ by a small amount.  Fuzz defines
+%  how much tolerance is acceptable to consider two colors as the same.
+%  For example, set fuzz to 10 and the color red at intensities of 100 and
+%  102 respectively are now interpreted as the same color.
+%
+%  The format of the OpaquePaintImage method is:
+%
+%      MagickBooleanType OpaquePaintImage(Image *image,
+%        const PixelPacket *target,const PixelPacket *fill,
+%        const MagickBooleanType invert)
+%      MagickBooleanType OpaquePaintImageChannel(Image *image,
+%        const ChannelType channel,const PixelPacket *target,
+%        const PixelPacket *fill,const MagickBooleanType invert)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel(s).
+%
+%    o target: the RGB value of the target color.
+%
+%    o fill: the replacement color.
+%
+%    o invert: paint any pixel that does not match the target color.
+%
+*/
+
+MagickExport MagickBooleanType OpaquePaintImage(Image *image,
+  const PixelInfo *target,const PixelInfo *fill,
+  const MagickBooleanType invert)
+{
+  return(OpaquePaintImageChannel(image,CompositeChannels,target,fill,invert));
+}
+
+MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
+  const ChannelType channel,const PixelInfo *target,
+  const PixelInfo *fill,const MagickBooleanType invert)
+{
+#define OpaquePaintImageTag  "Opaque/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(target != (PixelInfo *) NULL);
+  assert(fill != (PixelInfo *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  /*
+    Make image color opaque.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  GetPixelInfo(image,&zero);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,q,&pixel);
+      if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
+        {
+          if ((channel & RedChannel) != 0)
+            SetPixelRed(image,ClampToQuantum(fill->red),q);
+          if ((channel & GreenChannel) != 0)
+            SetPixelGreen(image,ClampToQuantum(fill->green),q);
+          if ((channel & BlueChannel) != 0)
+            SetPixelBlue(image,ClampToQuantum(fill->blue),q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace))
+            SetPixelBlack(image,ClampToQuantum(fill->black),q);
+          if ((channel & AlphaChannel) != 0)
+            SetPixelAlpha(image,ClampToQuantum(fill->alpha),q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_OpaquePaintImageChannel)
+#endif
+        proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T r a n s p a r e n t P a i n t I m a g e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransparentPaintImage() changes the opacity value associated with any pixel
+%  that matches color to the value defined by opacity.
+%
+%  By default color must match a particular pixel color exactly.  However,
+%  in many cases two colors may differ by a small amount.  Fuzz defines
+%  how much tolerance is acceptable to consider two colors as the same.
+%  For example, set fuzz to 10 and the color red at intensities of 100 and
+%  102 respectively are now interpreted as the same color.
+%
+%  The format of the TransparentPaintImage method is:
+%
+%      MagickBooleanType TransparentPaintImage(Image *image,
+%        const PixelInfo *target,const Quantum opacity,
+%        const MagickBooleanType invert)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o target: the target color.
+%
+%    o opacity: the replacement opacity value.
+%
+%    o invert: paint any pixel that does not match the target color.
+%
+*/
+MagickExport MagickBooleanType TransparentPaintImage(Image *image,
+  const PixelInfo *target,const Quantum opacity,
+  const MagickBooleanType invert)
+{
+#define TransparentPaintImageTag  "Transparent/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(target != (PixelInfo *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  /*
+    Make image color transparent.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  GetPixelInfo(image,&zero);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    pixel=zero;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,q,&pixel);
+      if (IsFuzzyEquivalencePixelInfo(&pixel,target) != invert)
+        SetPixelAlpha(image,opacity,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransparentPaintImage)
+#endif
+        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     T r a n s p a r e n t P a i n t I m a g e C h r o m a                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransparentPaintImageChroma() changes the opacity value associated with any
+%  pixel that matches color to the value defined by opacity.
+%
+%  As there is one fuzz value for the all the channels, the
+%  TransparentPaintImage() API is not suitable for the operations like chroma,
+%  where the tolerance for similarity of two color component (RGB) can be
+%  different, Thus we define this method take two target pixels (one
+%  low and one hight) and all the pixels of an image which are lying between
+%  these two pixels are made transparent.
+%
+%  The format of the TransparentPaintImage method is:
+%
+%      MagickBooleanType TransparentPaintImage(Image *image,
+%        const PixelInfo *low,const PixelInfo *hight,
+%        const Quantum opacity,const MagickBooleanType invert)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o low: the low target color.
+%
+%    o high: the high target color.
+%
+%    o opacity: the replacement opacity value.
+%
+%    o invert: paint any pixel that does not match the target color.
+%
+*/
+MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
+  const PixelInfo *low,const PixelInfo *high,
+  const Quantum opacity,const MagickBooleanType invert)
+{
+#define TransparentPaintImageTag  "Transparent/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(high != (PixelInfo *) NULL);
+  assert(low != (PixelInfo *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  if (image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
+  /*
+    Make image color transparent.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      match;
+
+    PixelInfo
+      pixel;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    GetPixelInfo(image,&pixel);
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,q,&pixel);
+      match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
+        (pixel.green >= low->green) && (pixel.green <= high->green) &&
+        (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ?
+        MagickTrue : MagickFalse;
+      if (match != invert)
+        SetPixelAlpha(image,opacity,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransparentPaintImageChroma)
+#endif
+        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/MagickCore/paint.h b/MagickCore/paint.h
new file mode 100644
index 0000000..24709b9
--- /dev/null
+++ b/MagickCore/paint.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image paint methods.
+*/
+#ifndef _MAGICKCORE_PAINT_H
+#define _MAGICKCORE_PAINT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/color.h"
+#include "MagickCore/draw.h"
+
+extern MagickExport Image
+  *OilPaintImage(const Image *,const double,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  FloodfillPaintImage(Image *,const ChannelType,const DrawInfo *,
+    const PixelInfo *,const ssize_t,const ssize_t,
+    const MagickBooleanType),
+  GradientImage(Image *,const GradientType,const SpreadMethod,
+    const PixelPacket *,const PixelPacket *),
+  OpaquePaintImage(Image *,const PixelInfo *,const PixelInfo *,
+    const MagickBooleanType),
+  OpaquePaintImageChannel(Image *,const ChannelType,const PixelInfo *,
+    const PixelInfo *,const MagickBooleanType),
+  TransparentPaintImage(Image *,const PixelInfo *,
+    const Quantum,const MagickBooleanType),
+  TransparentPaintImageChroma(Image *,const PixelInfo *,
+    const PixelInfo *,const Quantum,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/pixel-accessor.h b/MagickCore/pixel-accessor.h
new file mode 100644
index 0000000..a42b43b
--- /dev/null
+++ b/MagickCore/pixel-accessor.h
@@ -0,0 +1,511 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore pixel accessor methods.
+*/
+#ifndef _MAGICKCORE_PIXEL_ACCESSOR_H
+#define _MAGICKCORE_PIXEL_ACCESSOR_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <math.h>
+#include <MagickCore/cache-view.h>
+#include <MagickCore/color.h>
+#include <MagickCore/image.h>
+
+static inline Quantum GetPixelAlpha(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[AlphaPixelComponent].component]);
+}
+
+static inline Quantum GetPixelBlack(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[BlackPixelComponent].component]);
+}
+
+static inline Quantum GetPixelBlue(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[BluePixelComponent].component]);
+}
+
+static inline Quantum GetPixelCb(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[CbPixelComponent].component]);
+}
+
+static inline size_t GetPixelChannels(const Image *image)
+{
+  return(image->pixel_channels);
+}
+
+static inline Quantum GetPixelCr(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[CrPixelComponent].component]);
+}
+
+static inline Quantum GetPixelCyan(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[CyanPixelComponent].component]);
+}
+
+static inline Quantum GetPixelGray(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[GrayPixelComponent].component]);
+}
+
+static inline Quantum GetPixelGreen(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[GreenPixelComponent].component]);
+}
+
+static inline Quantum GetPixelIndex(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[IndexPixelComponent].component]);
+}
+
+static inline Quantum GetPixelInfoIntensity(const PixelInfo *pixel_info)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (0.299*pixel_info->red+0.587*pixel_info->green+0.114*pixel_info->blue+0.5));
+#else
+  return((Quantum) (0.299*pixel_info->red+0.587*pixel_info->green+0.114*pixel_info->blue));
+#endif
+}
+
+static inline Quantum GetPixelInfoLuminance(const PixelInfo *pixel_info)
+{
+  Quantum
+    luminance;
+  
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  luminance=(Quantum) (0.21267*pixel_info->red+0.71516*pixel_info->green+
+    0.07217*pixel_info->blue+0.5);
+#else
+  luminance=(Quantum) (0.21267*pixel_info->red+0.71516*pixel_info->green+
+    0.07217*pixel_info->blue);
+#endif
+  return((Quantum) luminance);
+}
+
+static inline Quantum GetPixelMagenta(const Image *image,
+  const Quantum *pixel)
+{
+  return(pixel[image->component_map[MagentaPixelComponent].component]);
+}
+
+static inline size_t GetPixelMetacontentExtent(const Image *image)
+{
+  return(image->metacontent_extent);
+}
+
+static inline Quantum GetPixelRed(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[RedPixelComponent].component]);
+}
+
+static inline void GetPixelPacket(const Image *image,const Quantum *pixel,
+  PixelPacket *packet)
+{
+  packet->red=GetPixelRed(image,pixel);
+  packet->green=GetPixelGreen(image,pixel);
+  packet->blue=GetPixelBlue(image,pixel);
+  packet->alpha=GetPixelAlpha(image,pixel);
+}
+
+static inline Quantum GetPixelPacketIntensity(const PixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(pixel->red);
+  return((Quantum) (0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue+0.5));
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=pixel->red-pixel->green;
+    beta=pixel->green-pixel->blue;
+    if ((fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(pixel->red);
+    return((Quantum) (0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue));
+  }
+#endif
+}
+
+static inline Quantum GetPixelY(const Image *image,const Quantum *pixel)
+{
+  return(pixel[image->component_map[YPixelComponent].component]);
+}
+
+static inline Quantum GetPixelYellow(const Image *image,
+  const Quantum *pixel)
+{
+  return(pixel[image->component_map[YellowPixelComponent].component]);
+}
+
+static inline MagickBooleanType IsPixelEquivalent(const Image *image,
+  const Quantum *p,const PixelPacket *q)
+{
+  if ((GetPixelRed(image,p) == q->red) &&
+      (GetPixelGreen(image,p) == q->green) &&
+      (GetPixelBlue(image,p) == q->blue))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsPixelGray(const Image *image,
+  const Quantum *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((GetPixelRed(image,pixel) == GetPixelGreen(image,pixel)) &&
+      (GetPixelGreen(image,pixel) == GetPixelBlue(image,pixel)))
+    return(MagickTrue);
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=GetPixelRed(image,pixel)-(double) GetPixelGreen(image,pixel);
+    beta=GetPixelGreen(image,pixel)-(double) GetPixelBlue(image,pixel);
+    if ((fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(MagickTrue);
+  }
+#endif
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsPixelInfoEquivalent(const PixelInfo *p,
+  const PixelInfo *q)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((p->matte != MagickFalse) && (q->matte == MagickFalse) &&
+      (p->alpha != OpaqueAlpha))
+    return(MagickFalse);
+  if ((q->matte != MagickFalse) && (p->matte == MagickFalse) &&
+      (q->alpha != OpaqueAlpha))
+    return(MagickFalse);
+  if ((p->matte != MagickFalse) && (q->matte != MagickFalse))
+    {
+      if (p->alpha != q->alpha)
+        return(MagickFalse);
+      if (p->alpha == TransparentAlpha)
+        return(MagickTrue);
+    }
+  if (p->red != q->red)
+    return(MagickFalse);
+  if (p->green != q->green)
+    return(MagickFalse);
+  if (p->blue != q->blue)
+    return(MagickFalse);
+  if ((p->colorspace == CMYKColorspace) && (p->black != q->black))
+    return(MagickFalse);
+#else
+  if ((p->matte != MagickFalse) && (q->matte == MagickFalse) &&
+      (fabs(p->alpha-OpaqueAlpha) > 0.5))
+    return(MagickFalse);
+  if ((q->matte != MagickFalse) && (p->matte == MagickFalse) &&
+      (fabs(q->alpha-OpaqueAlpha)) > 0.5)
+    return(MagickFalse);
+  if ((p->matte != MagickFalse) && (q->matte != MagickFalse))
+    {
+      if (fabs(p->alpha-q->alpha) > 0.5)
+        return(MagickFalse);
+      if (fabs(p->alpha-TransparentAlpha) <= 0.5)
+        return(MagickTrue);
+    }
+  if (fabs(p->red-q->red) > 0.5)
+    return(MagickFalse);
+  if (fabs(p->green-q->green) > 0.5)
+    return(MagickFalse);
+  if (fabs(p->blue-q->blue) > 0.5)
+    return(MagickFalse);
+  if ((p->colorspace == CMYKColorspace) && (fabs(p->black-q->black) > 0.5))
+    return(MagickFalse);
+#endif
+  return(MagickTrue);
+}
+
+static inline MagickBooleanType IsPixelMonochrome(const Image *image,
+  const Quantum *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if (((GetPixelRed(image,pixel) == 0) ||
+      (GetPixelRed(image,pixel) == (Quantum) QuantumRange)) &&
+      (GetPixelRed(image,pixel) == GetPixelGreen(image,pixel)) &&
+      (GetPixelGreen(image,pixel) == GetPixelBlue(image,pixel)))
+    return(MagickTrue);
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=GetPixelRed(image,pixel)-(double) GetPixelGreen(image,pixel);
+    beta=GetPixelGreen(image,pixel)-(double) GetPixelBlue(image,pixel);
+    if (((fabs(GetPixelRed(image,pixel)) <= MagickEpsilon) ||
+         (fabs(GetPixelRed(image,pixel)-QuantumRange) <= MagickEpsilon)) &&
+        (fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(MagickTrue);
+    }
+#endif
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsPixelPacketEquivalent(const PixelPacket *p,
+  const PixelPacket *q)
+{
+  if ((p->red == q->red) && (p->green == q->green) && (p->blue == q->blue))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsPixelPacketGray(const PixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(MagickTrue);
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=pixel->red-(double) pixel->green;
+    beta=pixel->green-(double) pixel->blue;
+    if ((fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(MagickTrue);
+  }
+#endif
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsPixelPacketMonochrome(
+  const PixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if (((pixel->red == 0) || (pixel->red == (Quantum) QuantumRange)) &&
+      (pixel->red == pixel->green) && (pixel->green == pixel->blue))
+    return(MagickTrue);
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=pixel->red-(double) pixel->green;
+    beta=pixel->green-(double) pixel->blue;
+    if (((fabs(pixel->red) <= MagickEpsilon) ||
+         (fabs(pixel->red-QuantumRange) <= MagickEpsilon)) &&
+        (fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(MagickTrue);
+    }
+#endif
+  return(MagickFalse);
+}
+
+static inline void SetPacketPixelInfo(const Image *image,
+  const PixelInfo *pixel_info,PixelPacket *packet)
+{
+  packet->red=ClampToQuantum(pixel_info->red);
+  packet->green=ClampToQuantum(pixel_info->green);
+  packet->blue=ClampToQuantum(pixel_info->blue);
+  packet->alpha=ClampToQuantum(pixel_info->alpha);
+  if (image->colorspace == CMYKColorspace)
+    packet->black=ClampToQuantum(pixel_info->black);
+  if (image->storage_class == PseudoClass)
+    packet->index=ClampToQuantum(pixel_info->index);
+}
+
+static inline void SetPixelAlpha(const Image *image,const Quantum alpha,
+  Quantum *pixel)
+{
+  pixel[image->component_map[AlphaPixelComponent].component]=alpha;
+}
+
+static inline void SetPixelBlack(const Image *image,const Quantum black,
+  Quantum *pixel)
+{
+  pixel[image->component_map[BlackPixelComponent].component]=black;
+}
+
+static inline void SetPixelBlue(const Image *image,const Quantum blue,
+  Quantum *pixel)
+{
+  pixel[image->component_map[BluePixelComponent].component]=blue;
+}
+
+static inline void SetPixelCb(const Image *image,const Quantum cb,
+  Quantum *pixel)
+{
+  pixel[image->component_map[CbPixelComponent].component]=cb;
+}
+
+static inline void SetPixelChannels(Image *image,const size_t channels)
+{
+  image->pixel_channels=channels;
+}
+
+static inline void SetPixelCr(const Image *image,const Quantum cr,
+  Quantum *pixel)
+{
+  pixel[image->component_map[CrPixelComponent].component]=cr;
+}
+
+static inline void SetPixelCyan(const Image *image,const Quantum cyan,
+  Quantum *pixel)
+{
+  pixel[image->component_map[CyanPixelComponent].component]=cyan;
+}
+
+static inline void SetPixelGray(const Image *image,const Quantum gray,
+  Quantum *pixel)
+{
+  pixel[image->component_map[GrayPixelComponent].component]=gray;
+}
+
+static inline void SetPixelGreen(const Image *image,const Quantum green,
+  Quantum *pixel)
+{
+  pixel[image->component_map[GreenPixelComponent].component]=green;
+}
+
+static inline void SetPixelIndex(const Image *image,const Quantum index,
+  Quantum *pixel)
+{
+  pixel[image->component_map[IndexPixelComponent].component]=index;
+}
+
+static inline void SetPixelInfo(const Image *image,const Quantum *pixel,
+  PixelInfo *pixel_info)
+{
+  pixel_info->red=(MagickRealType) GetPixelRed(image,pixel);
+  pixel_info->green=(MagickRealType) GetPixelGreen(image,pixel);
+  pixel_info->blue=(MagickRealType) GetPixelBlue(image,pixel);
+  pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+  if (image->colorspace == CMYKColorspace)
+    pixel_info->black=(MagickRealType) GetPixelBlack(image,pixel);
+  if (image->storage_class == PseudoClass)
+    pixel_info->index=(MagickRealType) GetPixelIndex(image,pixel);
+}
+
+static inline void SetPixelInfoBias(const Image *image,
+  PixelInfo *pixel_info)
+{
+  /*
+    Obsoleted by MorphologyApply().
+  */
+  pixel_info->red=image->bias;
+  pixel_info->green=image->bias;
+  pixel_info->blue=image->bias;
+  pixel_info->alpha=image->bias;
+  pixel_info->black=image->bias;
+}
+
+static inline void SetPixelInfoPacket(const Image *image,
+  const PixelPacket *pixel,PixelInfo *pixel_info)
+{
+  pixel_info->red=(MagickRealType) pixel->red;
+  pixel_info->green=(MagickRealType) pixel->green;
+  pixel_info->blue=(MagickRealType) pixel->blue;
+  pixel_info->alpha=(MagickRealType) pixel->alpha;
+  if (image->colorspace == CMYKColorspace)
+    pixel_info->black=(MagickRealType) pixel->black;
+  if (image->storage_class == PseudoClass)
+    pixel_info->index=(MagickRealType) pixel->index;
+}
+
+static inline void SetPixelMagenta(const Image *image,const Quantum magenta,
+  Quantum *pixel)
+{
+  pixel[image->component_map[MagentaPixelComponent].component]=magenta;
+}
+
+static inline void SetPixelMetacontentExtent(Image *image,const size_t extent)
+{
+  image->metacontent_extent=extent;
+}
+
+static inline void SetPixelRed(const Image *image,const Quantum red,
+  Quantum *pixel)
+{
+  pixel[image->component_map[RedPixelComponent].component]=red;
+}
+
+static inline void SetPixelPacket(const Image *image,const PixelPacket *packet,
+  Quantum *pixel)
+{
+  SetPixelRed(image,packet->red,pixel);
+  SetPixelGreen(image,packet->green,pixel);
+  SetPixelBlue(image,packet->blue,pixel);
+  SetPixelAlpha(image,packet->alpha,pixel);
+}
+
+static inline void SetPixelPixelInfo(const Image *image,
+  const PixelInfo *pixel_info,Quantum *packet)
+{
+  SetPixelRed(image,ClampToQuantum(pixel_info->red),packet);
+  SetPixelGreen(image,ClampToQuantum(pixel_info->green),packet);
+  SetPixelBlue(image,ClampToQuantum(pixel_info->blue),packet);
+  SetPixelAlpha(image,ClampToQuantum(pixel_info->alpha),packet);
+  if (image->colorspace == CMYKColorspace)
+    SetPixelBlack(image,ClampToQuantum(pixel_info->black),packet);
+}
+
+static inline void SetPixelYellow(const Image *image,const Quantum yellow,
+  Quantum *pixel)
+{
+  pixel[image->component_map[YellowPixelComponent].component]=yellow;
+}
+
+static inline void SetPixelY(const Image *image,const Quantum y,
+  Quantum *pixel)
+{
+  pixel[image->component_map[YPixelComponent].component]=y;
+}
+
+static inline Quantum GetPixelIntensity(const Image *image,
+  const Quantum *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((GetPixelRed(image,pixel) == GetPixelGreen(image,pixel)) &&
+      (GetPixelGreen(image,pixel) == GetPixelBlue(image,pixel)))
+    return(GetPixelRed(image,pixel));
+  return((Quantum) (0.299*GetPixelRed(image,pixel)+0.587*
+    GetPixelGreen(image,pixel)+0.114*GetPixelBlue(image,pixel)+0.5));
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=GetPixelRed(image,pixel)-(double) GetPixelGreen(image,pixel);
+    beta=GetPixelGreen(image,pixel)-(double) GetPixelBlue(image,pixel);
+    if ((fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(GetPixelRed(image,pixel));
+    return((Quantum) (0.299*GetPixelRed(image,pixel)+0.587*
+      GetPixelGreen(image,pixel)+0.114*GetPixelBlue(image,pixel)));
+  }
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/pixel-private.h b/MagickCore/pixel-private.h
new file mode 100644
index 0000000..4dfd038
--- /dev/null
+++ b/MagickCore/pixel-private.h
@@ -0,0 +1,132 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image pixel private methods.
+*/
+#ifndef _MAGICKCORE_PIXEL_PRIVATE_H
+#define _MAGICKCORE_PIXEL_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <magick/exception-private.h>
+#include <magick/image.h>
+#include <magick/color.h>
+#include <magick/image-private.h>
+#include <magick/quantum-private.h>
+
+static inline MagickPixelPacket *CloneMagickPixelPacket(
+  const MagickPixelPacket *pixel)
+{
+  MagickPixelPacket
+    *clone_pixel;
+
+  clone_pixel=(MagickPixelPacket *) AcquireAlignedMemory(1,
+    sizeof(*clone_pixel));
+  if (clone_pixel == (MagickPixelPacket *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  *clone_pixel=(*pixel);
+  return(clone_pixel);
+}
+
+static inline MagickBooleanType IsGrayPixel(const PixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if ((GetPixelRed(pixel) == GetPixelGreen(pixel)) && 
+      (GetPixelGreen(pixel) == GetPixelBlue(pixel)))
+    return(MagickTrue);
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=GetPixelRed(pixel)-GetPixelGreen(pixel);
+    beta=GetPixelGreen(pixel)-GetPixelBlue(pixel);
+    if ((fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(MagickTrue);
+  }
+#endif
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsMonochromePixel(const PixelPacket *pixel)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if (((GetPixelRed(pixel) == 0) ||
+       (GetPixelRed(pixel) == (Quantum) QuantumRange)) &&
+      (GetPixelRed(pixel) == GetPixelGreen(pixel)) &&
+      (GetPixelGreen(pixel) == GetPixelBlue(pixel)))
+    return(MagickTrue);
+#else
+  {
+    double
+      alpha,
+      beta;
+
+    alpha=GetPixelRed(pixel)-GetPixelGreen(pixel);
+    beta=GetPixelGreen(pixel)-GetPixelBlue(pixel);
+    if (((fabs(GetPixelRed(pixel)) <= MagickEpsilon) ||
+         (fabs(GetPixelRed(pixel)-QuantumRange) <= MagickEpsilon)) &&
+        (fabs(alpha) <= MagickEpsilon) && (fabs(beta) <= MagickEpsilon))
+      return(MagickTrue);
+    }
+#endif
+  return(MagickFalse);
+}
+
+static inline void SetMagickPixelPacket(const Image *image,
+  const PixelPacket *color,const IndexPacket *index,MagickPixelPacket *pixel)
+{
+  pixel->red=(MagickRealType) GetPixelRed(color);
+  pixel->green=(MagickRealType) GetPixelGreen(color);
+  pixel->blue=(MagickRealType) GetPixelBlue(color);
+  pixel->opacity=(MagickRealType) GetPixelOpacity(color);
+  if ((image->colorspace == CMYKColorspace) &&
+      (index != (const IndexPacket *) NULL))
+    pixel->index=(MagickRealType) GetPixelIndex(index);
+}
+
+static inline void SetMagickPixelPacketBias(const Image *image,
+  MagickPixelPacket *pixel)
+{
+  /*
+    Obsoleted by MorphologyApply().
+  */
+  pixel->red=image->bias;
+  pixel->green=image->bias;
+  pixel->blue=image->bias;
+  pixel->opacity=image->bias;
+  pixel->index=image->bias;
+}
+
+static inline void SetPixelPacket(const Image *image,
+  const MagickPixelPacket *pixel,PixelPacket *color,IndexPacket *index)
+{
+  SetPixelRed(color,ClampToQuantum(pixel->red));
+  SetPixelGreen(color,ClampToQuantum(pixel->green));
+  SetPixelBlue(color,ClampToQuantum(pixel->blue));
+  SetPixelOpacity(color,ClampToQuantum(pixel->opacity));
+  if ((image->colorspace == CMYKColorspace) ||
+      (image->storage_class == PseudoClass))
+    SetPixelIndex(index,ClampToQuantum(pixel->index));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/pixel.c b/MagickCore/pixel.c
new file mode 100644
index 0000000..1661c4d
--- /dev/null
+++ b/MagickCore/pixel.c
@@ -0,0 +1,4456 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      PPPP   IIIII  X   X  EEEEE  L                          %
+%                      P   P    I     X X   E      L                          %
+%                      PPPP     I      X    EEE    L                          %
+%                      P        I     X X   E      L                          %
+%                      P      IIIII  X   X  EEEEE  LLLLL                      %
+%                                                                             %
+%                  MagickCore Methods to Import/Export Pixels                 %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               October 1998                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e P i x e l C o m p o n e n t M a p                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquirePixelComponentMap() acquires a pixel component map.
+%
+%  The format of the AcquirePixelComponentMap() method is:
+%
+%      PixelComponentMap *AcquirePixelComponentMap(void)
+%
+*/
+MagickExport PixelComponentMap *AcquirePixelComponentMap(void)
+{
+  PixelComponentMap
+    *component_map;
+
+  register ssize_t
+    i;
+
+  component_map=(PixelComponentMap *) AcquireAlignedMemory(MaxPixelChannels,
+    sizeof(*component_map));
+  if (component_map == (PixelComponentMap *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  for (i=0; i < MaxPixelChannels; i++)
+  {
+    component_map[i].component=(PixelComponent) i;
+    component_map[i].trait=UndefinedPixelTrait;
+  }
+  return(component_map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o n e P i x e l C o m p o n e n t M a p                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClonePixelComponentMap() clones a pixel component map.
+%
+%  The format of the ClonePixelComponentMap() method is:
+%
+%      PixelComponentMap *ClonePixelComponentMap(
+%        const PixelComponentMap *component_map)
+%
+%  A description of each parameter follows:
+%
+%    o component_map: the pixel component map.
+%
+*/
+MagickExport PixelComponentMap *ClonePixelComponentMap(
+  const PixelComponentMap *component_map)
+{
+  PixelComponentMap
+    *clone_map;
+
+  assert(component_map != (const PixelComponentMap *) NULL);
+  clone_map=AcquirePixelComponentMap();
+  if (clone_map == (PixelComponentMap *) NULL)
+    return((PixelComponentMap *) NULL);
+  (void) CopyMagickMemory(clone_map,component_map,MaxPixelChannels*
+    sizeof(*component_map));
+  return(clone_map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o n e P i x e l I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClonePixelInfo() makes a duplicate of the given pixel info structure, or if
+%  pixel info is NULL, a new one.
+%
+%  The format of the ClonePixelInfo method is:
+%
+%      PixelInfo *ClonePixelInfo(const PixelInfo *pixel_info)
+%
+%  A description of each parameter follows:
+%
+%    o pixel_info: the pixel info.
+%
+*/
+MagickExport PixelInfo *ClonePixelInfo(const PixelInfo *pixel)
+{
+  PixelInfo
+    *pixel_info;
+
+  pixel_info=(PixelInfo *) AcquireAlignedMemory(1,sizeof(*pixel_info));
+  if (pixel_info == (PixelInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  *pixel_info=(*pixel);
+  return(pixel_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f i n e P i x e l C o m p o n e n t M a p                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefinePixelComponentMap() defines the pixel component map.
+%
+%  The format of the DefinePixelComponentMap() method is:
+%
+%      void DefinePixelComponentMap(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DefinePixelComponentMap(Image *image)
+{
+  image->pixel_channels=4;
+  if (image->storage_class == PseudoClass)
+    image->pixel_channels++;
+  if (image->colorspace == CMYKColorspace)
+    image->pixel_channels++;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P i x e l C o m p o n e n t M a p                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPixelComponentMap() deallocates memory associated with the pixel
+%  component map.
+%
+%  The format of the DestroyPixelComponentMap() method is:
+%
+%      PixelComponentMap *DestroyPixelComponentMap(
+%        PixelComponentMap *component_map)
+%
+%  A description of each parameter follows:
+%
+%    o component_map: the pixel component map.
+%
+*/
+MagickExport PixelComponentMap *DestroyPixelComponentMap(
+  PixelComponentMap *component_map)
+{
+  assert(component_map != (PixelComponentMap *) NULL);
+  return((PixelComponentMap *) RelinquishMagickMemory(component_map));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x p o r t I m a g e P i x e l s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExportImagePixels() extracts pixel data from an image and returns it to you.
+%  The method returns MagickTrue on success otherwise MagickFalse if an error is
+%  encountered.  The data is returned as char, short int, int, ssize_t, float,
+%  or double in the order specified by map.
+%
+%  Suppose you want to extract the first scanline of a 640x480 image as
+%  character data in red-green-blue order:
+%
+%      ExportImagePixels(image,0,0,640,1,"RGB",CharPixel,pixels,exception);
+%
+%  The format of the ExportImagePixels method is:
+%
+%      MagickBooleanType ExportImagePixels(const Image *image,
+%        const ssize_t x_offset,const ssize_t y_offset,const size_t columns,
+%        const size_t rows,const char *map,const StorageType type,
+%        void *pixels,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x_offset,y_offset,columns,rows:  These values define the perimeter
+%      of a region of pixels you want to extract.
+%
+%    o map:  This string reflects the expected ordering of the pixel array.
+%      It can be any combination or order of R = red, G = green, B = blue,
+%      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
+%      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
+%      P = pad.
+%
+%    o type: Define the data type of the pixels.  Float and double types are
+%      normalized to [0..1] otherwise [0..QuantumRange].  Choose from these
+%      types: CharPixel, DoublePixel, FloatPixel, IntegerPixel, LongPixel,
+%      QuantumPixel, or ShortPixel.
+%
+%    o pixels: This array of values contain the pixel components as defined by
+%      map and type.  You must preallocate this array where the expected
+%      length varies depending on the values of width, height, map, and type.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ExportImagePixels(const Image *image,
+  const ssize_t x_offset,const ssize_t y_offset,const size_t columns,
+  const size_t rows,const char *map,const StorageType type,void *pixels,
+  ExceptionInfo *exception)
+{
+  QuantumType
+    *quantum_map;
+
+  register ssize_t
+    i,
+    x;
+
+  register const Quantum
+    *p;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  length=strlen(map);
+  quantum_map=(QuantumType *) AcquireQuantumMemory(length,sizeof(*quantum_map));
+  if (quantum_map == (QuantumType *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) length; i++)
+  {
+    switch (map[i])
+    {
+      case 'A':
+      case 'a':
+      {
+        quantum_map[i]=AlphaQuantum;
+        break;
+      }
+      case 'B':
+      case 'b':
+      {
+        quantum_map[i]=BlueQuantum;
+        break;
+      }
+      case 'C':
+      case 'c':
+      {
+        quantum_map[i]=CyanQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",map);
+        return(MagickFalse);
+      }
+      case 'g':
+      case 'G':
+      {
+        quantum_map[i]=GreenQuantum;
+        break;
+      }
+      case 'I':
+      case 'i':
+      {
+        quantum_map[i]=IndexQuantum;
+        break;
+      }
+      case 'K':
+      case 'k':
+      {
+        quantum_map[i]=BlackQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",map);
+        return(MagickFalse);
+      }
+      case 'M':
+      case 'm':
+      {
+        quantum_map[i]=MagentaQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",map);
+        return(MagickFalse);
+      }
+      case 'o':
+      case 'O':
+      {
+        quantum_map[i]=OpacityQuantum;
+        break;
+      }
+      case 'P':
+      case 'p':
+      {
+        quantum_map[i]=UndefinedQuantum;
+        break;
+      }
+      case 'R':
+      case 'r':
+      {
+        quantum_map[i]=RedQuantum;
+        break;
+      }
+      case 'Y':
+      case 'y':
+      {
+        quantum_map[i]=YellowQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",map);
+        return(MagickFalse);
+      }
+      default:
+      {
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "UnrecognizedPixelMap","`%s'",map);
+        return(MagickFalse);
+      }
+    }
+  }
+  switch (type)
+  {
+    case CharPixel:
+    {
+      register unsigned char
+        *q;
+
+      q=(unsigned char *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+              *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+              *q++=ScaleQuantumToChar((Quantum) 0);
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelIntensity(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+              *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+              *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+              *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToChar((Quantum) 0);
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=ScaleQuantumToChar(GetPixelRed(image,p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=ScaleQuantumToChar(GetPixelGreen(image,p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=ScaleQuantumToChar(GetPixelBlue(image,p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=ScaleQuantumToChar(GetPixelAlpha(image,p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=ScaleQuantumToChar(GetPixelAlpha(image,p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=ScaleQuantumToChar(GetPixelBlack(image,p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=ScaleQuantumToChar(GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                break;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    case DoublePixel:
+    {
+      register double
+        *q;
+
+      q=(double *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(double) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(double) (QuantumScale*GetPixelRed(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(double) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(double) (QuantumScale*GetPixelRed(image,p));
+              *q++=(double) (QuantumScale*GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(double) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(double) (QuantumScale*GetPixelRed(image,p));
+              *q++=0.0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelIntensity(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelRed(image,p));
+              *q++=(double) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(double) (QuantumScale*GetPixelBlue(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelRed(image,p));
+              *q++=(double) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(double) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(double) (QuantumScale*GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(double) (QuantumScale*GetPixelRed(image,p));
+              *q++=(double) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(double) (QuantumScale*GetPixelBlue(image,p));
+              *q++=0.0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=(double) (QuantumScale*GetPixelRed(image,p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=(double) (QuantumScale*GetPixelGreen(image,p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=(double) (QuantumScale*GetPixelBlue(image,p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(double) (QuantumScale*GetPixelAlpha(image,p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=(double) (QuantumScale*GetPixelAlpha(image,p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=(double) (QuantumScale*
+                    GetPixelBlack(image,p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(double) (QuantumScale*GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                *q=0;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    case FloatPixel:
+    {
+      register float
+        *q;
+
+      q=(float *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(float) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(float) (QuantumScale*GetPixelRed(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(float) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(float) (QuantumScale*GetPixelRed(image,p));
+              *q++=(float) (QuantumScale*GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(float) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(float) (QuantumScale*GetPixelRed(image,p));
+              *q++=0.0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelIntensity(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelRed(image,p));
+              *q++=(float) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(float) (QuantumScale*GetPixelBlue(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelRed(image,p));
+              *q++=(float) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(float) (QuantumScale*GetPixelBlue(image,p));
+              *q++=(float) (QuantumScale*GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(float) (QuantumScale*GetPixelRed(image,p));
+              *q++=(float) (QuantumScale*GetPixelGreen(image,p));
+              *q++=(float) (QuantumScale*GetPixelBlue(image,p));
+              *q++=0.0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=(float) (QuantumScale*GetPixelRed(image,p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=(float) (QuantumScale*GetPixelGreen(image,p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=(float) (QuantumScale*GetPixelBlue(image,p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(float) (QuantumScale*((Quantum) (GetPixelAlpha(image,p))));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=(float) (QuantumScale*GetPixelAlpha(image,p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=(float) (QuantumScale* GetPixelBlack(image,p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(float) (QuantumScale*GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                *q=0;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    case IntegerPixel:
+    {
+      register unsigned int
+        *q;
+
+      q=(unsigned int *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=0U;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(
+                GetPixelIntensity(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=0U;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=(unsigned int) ScaleQuantumToLong(GetPixelBlack(image,p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(unsigned int) ScaleQuantumToLong(
+                  GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                *q=0;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    case LongPixel:
+    {
+      register size_t
+        *q;
+
+      q=(size_t *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=ScaleQuantumToLong(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelIntensity(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToLong(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+              *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+              *q++=0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=ScaleQuantumToLong(GetPixelRed(image,p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=ScaleQuantumToLong(GetPixelGreen(image,p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=ScaleQuantumToLong(GetPixelBlue(image,p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=ScaleQuantumToLong(GetPixelAlpha(image,p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=ScaleQuantumToLong(GetPixelAlpha(image,p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=ScaleQuantumToLong(GetPixelBlack(image,p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=ScaleQuantumToLong(GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                break;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    case QuantumPixel:
+    {
+      register Quantum
+        *q;
+
+      q=(Quantum *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelBlue(image,p);
+              *q++=GetPixelGreen(image,p);
+              *q++=GetPixelRed(image,p);
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelBlue(image,p);
+              *q++=GetPixelGreen(image,p);
+              *q++=GetPixelRed(image,p);
+              *q++=(Quantum) (GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelBlue(image,p);
+              *q++=GetPixelGreen(image,p);
+              *q++=GetPixelRed(image,p);
+              *q++=(Quantum) 0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelIntensity(image,p);
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelRed(image,p);
+              *q++=GetPixelGreen(image,p);
+              *q++=GetPixelBlue(image,p);
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelRed(image,p);
+              *q++=GetPixelGreen(image,p);
+              *q++=GetPixelBlue(image,p);
+              *q++=(Quantum) (GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=GetPixelRed(image,p);
+              *q++=GetPixelGreen(image,p);
+              *q++=GetPixelBlue(image,p);
+              *q++=(Quantum) 0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=(Quantum) 0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=GetPixelRed(image,p);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=GetPixelGreen(image,p);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=GetPixelBlue(image,p);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=(Quantum) (GetPixelAlpha(image,p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=GetPixelAlpha(image,p);
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=GetPixelBlack(image,p);
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=(GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                *q=(Quantum) 0;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    case ShortPixel:
+    {
+      register unsigned short
+        *q;
+
+      q=(unsigned short *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+              *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+              *q++=0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelIntensity(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+              *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+              *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+              *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+              *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+              *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+              *q++=0;
+              p+=GetPixelChannels(image);
+            }
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        p=GetVirtualPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            *q=0;
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                *q=ScaleQuantumToShort(GetPixelRed(image,p));
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                *q=ScaleQuantumToShort(GetPixelGreen(image,p));
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                *q=ScaleQuantumToShort(GetPixelBlue(image,p));
+                break;
+              }
+              case AlphaQuantum:
+              {
+                *q=ScaleQuantumToShort(GetPixelAlpha(image,p));
+                break;
+              }
+              case OpacityQuantum:
+              {
+                *q=ScaleQuantumToShort(GetPixelAlpha(image,p));
+                break;
+              }
+              case BlackQuantum:
+              {
+                if (image->colorspace == CMYKColorspace)
+                  *q=ScaleQuantumToShort(GetPixelBlack(image,p));
+                break;
+              }
+              case IndexQuantum:
+              {
+                *q=ScaleQuantumToShort(GetPixelIntensity(image,p));
+                break;
+              }
+              default:
+                break;
+            }
+            q++;
+          }
+          p+=GetPixelChannels(image);
+        }
+      }
+      break;
+    }
+    default:
+    {
+      quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "UnrecognizedPixelMap","`%s'",map);
+      break;
+    }
+  }
+  quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k P i x e l P a c k e t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPixelInfo() initializes the PixelInfo structure.
+%
+%  The format of the GetPixelInfo method is:
+%
+%      GetPixelInfo(const Image *image,PixelInfo *pixel)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o pixel: Specifies a pointer to a PixelPacket structure.
+%
+*/
+MagickExport void GetPixelInfo(const Image *image,
+  PixelInfo *pixel)
+{
+  pixel->storage_class=DirectClass;
+  pixel->colorspace=RGBColorspace;
+  pixel->matte=MagickFalse;
+  pixel->fuzz=0.0;
+  pixel->depth=MAGICKCORE_QUANTUM_DEPTH;
+  pixel->red=0.0;
+  pixel->green=0.0;
+  pixel->blue=0.0;
+  pixel->black=0.0;
+  pixel->alpha=(MagickRealType) OpaqueAlpha;
+  pixel->index=0.0;
+  if (image == (const Image *) NULL)
+    return;
+  pixel->storage_class=image->storage_class;
+  pixel->colorspace=image->colorspace;
+  pixel->matte=image->matte;
+  pixel->depth=image->depth;
+  pixel->fuzz=image->fuzz;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I m p o r t I m a g e P i x e l s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImportImagePixels() accepts pixel data and stores in the image at the
+%  location you specify.  The method returns MagickTrue on success otherwise
+%  MagickFalse if an error is encountered.  The pixel data can be either char,
+%  short int, int, ssize_t, float, or double in the order specified by map.
+%
+%  Suppose your want to upload the first scanline of a 640x480 image from
+%  character data in red-green-blue order:
+%
+%      ImportImagePixels(image,0,0,640,1,"RGB",CharPixel,pixels);
+%
+%  The format of the ImportImagePixels method is:
+%
+%      MagickBooleanType ImportImagePixels(Image *image,const ssize_t x_offset,
+%        const ssize_t y_offset,const size_t columns,
+%        const size_t rows,const char *map,const StorageType type,
+%        const void *pixels)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x_offset,y_offset,columns,rows:  These values define the perimeter
+%      of a region of pixels you want to define.
+%
+%    o map:  This string reflects the expected ordering of the pixel array.
+%      It can be any combination or order of R = red, G = green, B = blue,
+%      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
+%      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
+%      P = pad.
+%
+%    o type: Define the data type of the pixels.  Float and double types are
+%      normalized to [0..1] otherwise [0..QuantumRange].  Choose from these
+%      types: CharPixel, ShortPixel, IntegerPixel, LongPixel, FloatPixel, or
+%      DoublePixel.
+%
+%    o pixels: This array of values contain the pixel components as defined by
+%      map and type.  You must preallocate this array where the expected
+%      length varies depending on the values of width, height, map, and type.
+%
+*/
+MagickExport MagickBooleanType ImportImagePixels(Image *image,
+  const ssize_t x_offset,const ssize_t y_offset,const size_t columns,
+  const size_t rows,const char *map,const StorageType type,
+  const void *pixels)
+{
+  ExceptionInfo
+    *exception;
+
+  QuantumType
+    *quantum_map;
+
+  register Quantum
+    *q;
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate image structure.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  length=strlen(map);
+  quantum_map=(QuantumType *) AcquireQuantumMemory(length,sizeof(*quantum_map));
+  if (quantum_map == (QuantumType *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  for (i=0; i < (ssize_t) length; i++)
+  {
+    switch (map[i])
+    {
+      case 'a':
+      case 'A':
+      {
+        quantum_map[i]=AlphaQuantum;
+        image->matte=MagickTrue;
+        break;
+      }
+      case 'B':
+      case 'b':
+      {
+        quantum_map[i]=BlueQuantum;
+        break;
+      }
+      case 'C':
+      case 'c':
+      {
+        quantum_map[i]=CyanQuantum;
+        (void) SetImageColorspace(image,CMYKColorspace);
+        break;
+      }
+      case 'g':
+      case 'G':
+      {
+        quantum_map[i]=GreenQuantum;
+        break;
+      }
+      case 'K':
+      case 'k':
+      {
+        quantum_map[i]=BlackQuantum;
+        (void) SetImageColorspace(image,CMYKColorspace);
+        break;
+      }
+      case 'I':
+      case 'i':
+      {
+        quantum_map[i]=IndexQuantum;
+        break;
+      }
+      case 'm':
+      case 'M':
+      {
+        quantum_map[i]=MagentaQuantum;
+        (void) SetImageColorspace(image,CMYKColorspace);
+        break;
+      }
+      case 'O':
+      case 'o':
+      {
+        quantum_map[i]=OpacityQuantum;
+        image->matte=MagickTrue;
+        break;
+      }
+      case 'P':
+      case 'p':
+      {
+        quantum_map[i]=UndefinedQuantum;
+        break;
+      }
+      case 'R':
+      case 'r':
+      {
+        quantum_map[i]=RedQuantum;
+        break;
+      }
+      case 'Y':
+      case 'y':
+      {
+        quantum_map[i]=YellowQuantum;
+        (void) SetImageColorspace(image,CMYKColorspace);
+        break;
+      }
+      default:
+      {
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(&image->exception,GetMagickModule(),
+          OptionError,"UnrecognizedPixelMap","`%s'",map);
+        return(MagickFalse);
+      }
+    }
+  }
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  /*
+    Transfer the pixels from the pixel datarray to the image.
+  */
+  exception=(&image->exception);
+  switch (type)
+  {
+    case CharPixel:
+    {
+      register const unsigned char
+        *p;
+
+      p=(const unsigned char *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRO") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBO") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleCharToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,ScaleCharToQuantum(*p),q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,ScaleCharToQuantum(*p),q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,ScaleCharToQuantum(*p),q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,ScaleCharToQuantum(*p),q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,ScaleCharToQuantum(*p),q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,ScaleCharToQuantum(*p),q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,ScaleCharToQuantum(*p),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case DoublePixel:
+    {
+      register const double
+        *p;
+
+      p=(const double *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelAlpha(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelAlpha(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case FloatPixel:
+    {
+      register const float
+        *p;
+
+      p=(const float *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelAlpha(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType)
+                QuantumRange*(*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelAlpha(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelGreen(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              SetPixelBlue(image,ClampToQuantum((MagickRealType) QuantumRange*
+                (*p)),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*(*p)),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case IntegerPixel:
+    {
+      register const unsigned int
+        *p;
+
+      p=(const unsigned int *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,ScaleLongToQuantum(*p),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case LongPixel:
+    {
+      register const unsigned int
+        *p;
+
+      p=(const unsigned int *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleLongToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,ScaleLongToQuantum(*p),q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,ScaleLongToQuantum(*p),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case QuantumPixel:
+    {
+      register const Quantum
+        *p;
+
+      p=(const Quantum *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,*p++,q);
+              SetPixelGreen(image,*p++,q);
+              SetPixelRed(image,*p++,q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,*p++,q);
+              SetPixelGreen(image,*p++,q);
+              SetPixelRed(image,*p++,q);
+              SetPixelAlpha(image,*p++,q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,*p++,q);
+              SetPixelGreen(image,*p++,q);
+              SetPixelRed(image,*p++,q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,*p++,q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,*p++,q);
+              SetPixelGreen(image,*p++,q);
+              SetPixelBlue(image,*p++,q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,*p++,q);
+              SetPixelGreen(image,*p++,q);
+              SetPixelBlue(image,*p++,q);
+              SetPixelAlpha(image,*p++,q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,*p++,q);
+              SetPixelGreen(image,*p++,q);
+              SetPixelBlue(image,*p++,q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,*p,q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,*p,q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,*p,q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,*p,q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,*p,q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,*p,q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,*p,q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    case ShortPixel:
+    {
+      register const unsigned short
+        *p;
+
+      p=(const unsigned short *) pixels;
+      if (LocaleCompare(map,"BGR") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"BGRP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"I") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGB") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBA") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
+              SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      if (LocaleCompare(map,"RGBP") == 0)
+        {
+          for (y=0; y < (ssize_t) rows; y++)
+          {
+            q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+            if (q == (Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) columns; x++)
+            {
+              SetPixelRed(image,ScaleShortToQuantum(*p++),q);
+              SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
+              SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
+              p++;
+              q+=GetPixelChannels(image);
+            }
+            if (SyncAuthenticPixels(image,exception) == MagickFalse)
+              break;
+          }
+          break;
+        }
+      for (y=0; y < (ssize_t) rows; y++)
+      {
+        q=GetAuthenticPixels(image,x_offset,y_offset+y,columns,1,exception);
+        if (q == (Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) columns; x++)
+        {
+          for (i=0; i < (ssize_t) length; i++)
+          {
+            switch (quantum_map[i])
+            {
+              case RedQuantum:
+              case CyanQuantum:
+              {
+                SetPixelRed(image,ScaleShortToQuantum(*p),q);
+                break;
+              }
+              case GreenQuantum:
+              case MagentaQuantum:
+              {
+                SetPixelGreen(image,ScaleShortToQuantum(*p),q);
+                break;
+              }
+              case BlueQuantum:
+              case YellowQuantum:
+              {
+                SetPixelBlue(image,ScaleShortToQuantum(*p),q);
+                break;
+              }
+              case AlphaQuantum:
+              {
+                SetPixelAlpha(image,ScaleShortToQuantum(*p),q);
+                break;
+              }
+              case OpacityQuantum:
+              {
+                SetPixelAlpha(image,ScaleShortToQuantum(*p),q);
+                break;
+              }
+              case BlackQuantum:
+              {
+                SetPixelBlack(image,ScaleShortToQuantum(*p),q);
+                break;
+              }
+              case IndexQuantum:
+              {
+                SetPixelRed(image,ScaleShortToQuantum(*p),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                break;
+              }
+              default:
+                break;
+            }
+            p++;
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncAuthenticPixels(image,exception) == MagickFalse)
+          break;
+      }
+      break;
+    }
+    default:
+    {
+      quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        OptionError,"UnrecognizedPixelMap","`%s'",map);
+      break;
+    }
+  }
+  quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p o l a t e M a g i c k P i x e l P a c k e t                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpolatePixelInfo() applies bi-linear or tri-linear interpolation
+%  between a floating point coordinate and the pixels surrounding that
+%  coordinate.  No pixel area resampling, or scaling of the result is
+%  performed.
+%
+%  The format of the InterpolatePixelInfo method is:
+%
+%      MagickBooleanType InterpolatePixelInfo(const Image *image,
+%        const CacheView *image_view,const InterpolatePixelMethod method,
+%        const double x,const double y,PixelInfo *pixel,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o image_view: the image view.
+%
+%    o method: the pixel color interpolation method.
+%
+%    o x,y: A double representing the current (x,y) position of the pixel.
+%
+%    o pixel: return the interpolated pixel here.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline void AlphaBlendPixelInfo(const Image *image,
+  const Quantum *pixel,PixelInfo *pixel_info,MagickRealType *alpha)
+{
+  if (image->matte == MagickFalse)
+    {
+      *alpha=1.0;
+      pixel_info->red=(MagickRealType) GetPixelRed(image,pixel);
+      pixel_info->green=(MagickRealType) GetPixelGreen(image,pixel);
+      pixel_info->blue=(MagickRealType) GetPixelBlue(image,pixel);
+      pixel_info->black=0.0;
+      if (image->colorspace == CMYKColorspace)
+        pixel_info->black=(MagickRealType) GetPixelBlack(image,pixel);
+      pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+      return;
+    }
+  *alpha=QuantumScale*GetPixelAlpha(image,pixel);
+  pixel_info->red=(*alpha*GetPixelRed(image,pixel));
+  pixel_info->green=(*alpha*GetPixelGreen(image,pixel));
+  pixel_info->blue=(*alpha*GetPixelBlue(image,pixel));
+  pixel_info->black=0.0;
+  if (image->colorspace == CMYKColorspace)
+    pixel_info->black=(*alpha*GetPixelBlack(image,pixel));
+  pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+}
+
+static void BicubicInterpolate(const PixelInfo *pixels,const double dx,
+  PixelInfo *pixel)
+{
+  MagickRealType
+    dx2,
+    p,
+    q,
+    r,
+    s;
+
+  dx2=dx*dx;
+  p=(pixels[3].red-pixels[2].red)-(pixels[0].red-pixels[1].red);
+  q=(pixels[0].red-pixels[1].red)-p;
+  r=pixels[2].red-pixels[0].red;
+  s=pixels[1].red;
+  pixel->red=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  p=(pixels[3].green-pixels[2].green)-(pixels[0].green-pixels[1].green);
+  q=(pixels[0].green-pixels[1].green)-p;
+  r=pixels[2].green-pixels[0].green;
+  s=pixels[1].green;
+  pixel->green=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  p=(pixels[3].blue-pixels[2].blue)-(pixels[0].blue-pixels[1].blue);
+  q=(pixels[0].blue-pixels[1].blue)-p;
+  r=pixels[2].blue-pixels[0].blue;
+  s=pixels[1].blue;
+  pixel->blue=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  p=(pixels[3].alpha-pixels[2].alpha)-(pixels[0].alpha-pixels[1].alpha);
+  q=(pixels[0].alpha-pixels[1].alpha)-p;
+  r=pixels[2].alpha-pixels[0].alpha;
+  s=pixels[1].alpha;
+  pixel->alpha=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  if (pixel->colorspace == CMYKColorspace)
+    {
+      p=(pixels[3].black-pixels[2].black)-(pixels[0].black-pixels[1].black);
+      q=(pixels[0].black-pixels[1].black)-p;
+      r=pixels[2].black-pixels[0].black;
+      s=pixels[1].black;
+      pixel->black=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+    }
+}
+
+static inline double MagickMax(const MagickRealType x,const MagickRealType y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline MagickRealType CubicWeightingFunction(const MagickRealType x)
+{
+  MagickRealType
+    alpha,
+    gamma;
+
+  alpha=MagickMax(x+2.0,0.0);
+  gamma=1.0*alpha*alpha*alpha;
+  alpha=MagickMax(x+1.0,0.0);
+  gamma-=4.0*alpha*alpha*alpha;
+  alpha=MagickMax(x+0.0,0.0);
+  gamma+=6.0*alpha*alpha*alpha;
+  alpha=MagickMax(x-1.0,0.0);
+  gamma-=4.0*alpha*alpha*alpha;
+  return(gamma/6.0);
+}
+
+static inline double MeshInterpolate(const PointInfo *delta,const double p,
+  const double x,const double y)
+{
+  return(delta->x*x+delta->y*y+(1.0-delta->x-delta->y)*p);
+}
+
+static inline ssize_t NearestNeighbor(const MagickRealType x)
+{
+  if (x >= 0.0)
+    return((ssize_t) (x+0.5));
+  return((ssize_t) (x-0.5));
+}
+
+MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
+  const CacheView *image_view,const InterpolatePixelMethod method,
+  const double x,const double y,PixelInfo *pixel,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    pixels[16];
+
+  MagickRealType
+    alpha[16],
+    gamma;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    x_offset,
+    y_offset;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image_view != (CacheView *) NULL);
+  status=MagickTrue;
+  x_offset=(ssize_t) floor(x);
+  y_offset=(ssize_t) floor(y);
+  switch (method == UndefinedInterpolatePixel ? image->interpolate : method)
+  {
+    case AverageInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p+0*GetPixelChannels(image),pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
+      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
+      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
+      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
+      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
+      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
+      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,
+        alpha+10);
+      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,
+        alpha+11);
+      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,
+        alpha+12);
+      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,
+        alpha+13);
+      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,
+        alpha+14);
+      AlphaBlendPixelInfo(image,p+15,pixels+15,alpha+15);
+      pixel->red=0.0;
+      pixel->green=0.0;
+      pixel->blue=0.0;
+      pixel->alpha=0.0;
+      pixel->black=0.0;
+      for (i=0; i < 16L; i++)
+      {
+        gamma=1.0/(fabs((double) alpha[i]) <= MagickEpsilon ? 1.0 : alpha[i]);
+        pixel->red+=gamma*0.0625*pixels[i].red;
+        pixel->green+=gamma*0.0625*pixels[i].green;
+        pixel->blue+=gamma*0.0625*pixels[i].blue;
+        pixel->alpha+=0.0625*pixels[i].alpha;
+        if (image->colorspace == CMYKColorspace)
+          pixel->black+=gamma*0.0625*pixels[i].black;
+      }
+      break;
+    }
+    case BicubicInterpolatePixel:
+    {
+      PixelInfo
+        u[4];
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p+0*GetPixelChannels(image),pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
+      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
+      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
+      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
+      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
+      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
+      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,
+        alpha+10);
+      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,
+        alpha+11);
+      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,
+        alpha+12);
+      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,
+        alpha+13);
+      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,
+        alpha+14);
+      AlphaBlendPixelInfo(image,p+15*GetPixelChannels(image),pixels+15,
+        alpha+15);
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      for (i=0; i < 4L; i++)
+        BicubicInterpolate(pixels+4*i,delta.x,u+i);
+      BicubicInterpolate(u,delta.y,pixel);
+      break;
+    }
+    case BilinearInterpolatePixel:
+    default:
+    {
+      PointInfo
+        delta,
+        epsilon;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p+0*GetPixelChannels(image),pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      epsilon.x=1.0-delta.x;
+      epsilon.y=1.0-delta.y;
+      gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
+        (epsilon.x*alpha[2]+delta.x*alpha[3])));
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
+        pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
+      pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
+        pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
+        pixels[3].green));
+      pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
+        pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
+        pixels[3].blue));
+      pixel->alpha=(epsilon.y*(epsilon.x*pixels[0].alpha+delta.x*
+        pixels[1].alpha)+delta.y*(epsilon.x*pixels[2].alpha+delta.x*
+        pixels[3].alpha));
+      if (image->colorspace == CMYKColorspace)
+        pixel->black=gamma*(epsilon.y*(epsilon.x*pixels[0].black+delta.x*
+          pixels[1].black)+delta.y*(epsilon.x*pixels[2].black+delta.x*
+          pixels[3].black));
+      break;
+    }
+    case FilterInterpolatePixel:
+    {
+      CacheView
+        *filter_view;
+
+      Image
+        *excerpt_image,
+        *filter_image;
+
+      RectangleInfo
+        geometry;
+
+      geometry.width=4L;
+      geometry.height=4L;
+      geometry.x=x_offset-1;
+      geometry.y=y_offset-1;
+      excerpt_image=ExcerptImage(image,&geometry,exception);
+      if (excerpt_image == (Image *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      filter_image=ResizeImage(excerpt_image,1,1,image->filter,image->blur,
+        exception);
+      excerpt_image=DestroyImage(excerpt_image);
+      if (filter_image == (Image *) NULL)
+        break;
+      filter_view=AcquireCacheView(filter_image);
+      p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
+      if (p != (const Quantum *) NULL)
+        SetPixelInfo(image,p,pixel);
+      filter_view=DestroyCacheView(filter_view);
+      filter_image=DestroyImage(filter_image);
+      break;
+    }
+    case IntegerInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      SetPixelInfo(image,p,pixel);
+      break;
+    }
+    case MeshInterpolatePixel:
+    {
+      PointInfo
+        delta,
+        luminance;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p+0*GetPixelChannels(image),pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      luminance.x=GetPixelInfoLuminance(pixels+0)-(double)
+        GetPixelInfoLuminance(pixels+3);
+      luminance.y=GetPixelInfoLuminance(pixels+1)-(double)
+        GetPixelInfoLuminance(pixels+2);
+      if (fabs(luminance.x) < fabs(luminance.y))
+        {
+          /*
+            Diagonal 0-3 NW-SE.
+          */
+          if (delta.x <= delta.y)
+            {
+              /*
+                Bottom-left triangle  (pixel:2, diagonal: 0-3).
+              */
+              delta.y=1.0-delta.y;
+              gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
+                pixels[3].red,pixels[0].red);
+              pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
+                pixels[3].green,pixels[0].green);
+              pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
+                pixels[3].blue,pixels[0].blue);
+              pixel->alpha=gamma*MeshInterpolate(&delta,pixels[2].alpha,
+                pixels[3].alpha,pixels[0].alpha);
+              if (image->colorspace == CMYKColorspace)
+                pixel->black=gamma*MeshInterpolate(&delta,pixels[2].black,
+                  pixels[3].black,pixels[0].black);
+            }
+          else
+            {
+              /*
+                Top-right triangle (pixel:1, diagonal: 0-3).
+              */
+              delta.x=1.0-delta.x;
+              gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
+                pixels[0].red,pixels[3].red);
+              pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
+                pixels[0].green,pixels[3].green);
+              pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
+                pixels[0].blue,pixels[3].blue);
+              pixel->alpha=gamma*MeshInterpolate(&delta,pixels[1].alpha,
+                pixels[0].alpha,pixels[3].alpha);
+              if (image->colorspace == CMYKColorspace)
+                pixel->black=gamma*MeshInterpolate(&delta,pixels[1].black,
+                  pixels[0].black,pixels[3].black);
+            }
+        }
+      else
+        {
+          /*
+            Diagonal 1-2 NE-SW.
+          */
+          if (delta.x <= (1.0-delta.y))
+            {
+              /*
+                Top-left triangle (pixel 0, diagonal: 1-2).
+              */
+              gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
+                pixels[1].red,pixels[2].red);
+              pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
+                pixels[1].green,pixels[2].green);
+              pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
+                pixels[1].blue,pixels[2].blue);
+              pixel->alpha=gamma*MeshInterpolate(&delta,pixels[0].alpha,
+                pixels[1].alpha,pixels[2].alpha);
+              if (image->colorspace == CMYKColorspace)
+                pixel->black=gamma*MeshInterpolate(&delta,pixels[0].black,
+                  pixels[1].black,pixels[2].black);
+            }
+          else
+            {
+              /*
+                Bottom-right triangle (pixel: 3, diagonal: 1-2).
+              */
+              delta.x=1.0-delta.x;
+              delta.y=1.0-delta.y;
+              gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
+                pixels[2].red,pixels[1].red);
+              pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
+                pixels[2].green,pixels[1].green);
+              pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
+                pixels[2].blue,pixels[1].blue);
+              pixel->alpha=gamma*MeshInterpolate(&delta,pixels[3].alpha,
+                pixels[2].alpha,pixels[1].alpha);
+              if (image->colorspace == CMYKColorspace)
+                pixel->black=gamma*MeshInterpolate(&delta,pixels[3].black,
+                  pixels[2].black,pixels[1].black);
+            }
+        }
+      break;
+    }
+    case NearestNeighborInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(image_view,NearestNeighbor(x),
+        NearestNeighbor(y),1,1,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      SetPixelInfo(image,p,pixel);
+      break;
+    }
+    case SplineInterpolatePixel:
+    {
+      MagickRealType
+        dx,
+        dy;
+
+      PointInfo
+        delta;
+
+      ssize_t
+        j,
+        n;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p+0*GetPixelChannels(image),pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
+      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
+      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
+      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
+      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
+      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
+      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,
+        alpha+10);
+      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,
+        alpha+11);
+      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,
+        alpha+12);
+      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,
+        alpha+13);
+      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,
+        alpha+14);
+      AlphaBlendPixelInfo(image,p+15*GetPixelChannels(image),pixels+15,
+        alpha+15);
+      pixel->red=0.0;
+      pixel->green=0.0;
+      pixel->blue=0.0;
+      pixel->alpha=0.0;
+      pixel->black=0.0;
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      n=0;
+      for (i=(-1); i < 3L; i++)
+      {
+        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
+        for (j=(-1); j < 3L; j++)
+        {
+          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
+          gamma=1.0/(fabs((double) alpha[n]) <= MagickEpsilon ? 1.0 : alpha[n]);
+          pixel->red+=gamma*dx*dy*pixels[n].red;
+          pixel->green+=gamma*dx*dy*pixels[n].green;
+          pixel->blue+=gamma*dx*dy*pixels[n].blue;
+          if (image->colorspace == CMYKColorspace)
+            pixel->black+=gamma*dx*dy*pixels[n].black;
+          pixel->alpha+=dx*dy*pixels[n].alpha;
+          n++;
+        }
+      }
+      break;
+    }
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s F u z z y E q u i v a l e n c e P i x e l                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsFuzzyEquivalencePixel() returns MagickTrue if the distance between two
+%  pixels is less than the specified distance in a linear three (or four)u
+%  dimensional color space.
+%
+%  The format of the IsFuzzyEquivalencePixel method is:
+%
+%      void IsFuzzyEquivalencePixel(const Image *image,const Quantum *p,
+%        const Quantum *q)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o p: Pixel p.
+%
+%    o q: Pixel q.
+%
+*/
+MagickExport MagickBooleanType IsFuzzyEquivalencePixel(const Image *image,
+  const Quantum *p,const Quantum *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    distance,
+    scale;
+
+  fuzz=MagickMax(image->fuzz,(MagickRealType) MagickSQ1_2)*
+    MagickMax(image->fuzz,(MagickRealType) MagickSQ1_2);
+  scale=1.0;
+  distance=0.0;
+  if (image->matte != MagickFalse)
+    {
+      /*
+        Transparencies are involved - set alpha distance
+      */
+      pixel=(MagickRealType) ((image->matte != MagickFalse ?
+        GetPixelAlpha(image,p) : OpaqueAlpha)-(image->matte != MagickFalse ?
+        GetPixelAlpha(image,q) : OpaqueAlpha));
+      distance=pixel*pixel;
+      if (distance > fuzz)
+        return(MagickFalse);
+      /*
+        Generate a alpha scaling factor to generate a 4D cone on colorspace
+        Note that if one color is transparent, distance has no color component.
+      */
+      scale=QuantumScale*GetPixelAlpha(image,p);
+      scale*=QuantumScale*GetPixelAlpha(image,q);
+      if (scale <= MagickEpsilon)
+        return(MagickTrue);
+    }
+  /*
+    RGB or CMY color cube
+  */
+  distance*=3.0;  /* rescale appropriately */
+  fuzz*=3.0;
+  pixel=GetPixelRed(image,p)-(MagickRealType) GetPixelRed(image,q);
+  if ((image->colorspace == HSLColorspace) ||
+      (image->colorspace == HSBColorspace) ||
+      (image->colorspace == HWBColorspace))
+    {
+      /*
+        Compute an arc distance for hue.  It should be a vector angle of
+        'S'/'W' length with 'L'/'B' forming appropriate cones.
+      */
+      if (fabs((double) pixel) > (QuantumRange/2))
+        pixel-=QuantumRange;
+      pixel*=2;
+    }
+  distance+=scale*pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=GetPixelGreen(image,p)-(MagickRealType) GetPixelGreen(image,q);
+  distance+=scale*pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=GetPixelBlue(image,p)-(MagickRealType) GetPixelBlue(image,q);
+  distance+=scale*pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s F u z z y E q u i v a l e n c e P i x e l I n f o                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsFuzzyEquivalencePixelInfo() returns true if the distance between two
+%  colors is less than the specified distance in a linear three (or four)
+%  dimensional color space.
+%
+%  This implements the equivalent of...
+%    fuzz < sqrt( color_distance^2 * u.a*v.a  + alpha_distance^2 )
+%
+%  Which produces a multi-dimensional cone for that colorspace along the
+%  transparency vector.
+%
+%  For example for an RGB
+%    color_distance^2  = ( (u.r-v.r)^2 + (u.g-v.g)^2 + (u.b-v.b)^2 ) / 3
+%
+%  See http://www.imagemagick.org/Usage/bugs/fuzz_distance/
+%
+%  Hue colorspace distances need more work.  Hue is not a distance, it is an
+%  angle!
+%
+%  A check that q is in the same color space as p should be made and the
+%  appropriate mapping made.  -- Anthony Thyssen  8 December 2010
+%
+%  The format of the IsFuzzyEquivalencePixelInfo method is:
+%
+%      MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p,
+%        const PixelInfo *q)
+%
+%  A description of each parameter follows:
+%
+%    o p: Pixel p.
+%
+%    o q: Pixel q.
+%
+*/
+MagickExport MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p,
+  const PixelInfo *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    scale,
+    distance;
+
+  if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
+    return(IsPixelInfoEquivalent(p,q));
+  if (p->fuzz == 0.0)
+    fuzz=MagickMax(q->fuzz,(MagickRealType) MagickSQ1_2)*
+      MagickMax(q->fuzz,(MagickRealType) MagickSQ1_2);
+  else if (q->fuzz == 0.0)
+    fuzz=MagickMax(p->fuzz,(MagickRealType) MagickSQ1_2)*
+      MagickMax(p->fuzz,(MagickRealType) MagickSQ1_2);
+  else
+    fuzz=MagickMax(p->fuzz,(MagickRealType) MagickSQ1_2)*
+      MagickMax(q->fuzz,(MagickRealType) MagickSQ1_2);
+  scale=1.0;
+  distance=0.0;
+  if ((p->matte != MagickFalse) || (q->matte != MagickFalse))
+    {
+      /*
+        Transparencies are involved - set alpha distance.
+      */
+      pixel=(p->matte != MagickFalse ? p->alpha : OpaqueAlpha)-
+        (q->matte != MagickFalse ? q->alpha : OpaqueAlpha);
+      distance=pixel*pixel;
+      if (distance > fuzz)
+        return(MagickFalse);
+      /*
+        Generate a alpha scaling factor to generate a 4D cone on colorspace.
+        Note that if one color is transparent, distance has no color component
+      */
+      if (p->matte != MagickFalse)
+        scale=(QuantumScale*p->alpha);
+      if (q->matte != MagickFalse)
+        scale*=(QuantumScale*q->alpha);
+      if (scale <= MagickEpsilon )
+        return(MagickTrue);
+    }
+  /*
+    CMYK create a CMY cube with a multi-dimensional cone toward black.
+  */
+  if (p->colorspace == CMYKColorspace)
+    {
+      pixel=p->black-q->black;
+      distance+=pixel*pixel*scale;
+      if (distance > fuzz)
+        return(MagickFalse);
+      scale*=(MagickRealType) (QuantumScale*(QuantumRange-p->black));
+      scale*=(MagickRealType) (QuantumScale*(QuantumRange-q->black));
+    }
+  /*
+    RGB or CMY color cube.
+  */
+  distance*=3.0;  /* rescale appropriately */
+  fuzz*=3.0;
+  pixel=p->red-q->red;
+  if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
+      (p->colorspace == HWBColorspace))
+    {
+      /* This calculates a arc distance for hue
+         Really if should be a vector angle of 'S'/'W' length
+         with 'L'/'B' forming appropriate cones.
+         In other words this is a hack - Anthony
+      */
+      if (fabs((double) pixel) > (QuantumRange/2))
+        pixel-=QuantumRange;
+      pixel*=2;
+    }
+  distance+=pixel*pixel*scale;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=p->green-q->green;
+  distance+=pixel*pixel*scale;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=p->blue-q->blue;
+  distance+=pixel*pixel*scale;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I s F u z z y E q u i v a l e n c e P i x e l P a c k e t                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsFuzzyEquivalencePixelPacket() returns MagickTrue if the distance between
+%  two pixels is less than the specified distance in a linear three (or four)
+%  dimensional color space.
+%
+%  The format of the IsFuzzyEquivalencePixelPacket method is:
+%
+%      void IsFuzzyEquivalencePixelPacket(const Image *image,
+%        const PixelPacket *p,const PixelPacket *q)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o p: Pixel p.
+%
+%    o q: Pixel q.
+%
+*/
+MagickExport MagickBooleanType IsFuzzyEquivalencePixelPacket(const Image *image,
+  const PixelPacket *p,const PixelPacket *q)
+{
+  MagickRealType
+    fuzz,
+    pixel;
+
+  register MagickRealType
+    distance,
+    scale;
+
+  if ((image->fuzz == 0.0) && (image->matte == MagickFalse))
+    return(IsPixelPacketEquivalent(p,q));
+  fuzz=MagickMax(image->fuzz,(MagickRealType) MagickSQ1_2)*
+    MagickMax(image->fuzz,(MagickRealType) MagickSQ1_2);
+  scale=1.0;
+  distance=0.0;
+  if (image->matte != MagickFalse)
+    {
+      /*
+        Transparencies are involved - set alpha distance
+      */
+      pixel=(MagickRealType) ((image->matte != MagickFalse ? p->alpha :
+        OpaqueAlpha)-(image->matte != MagickFalse ? q->alpha : OpaqueAlpha));
+      distance=pixel*pixel;
+      if (distance > fuzz)
+        return(MagickFalse);
+      /*
+        Generate a alpha scaling factor to generate a 4D cone on colorspace
+        Note that if one color is transparent, distance has no color component.
+      */
+      scale=QuantumScale*p->alpha;
+      scale*=QuantumScale*q->alpha;
+      if (scale <= MagickEpsilon)
+        return(MagickTrue);
+    }
+  /*
+    RGB or CMY color cube
+  */
+  distance*=3.0;  /* rescale appropriately */
+  fuzz*=3.0;
+  pixel=p->red-(MagickRealType) q->red;
+  if ((image->colorspace == HSLColorspace) ||
+      (image->colorspace == HSBColorspace) ||
+      (image->colorspace == HWBColorspace))
+    {
+      /*
+        Compute an arc distance for hue.  It should be a vector angle of
+        'S'/'W' length with 'L'/'B' forming appropriate cones.
+      */
+      if (fabs((double) pixel) > (QuantumRange/2))
+        pixel-=QuantumRange;
+      pixel*=2;
+    }
+  distance+=scale*pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=(MagickRealType) p->green-q->green;
+  distance+=scale*pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  pixel=(MagickRealType) p->blue-q->blue;
+  distance+=scale*pixel*pixel;
+  if (distance > fuzz)
+    return(MagickFalse);
+  return(MagickTrue);
+}
diff --git a/MagickCore/pixel.h b/MagickCore/pixel.h
new file mode 100644
index 0000000..36e94dc
--- /dev/null
+++ b/MagickCore/pixel.h
@@ -0,0 +1,166 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image constitute methods.
+*/
+#ifndef _MAGICKCORE_PIXEL_H
+#define _MAGICKCORE_PIXEL_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/colorspace.h>
+#include <MagickCore/constitute.h>
+
+typedef enum
+{
+  UndefinedInterpolatePixel,
+  AverageInterpolatePixel,
+  BicubicInterpolatePixel,
+  BilinearInterpolatePixel,
+  FilterInterpolatePixel,
+  IntegerInterpolatePixel,
+  MeshInterpolatePixel,
+  NearestNeighborInterpolatePixel,
+  SplineInterpolatePixel
+} InterpolatePixelMethod;
+
+typedef enum
+{
+  RedPixelComponent = 0,
+  CyanPixelComponent = 0,
+  GrayPixelComponent = 0,
+  YPixelComponent = 0,
+  GreenPixelComponent = 1,
+  MagentaPixelComponent = 1,
+  CbPixelComponent = 1,
+  BluePixelComponent = 2,
+  YellowPixelComponent = 2,
+  CrPixelComponent = 2,
+  AlphaPixelComponent = 3,
+  BlackPixelComponent = 4,
+  IndexPixelComponent = 4,
+  MaskPixelComponent = 5
+} PixelComponent;
+
+typedef enum
+{
+  UndefinedPixelTrait
+} PixelTrait;
+
+typedef struct _PixelComponentMap
+{
+  PixelComponent
+    component;
+
+  PixelTrait
+    trait;
+} PixelComponentMap;
+
+typedef struct _DoublePixelPacket
+{
+  double
+    red,
+    green,
+    blue,
+    alpha,
+    black;
+} DoublePixelPacket;
+
+typedef struct _LongPixelPacket
+{
+  unsigned int
+    red,
+    green,
+    blue,
+    alpha,
+    black;
+} LongPixelPacket;
+
+typedef struct _PixelInfo
+{
+  ClassType
+    storage_class;
+
+  ColorspaceType
+    colorspace;
+
+  MagickBooleanType
+    matte;
+
+  double
+    fuzz;
+
+  size_t
+    depth;
+
+  MagickRealType
+    red,
+    green,
+    blue,
+    alpha,
+    black,
+    index;
+} PixelInfo;
+
+typedef struct _PixelPacket
+{
+  Quantum
+    red,
+    green,
+    blue,
+    alpha,
+    black,
+    index;
+
+ MagickSizeType
+    count;
+} PixelPacket;
+
+typedef struct _CacheView
+  CacheView_;
+
+extern MagickExport MagickBooleanType
+  ExportImagePixels(const Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,const char *,const StorageType,void *,ExceptionInfo *),
+  ImportImagePixels(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,const char *,const StorageType,const void *),
+  InterpolatePixelInfo(const Image *,const CacheView_ *,
+    const InterpolatePixelMethod,const double,const double,PixelInfo *,
+    ExceptionInfo *),
+  IsFuzzyEquivalencePixel(const Image *,const Quantum *,
+    const Quantum *),
+  IsFuzzyEquivalencePixelInfo(const PixelInfo *,const PixelInfo *),
+  IsFuzzyEquivalencePixelPacket(const Image *,const PixelPacket *,
+    const PixelPacket *);
+
+extern MagickExport PixelComponentMap
+  *AcquirePixelComponentMap(void),
+  *ClonePixelComponentMap(const PixelComponentMap *),
+  *DestroyPixelComponentMap(PixelComponentMap *);
+
+extern MagickExport PixelInfo
+  *ClonePixelInfo(const PixelInfo *);
+
+extern MagickExport void
+  DefinePixelComponentMap(Image *),
+  GetPixelInfo(const Image *,PixelInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/policy.c b/MagickCore/policy.c
new file mode 100644
index 0000000..8d20a11
--- /dev/null
+++ b/MagickCore/policy.c
@@ -0,0 +1,1022 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                  PPPP    OOO   L      IIIII   CCCC  Y   Y                   %
+%                  P   P  O   O  L        I    C       Y Y                    %
+%                  PPPP   O   O  L        I    C        Y                     %
+%                  P      O   O  L        I    C        Y                     %
+%                  P       OOO   LLLLL  IIIII   CCCC    Y                     %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Policy Methods                           %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  We use linked-lists because splay-trees do not currently support duplicate
+%  key / value pairs (.e.g X11 green compliance and SVG green compliance).
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define PolicyFilename  "policy.xml"
+
+/*
+  Typedef declarations.
+*/
+struct _PolicyInfo
+{
+  char
+    *path;
+
+  PolicyDomain
+    domain;
+
+  PolicyRights
+    rights;
+
+  char
+    *name,
+    *pattern,
+    *value;
+
+  MagickBooleanType
+    exempt,
+    stealth,
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+typedef struct _PolicyMapInfo
+{
+  const PolicyDomain
+    domain;
+
+  const PolicyRights
+    rights;
+
+  const char
+    *name,
+    *pattern,
+    *value;
+} PolicyMapInfo;
+
+/*
+  Static declarations.
+*/
+static const PolicyMapInfo
+  PolicyMap[] =
+  {
+    { UndefinedPolicyDomain, UndefinedPolicyRights, (const char *) NULL,
+      (const char *) NULL, (const char *) NULL }
+  };
+
+static LinkedListInfo
+  *policy_list = (LinkedListInfo *) NULL;
+
+static SemaphoreInfo
+  *policy_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_policy = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializePolicyList(ExceptionInfo *),
+  LoadPolicyLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t P o l i c y I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPolicyInfo() searches the policy list for the specified name and if found
+%  returns attributes for that policy.
+%
+%  The format of the GetPolicyInfo method is:
+%
+%      PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the policy name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
+{
+  char
+    policyname[MaxTextExtent];
+
+  register PolicyInfo
+    *p;
+
+  register char
+    *q;
+
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((policy_list == (LinkedListInfo *) NULL) ||
+      (instantiate_policy == MagickFalse))
+    if (InitializePolicyList(exception) == MagickFalse)
+      return((PolicyInfo *) NULL);
+  if ((policy_list == (LinkedListInfo *) NULL) ||
+      (IsLinkedListEmpty(policy_list) != MagickFalse))
+    return((PolicyInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    return((PolicyInfo *) GetValueFromLinkedList(policy_list,0));
+  /*
+    Strip names of whitespace.
+  */
+  (void) CopyMagickString(policyname,name,MaxTextExtent);
+  for (q=policyname; *q != '\0'; q++)
+  {
+    if (isspace((int) ((unsigned char) *q)) == 0)
+      continue;
+    (void) CopyMagickString(q,q+1,MaxTextExtent);
+    q--;
+  }
+  /*
+    Search for policy tag.
+  */
+  LockSemaphoreInfo(policy_semaphore);
+  ResetLinkedListIterator(policy_list);
+  p=(PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  while (p != (PolicyInfo *) NULL)
+  {
+    if (LocaleCompare(policyname,p->name) == 0)
+      break;
+    p=(PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  }
+  if (p != (PolicyInfo *) NULL)
+    (void) InsertValueInLinkedList(policy_list,0,
+      RemoveElementByValueFromLinkedList(policy_list,p));
+  UnlockSemaphoreInfo(policy_semaphore);
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P o l i c y I n f o L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPolicyInfoList() returns any policies that match the specified pattern.
+%
+%  The format of the GetPolicyInfoList function is:
+%
+%      const PolicyInfo **GetPolicyInfoList(const char *pattern,
+%        size_t *number_policies,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_policies:  returns the number of policies in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const PolicyInfo **GetPolicyInfoList(const char *pattern,
+  size_t *number_policies,ExceptionInfo *exception)
+{
+  const PolicyInfo
+    **policies;
+
+  register const PolicyInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate policy list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_policies != (size_t *) NULL);
+  *number_policies=0;
+  p=GetPolicyInfo("*",exception);
+  if (p == (const PolicyInfo *) NULL)
+    return((const PolicyInfo **) NULL);
+  policies=(const PolicyInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(policy_list)+1UL,sizeof(*policies));
+  if (policies == (const PolicyInfo **) NULL)
+    return((const PolicyInfo **) NULL);
+  /*
+    Generate policy list.
+  */
+  LockSemaphoreInfo(policy_semaphore);
+  ResetLinkedListIterator(policy_list);
+  p=(const PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  for (i=0; p != (const PolicyInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      policies[i++]=p;
+    p=(const PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  }
+  UnlockSemaphoreInfo(policy_semaphore);
+  policies[i]=(PolicyInfo *) NULL;
+  *number_policies=(size_t) i;
+  return(policies);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P o l i c y L i s t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPolicyList() returns any policies that match the specified pattern.
+%
+%  The format of the GetPolicyList function is:
+%
+%      char **GetPolicyList(const char *pattern,size_t *number_policies,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: a pointer to a text string containing a pattern.
+%
+%    o number_policies:  returns the number of policies in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport char **GetPolicyList(const char *pattern,
+  size_t *number_policies,ExceptionInfo *exception)
+{
+  char
+    **policies;
+
+  register const PolicyInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate policy list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_policies != (size_t *) NULL);
+  *number_policies=0;
+  p=GetPolicyInfo("*",exception);
+  if (p == (const PolicyInfo *) NULL)
+    return((char **) NULL);
+  policies=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfElementsInLinkedList(policy_list)+1UL,sizeof(*policies));
+  if (policies == (char **) NULL)
+    return((char **) NULL);
+  /*
+    Generate policy list.
+  */
+  LockSemaphoreInfo(policy_semaphore);
+  ResetLinkedListIterator(policy_list);
+  p=(const PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  for (i=0; p != (const PolicyInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      policies[i++]=ConstantString(p->name);
+    p=(const PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  }
+  UnlockSemaphoreInfo(policy_semaphore);
+  policies[i]=(char *) NULL;
+  *number_policies=(size_t) i;
+  return(policies);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P o l i c y V a l u e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPolicyValue() returns the value associated with the named policy.
+%
+%  The format of the GetPolicyValue method is:
+%
+%      char *GetPolicyValue(const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o policy_info:  The policy info.
+%
+*/
+MagickExport char *GetPolicyValue(const char *name)
+{
+  const char
+    *value;
+
+  const PolicyInfo
+    *policy_info;
+
+  ExceptionInfo
+    *exception;
+
+  assert(name != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
+  exception=AcquireExceptionInfo();
+  policy_info=GetPolicyInfo(name,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (policy_info == (PolicyInfo *) NULL)
+    return((char *) NULL);
+  value=policy_info->value;
+  if ((value == (const char *) NULL) || (*value == '\0'))
+    return((char *) NULL);
+  return(ConstantString(value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e P o l i c y L i s t                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializePolicyList() initializes the policy list.
+%
+%  The format of the InitializePolicyList method is:
+%
+%      MagickBooleanType InitializePolicyList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType InitializePolicyList(ExceptionInfo *exception)
+{
+  if ((policy_list == (LinkedListInfo *) NULL) &&
+      (instantiate_policy == MagickFalse))
+    {
+      if (policy_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&policy_semaphore);
+      LockSemaphoreInfo(policy_semaphore);
+      if ((policy_list == (LinkedListInfo *) NULL) &&
+          (instantiate_policy == MagickFalse))
+        {
+          (void) LoadPolicyLists(PolicyFilename,exception);
+          instantiate_policy=MagickTrue;
+        }
+      UnlockSemaphoreInfo(policy_semaphore);
+    }
+  return(policy_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s R i g h t s A u t h o r i z e d                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsRightsAuthorized() returns MagickTrue if the policy authorizes the
+%  requested rights for the specified domain.
+%
+%  The format of the IsRightsAuthorized method is:
+%
+%      MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
+%        const PolicyRights rights,const char *pattern)
+%
+%  A description of each parameter follows:
+%
+%    o domain: the policy domain.
+%
+%    o rights: the policy rights.
+%
+%    o pattern: the coder, delegate, filter, or path pattern.
+%
+*/
+MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
+  const PolicyRights rights,const char *pattern)
+{
+  const PolicyInfo
+    *policy_info;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    authorized;
+
+  register PolicyInfo
+    *p;
+
+  (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
+    "Domain: %s; rights=%s; pattern=\"%s\" ...",
+    CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
+    CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
+  exception=AcquireExceptionInfo();
+  policy_info=GetPolicyInfo("*",exception);
+  exception=DestroyExceptionInfo(exception);
+  if (policy_info == (PolicyInfo *) NULL)
+    return(MagickTrue);
+  authorized=MagickTrue;
+  LockSemaphoreInfo(policy_semaphore);
+  ResetLinkedListIterator(policy_list);
+  p=(PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  while ((p != (PolicyInfo *) NULL) && (authorized != MagickFalse))
+  {
+    if ((p->domain == domain) &&
+        (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
+      {
+        if (((rights & ReadPolicyRights) != 0) &&
+            ((p->rights & ReadPolicyRights) == 0))
+          authorized=MagickFalse;
+        if (((rights & WritePolicyRights) != 0) &&
+            ((p->rights & WritePolicyRights) == 0))
+          authorized=MagickFalse;
+        if (((rights & ExecutePolicyRights) != 0) &&
+            ((p->rights & ExecutePolicyRights) == 0))
+          authorized=MagickFalse;
+      }
+    p=(PolicyInfo *) GetNextValueInLinkedList(policy_list);
+  }
+  UnlockSemaphoreInfo(policy_semaphore);
+  return(authorized);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t P o l i c y I n f o                                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListPolicyInfo() lists policies to the specified file.
+%
+%  The format of the ListPolicyInfo method is:
+%
+%      MagickBooleanType ListPolicyInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  List policy names to this file handle.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
+  ExceptionInfo *exception)
+{
+  const char
+    *path,
+    *domain;
+
+  const PolicyInfo
+    **policy_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_policies;
+
+  /*
+    List name and attributes of each policy in the list.
+  */
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  policy_info=GetPolicyInfoList("*",&number_policies,exception);
+  if (policy_info == (const PolicyInfo **) NULL)
+    return(MagickFalse);
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_policies; i++)
+  {
+    if (policy_info[i]->stealth != MagickFalse)
+      continue;
+    if (((path == (const char *) NULL) ||
+         (LocaleCompare(path,policy_info[i]->path) != 0)) &&
+         (policy_info[i]->path != (char *) NULL))
+      (void) FormatLocaleFile(file,"\nPath: %s\n",policy_info[i]->path);
+    path=policy_info[i]->path;
+    domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
+      policy_info[i]->domain);
+    (void) FormatLocaleFile(file,"  Policy: %s\n",domain);
+    if ((policy_info[i]->domain == ResourcePolicyDomain) ||
+        (policy_info[i]->domain == SystemPolicyDomain))
+      {
+        if (policy_info[i]->name != (char *) NULL)
+          (void) FormatLocaleFile(file,"    name: %s\n",policy_info[i]->name);
+        if (policy_info[i]->value != (char *) NULL)
+          (void) FormatLocaleFile(file,"    value: %s\n",policy_info[i]->value);
+      }
+    else
+      {
+        (void) FormatLocaleFile(file,"    rights: ");
+        if (policy_info[i]->rights == NoPolicyRights)
+          (void) FormatLocaleFile(file,"None ");
+        if ((policy_info[i]->rights & ReadPolicyRights) != 0)
+          (void) FormatLocaleFile(file,"Read ");
+        if ((policy_info[i]->rights & WritePolicyRights) != 0)
+          (void) FormatLocaleFile(file,"Write ");
+        if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
+          (void) FormatLocaleFile(file,"Execute ");
+        (void) FormatLocaleFile(file,"\n");
+        if (policy_info[i]->pattern != (char *) NULL)
+          (void) FormatLocaleFile(file,"    pattern: %s\n",
+            policy_info[i]->pattern);
+      }
+  }
+  policy_info=(const PolicyInfo **) RelinquishMagickMemory((void *)
+    policy_info);
+  (void) fflush(file);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d P o l i c y L i s t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadPolicyList() loads the policy configuration file which provides a mapping
+%  between policy attributes and a policy domain.
+%
+%  The format of the LoadPolicyList method is:
+%
+%      MagickBooleanType LoadPolicyList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The policy list in XML format.
+%
+%    o filename:  The policy list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadPolicyList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    keyword[MaxTextExtent],
+    *token;
+
+  PolicyInfo
+    *policy_info;
+
+  const char
+    *q;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Load the policy map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading policy file \"%s\" ...",filename);
+  if (xml == (char *) NULL)
+    return(MagickFalse);
+  if (policy_list == (LinkedListInfo *) NULL)
+    {
+      policy_list=NewLinkedList(0);
+      if (policy_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  policy_info=(PolicyInfo *) NULL;
+  token=AcquireString(xml);
+  for (q=(const char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Docdomain element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  xml=FileToString(path,~0,exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadPolicyList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<policy") == 0)
+      {
+        /*
+          Policy element.
+        */
+        policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
+        if (policy_info == (PolicyInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(policy_info,0,sizeof(*policy_info));
+        policy_info->path=ConstantString(filename);
+        policy_info->exempt=MagickFalse;
+        policy_info->signature=MagickSignature;
+        continue;
+      }
+    if (policy_info == (PolicyInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AppendValueToLinkedList(policy_list,policy_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            policy_info->name);
+        policy_info=(PolicyInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'D':
+      case 'd':
+      {
+        if (LocaleCompare((char *) keyword,"domain") == 0)
+          {
+            policy_info->domain=(PolicyDomain) ParseCommandOption(
+              MagickPolicyDomainOptions,MagickTrue,token);
+            break;
+          }
+        break;
+      }
+      case 'N':
+      case 'n':
+      {
+        if (LocaleCompare((char *) keyword,"name") == 0)
+          {
+            policy_info->name=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'P':
+      case 'p':
+      {
+        if (LocaleCompare((char *) keyword,"pattern") == 0)
+          {
+            policy_info->pattern=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'R':
+      case 'r':
+      {
+        if (LocaleCompare((char *) keyword,"rights") == 0)
+          {
+            policy_info->rights=(PolicyRights) ParseCommandOption(
+              MagickPolicyRightsOptions,MagickTrue,token);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            policy_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        break;
+      }
+      case 'V':
+      case 'v':
+      {
+        if (LocaleCompare((char *) keyword,"value") == 0)
+          {
+            policy_info->value=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d P o l i c y L i s t s                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadPolicyList() loads one or more policy configuration file which provides a
+%  mapping between policy attributes and a policy name.
+%
+%  The format of the LoadPolicyLists method is:
+%
+%      MagickBooleanType LoadPolicyLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadPolicyLists(const char *filename,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  /*
+    Load built-in policy map.
+  */
+  status=MagickFalse;
+  if (policy_list == (LinkedListInfo *) NULL)
+    {
+      policy_list=NewLinkedList(0);
+      if (policy_list == (LinkedListInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  for (i=0; i < (ssize_t) (sizeof(PolicyMap)/sizeof(*PolicyMap)); i++)
+  {
+    PolicyInfo
+      *policy_info;
+
+    register const PolicyMapInfo
+      *p;
+
+    p=PolicyMap+i;
+    policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
+    if (policy_info == (PolicyInfo *) NULL)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",policy_info->name);
+        continue;
+      }
+    (void) ResetMagickMemory(policy_info,0,sizeof(*policy_info));
+    policy_info->path=(char *) "[built-in]";
+    policy_info->domain=p->domain;
+    policy_info->rights=p->rights;
+    policy_info->name=(char *) p->name;
+    policy_info->pattern=(char *) p->pattern;
+    policy_info->value=(char *) p->value;
+    policy_info->exempt=MagickTrue;
+    policy_info->signature=MagickSignature;
+    status=AppendValueToLinkedList(policy_list,policy_info);
+    if (status == MagickFalse)
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",policy_info->name);
+  }
+  /*
+    Load external policy map.
+  */
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    status|=LoadPolicyList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P o l i c y C o m p o n e n t G e n e s i s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PolicyComponentGenesis() instantiates the policy component.
+%
+%  The format of the PolicyComponentGenesis method is:
+%
+%      MagickBooleanType PolicyComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType PolicyComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&policy_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P o l i c y C o m p o n e n t T e r m i n u s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PolicyComponentTerminus() destroys the policy component.
+%
+%  The format of the PolicyComponentTerminus method is:
+%
+%      PolicyComponentTerminus(void)
+%
+*/
+
+static void *DestroyPolicyElement(void *policy_info)
+{
+  register PolicyInfo
+    *p;
+
+  p=(PolicyInfo *) policy_info;
+  if (p->exempt == MagickFalse)
+    {
+      if (p->value != (char *) NULL)
+        p->value=DestroyString(p->value);
+      if (p->pattern != (char *) NULL)
+        p->pattern=DestroyString(p->pattern);
+      if (p->name != (char *) NULL)
+        p->name=DestroyString(p->name);
+      if (p->path != (char *) NULL)
+        p->path=DestroyString(p->path);
+    }
+  p=(PolicyInfo *) RelinquishMagickMemory(p);
+  return((void *) NULL);
+}
+
+MagickExport void PolicyComponentTerminus(void)
+{
+  if (policy_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&policy_semaphore);
+  LockSemaphoreInfo(policy_semaphore);
+  if (policy_list != (LinkedListInfo *) NULL)
+    policy_list=DestroyLinkedList(policy_list,DestroyPolicyElement);
+  instantiate_policy=MagickFalse;
+  UnlockSemaphoreInfo(policy_semaphore);
+  DestroySemaphoreInfo(&policy_semaphore);
+}
diff --git a/MagickCore/policy.h b/MagickCore/policy.h
new file mode 100644
index 0000000..16854a4
--- /dev/null
+++ b/MagickCore/policy.h
@@ -0,0 +1,70 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image color methods.
+*/
+#ifndef _MAGICKCORE_POLICY_H
+#define _MAGICKCORE_POLICY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/pixel.h>
+#include <MagickCore/exception.h>
+
+typedef enum
+{
+  UndefinedPolicyDomain,
+  CoderPolicyDomain,
+  DelegatePolicyDomain,
+  FilterPolicyDomain,
+  PathPolicyDomain,
+  ResourcePolicyDomain,
+  SystemPolicyDomain
+} PolicyDomain;
+
+typedef enum
+{
+  UndefinedPolicyRights = 0x00,
+  NoPolicyRights = 0x00,
+  ReadPolicyRights = 0x01,
+  WritePolicyRights = 0x02,
+  ExecutePolicyRights = 0x04
+} PolicyRights;
+
+typedef struct _PolicyInfo
+  PolicyInfo;
+
+extern MagickExport char
+  *GetPolicyValue(const char *name),
+  **GetPolicyList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport const PolicyInfo
+  **GetPolicyInfoList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  IsRightsAuthorized(const PolicyDomain,const PolicyRights,const char *),
+  ListPolicyInfo(FILE *,ExceptionInfo *),
+  PolicyComponentGenesis(void);
+
+extern MagickExport void
+  PolicyComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/prepress.c b/MagickCore/prepress.c
new file mode 100644
index 0000000..76b09f6
--- /dev/null
+++ b/MagickCore/prepress.c
@@ -0,0 +1,151 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           PPPP    RRRR    EEEEE  PPPP   RRRR   EEEEE  SSSSS  SSSSS          %
+%           P   P   R   R   E      P   P  R   R  E      SS     SS             %
+%           PPPP    RRRR    EEE    PPPP   RRRR   EEE     SSS    SSS           %
+%           P       R R     E      P      R R    E         SS     SS          %
+%           P       R  R    EEEEE  P      R  R   EEEEE  SSSSS  SSSSS          %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Prepress Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                October 2001                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/image.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/prepress.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e T o t a l I n k D e n s i t y                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageTotalInkDensity() returns the total ink density for a CMYK image.
+%  Total Ink Density (TID) is determined by adding the CMYK values in the
+%  darkest shadow area in an image.
+%
+%  The format of the GetImageTotalInkDensity method is:
+%
+%      double GetImageTotalInkDensity(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport double GetImageTotalInkDensity(Image *image)
+{
+  CacheView
+    *image_view;
+
+  double
+    total_ink_density;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickSignature);
+  if (image->colorspace != CMYKColorspace)
+    {
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        ImageError,"ColorSeparatedImageRequired","`%s'",image->filename);
+      return(0.0);
+    }
+  status=MagickTrue;
+  total_ink_density=0.0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    double
+      density;
+
+    register const Quantum
+      *p;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      density=(double) GetPixelRed(image,p)+GetPixelGreen(image,p)+
+        GetPixelBlue(image,p)+GetPixelBlack(image,p);
+      if (density > total_ink_density)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_GetImageTotalInkDensity)
+#endif
+        {
+          if (density > total_ink_density)
+            total_ink_density=density;
+        }
+      p+=GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    total_ink_density=0.0;
+  return(total_ink_density);
+}
diff --git a/MagickCore/prepress.h b/MagickCore/prepress.h
new file mode 100644
index 0000000..b3c46a2
--- /dev/null
+++ b/MagickCore/prepress.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore prepress methods.
+*/
+#ifndef _MAGICKCORE_PREPRESS_H
+#define _MAGICKCORE_PREPRESS_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport double
+  GetImageTotalInkDensity(Image *image);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/profile.c b/MagickCore/profile.c
new file mode 100644
index 0000000..b3a747a
--- /dev/null
+++ b/MagickCore/profile.c
@@ -0,0 +1,1945 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               PPPP   RRRR    OOO   FFFFF  IIIII  L      EEEEE               %
+%               P   P  R   R  O   O  F        I    L      E                   %
+%               PPPP   RRRR   O   O  FFF      I    L      EEE                 %
+%               P      R R    O   O  F        I    L      E                   %
+%               P      R  R    OOO   F      IIIII  LLLLL  EEEEE               %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Image Profile Methods                      %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H)
+#include <wchar.h>
+#include <lcms/lcms2.h>
+#elif defined(MAGICKCORE_HAVE_LCMS2_H)
+#include <wchar.h>
+#include "lcms2.h"
+#elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H)
+#include <lcms/lcms.h>
+#else
+#include "lcms.h"
+#endif
+#endif
+
+/*
+  Define declarations.
+*/
+#if !defined(LCMS_VERSION) || (LCMS_VERSION < 2000)
+#define cmsSigCmykData icSigCmykData
+#define cmsSigGrayData icSigGrayData
+#define cmsSigLabData icSigLabData
+#define cmsSigLuvData icSigLuvData
+#define cmsSigRgbData icSigRgbData
+#define cmsSigXYZData icSigXYZData
+#define cmsSigYCbCrData icSigYCbCrData
+#define cmsSigLinkClass icSigLinkClass
+#define cmsColorSpaceSignature icColorSpaceSignature
+#define cmsUInt32Number  DWORD
+#define cmsSetLogErrorHandler(handler)  cmsSetErrorHandler(handler)
+#define cmsCreateTransformTHR(context,source_profile,source_type, \
+  target_profile,target_type,intent,flags)  cmsCreateTransform(source_profile, \
+  source_type,target_profile,target_type,intent,flags);
+#define cmsOpenProfileFromMemTHR(context,profile,length) \
+  cmsOpenProfileFromMem(profile,length)
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e P r o f i l e s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageProfiles() clones one or more image profiles.
+%
+%  The format of the CloneImageProfiles method is:
+%
+%      MagickBooleanType CloneImageProfiles(Image *image,
+%        const Image *clone_image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o clone_image: the clone image.
+%
+*/
+MagickExport MagickBooleanType CloneImageProfiles(Image *image,
+  const Image *clone_image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(clone_image != (const Image *) NULL);
+  assert(clone_image->signature == MagickSignature);
+  image->color_profile.length=clone_image->color_profile.length;
+  image->color_profile.info=clone_image->color_profile.info;
+  image->iptc_profile.length=clone_image->iptc_profile.length;
+  image->iptc_profile.info=clone_image->iptc_profile.info;
+  if (clone_image->profiles != (void *) NULL)
+    image->profiles=CloneSplayTree((SplayTreeInfo *) clone_image->profiles,
+      (void *(*)(void *)) ConstantString,(void *(*)(void *)) CloneStringInfo);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e P r o f i l e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageProfile() deletes a profile from the image by its name.
+%
+%  The format of the DeleteImageProfile method is:
+%
+%      MagickBooleanTyupe DeleteImageProfile(Image *image,const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o name: the profile name.
+%
+*/
+MagickExport MagickBooleanType DeleteImageProfile(Image *image,const char *name)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->profiles == (SplayTreeInfo *) NULL)
+    return(MagickFalse);
+  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->profiles,name));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e P r o f i l e s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageProfiles() releases memory associated with an image profile map.
+%
+%  The format of the DestroyProfiles method is:
+%
+%      void DestroyImageProfiles(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DestroyImageProfiles(Image *image)
+{
+  if (image->profiles != (SplayTreeInfo *) NULL)
+    image->profiles=DestroySplayTree((SplayTreeInfo *) image->profiles);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e P r o f i l e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageProfile() gets a profile associated with an image by name.
+%
+%  The format of the GetImageProfile method is:
+%
+%      const StringInfo *GetImageProfile(const Image *image,const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o name: the profile name.
+%
+*/
+MagickExport const StringInfo *GetImageProfile(const Image *image,
+  const char *name)
+{
+  char
+    key[MaxTextExtent];
+
+  const StringInfo
+    *profile;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->profiles == (SplayTreeInfo *) NULL)
+    return((StringInfo *) NULL);
+  (void) CopyMagickString(key,name,MaxTextExtent);
+  profile=(const StringInfo *) GetValueFromSplayTree((SplayTreeInfo *)
+    image->profiles,key);
+  return(profile);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e P r o f i l e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageProfile() gets the next profile name for an image.
+%
+%  The format of the GetNextImageProfile method is:
+%
+%      char *GetNextImageProfile(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o hash_info: the hash info.
+%
+*/
+MagickExport char *GetNextImageProfile(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->profiles == (SplayTreeInfo *) NULL)
+    return((char *) NULL);
+  return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->profiles));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P r o f i l e I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ProfileImage() associates, applies, or removes an ICM, IPTC, or generic
+%  profile with / to / from an image.  If the profile is NULL, it is removed
+%  from the image otherwise added or applied.  Use a name of '*' and a profile
+%  of NULL to remove all profiles from the image.
+%
+%  ICC and ICM profiles are handled as follows: If the image does not have
+%  an associated color profile, the one you provide is associated with the
+%  image and the image pixels are not transformed.  Otherwise, the colorspace
+%  transform defined by the existing and new profile are applied to the image
+%  pixels and the new profile is associated with the image.
+%
+%  The format of the ProfileImage method is:
+%
+%      MagickBooleanType ProfileImage(Image *image,const char *name,
+%        const void *datum,const size_t length,const MagickBooleanType clone)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o name: Name of profile to add or remove: ICC, IPTC, or generic profile.
+%
+%    o datum: the profile data.
+%
+%    o length: the length of the profile.
+%
+%    o clone: should be MagickFalse.
+%
+*/
+
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+
+static unsigned short **DestroyPixelThreadSet(unsigned short **pixels)
+{
+  register ssize_t
+    i;
+
+  assert(pixels != (unsigned short **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (pixels[i] != (unsigned short *) NULL)
+      pixels[i]=(unsigned short *) RelinquishMagickMemory(pixels[i]);
+  pixels=(unsigned short **) RelinquishMagickMemory(pixels);
+  return(pixels);
+}
+
+static unsigned short **AcquirePixelThreadSet(const size_t columns,
+  const size_t channels)
+{
+  register ssize_t
+    i;
+
+  unsigned short
+    **pixels;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixels=(unsigned short **) AcquireQuantumMemory(number_threads,
+    sizeof(*pixels));
+  if (pixels == (unsigned short **) NULL)
+    return((unsigned short **) NULL);
+  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    pixels[i]=(unsigned short *) AcquireQuantumMemory(columns,channels*
+      sizeof(**pixels));
+    if (pixels[i] == (unsigned short *) NULL)
+      return(DestroyPixelThreadSet(pixels));
+  }
+  return(pixels);
+}
+
+static cmsHTRANSFORM *DestroyTransformThreadSet(cmsHTRANSFORM *transform)
+{
+  register ssize_t
+    i;
+
+  assert(transform != (cmsHTRANSFORM *) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (transform[i] != (cmsHTRANSFORM) NULL)
+      cmsDeleteTransform(transform[i]);
+  transform=(cmsHTRANSFORM *) RelinquishMagickMemory(transform);
+  return(transform);
+}
+
+static cmsHTRANSFORM *AcquireTransformThreadSet(Image *image,
+  const cmsHPROFILE source_profile,const cmsUInt32Number source_type,
+  const cmsHPROFILE target_profile,const cmsUInt32Number target_type,
+  const int intent,const cmsUInt32Number flags)
+{
+  cmsHTRANSFORM
+    *transform;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  transform=(cmsHTRANSFORM *) AcquireQuantumMemory(number_threads,
+    sizeof(*transform));
+  if (transform == (cmsHTRANSFORM *) NULL)
+    return((cmsHTRANSFORM *) NULL);
+  (void) ResetMagickMemory(transform,0,number_threads*sizeof(*transform));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    transform[i]=cmsCreateTransformTHR(image,source_profile,source_type,
+      target_profile,target_type,intent,flags);
+    if (transform[i] == (cmsHTRANSFORM) NULL)
+      return(DestroyTransformThreadSet(transform));
+  }
+  return(transform);
+}
+#endif
+
+static MagickBooleanType SetAdobeRGB1998ImageProfile(Image *image)
+{
+  static unsigned char
+    AdobeRGB1998Profile[] =
+    {
+      0x00, 0x00, 0x02, 0x30, 0x41, 0x44, 0x42, 0x45, 0x02, 0x10, 0x00,
+      0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59,
+      0x5a, 0x20, 0x07, 0xd0, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x13, 0x00,
+      0x33, 0x00, 0x3b, 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, 0x4c,
+      0x00, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x6e, 0x65, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0xd3, 0x2d, 0x41, 0x44, 0x42, 0x45, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
+      0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
+      0x32, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00,
+      0x00, 0x6b, 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x9c, 0x00,
+      0x00, 0x00, 0x14, 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x01, 0xb0,
+      0x00, 0x00, 0x00, 0x14, 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01,
+      0xc4, 0x00, 0x00, 0x00, 0x0e, 0x67, 0x54, 0x52, 0x43, 0x00, 0x00,
+      0x01, 0xd4, 0x00, 0x00, 0x00, 0x0e, 0x62, 0x54, 0x52, 0x43, 0x00,
+      0x00, 0x01, 0xe4, 0x00, 0x00, 0x00, 0x0e, 0x72, 0x58, 0x59, 0x5a,
+      0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x00, 0x14, 0x67, 0x58, 0x59,
+      0x5a, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x14, 0x62, 0x58,
+      0x59, 0x5a, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x74,
+      0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79,
+      0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x30, 0x30, 0x20,
+      0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
+      0x6d, 0x73, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72,
+      0x61, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x41, 0x64, 0x6f,
+      0x62, 0x65, 0x20, 0x52, 0x47, 0x42, 0x20, 0x28, 0x31, 0x39, 0x39,
+      0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0xf3, 0x51, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x01, 0x16, 0xcc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x01, 0x02, 0x33, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x33, 0x00, 0x00,
+      0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x01, 0x02, 0x33, 0x00, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x9c, 0x18, 0x00, 0x00, 0x4f, 0xa5, 0x00,
+      0x00, 0x04, 0xfc, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x34, 0x8d, 0x00, 0x00, 0xa0, 0x2c, 0x00, 0x00, 0x0f,
+      0x95, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x26, 0x31, 0x00, 0x00, 0x10, 0x2f, 0x00, 0x00, 0xbe, 0x9c
+    };
+
+  StringInfo
+    *profile;
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (GetImageProfile(image,"icm") != (const StringInfo *) NULL)
+    return(MagickFalse);
+  profile=AcquireStringInfo(sizeof(AdobeRGB1998Profile));
+  SetStringInfoDatum(profile,AdobeRGB1998Profile);
+  status=SetImageProfile(image,"icm",profile);
+  profile=DestroyStringInfo(profile);
+  return(status);
+}
+
+static MagickBooleanType SetsRGBImageProfile(Image *image)
+{
+  static unsigned char
+    sRGBProfile[] =
+    {
+      0x00, 0x00, 0x0c, 0x48, 0x4c, 0x69, 0x6e, 0x6f, 0x02, 0x10, 0x00,
+      0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59,
+      0x5a, 0x20, 0x07, 0xce, 0x00, 0x02, 0x00, 0x09, 0x00, 0x06, 0x00,
+      0x31, 0x00, 0x00, 0x61, 0x63, 0x73, 0x70, 0x4d, 0x53, 0x46, 0x54,
+      0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47,
+      0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0xd3, 0x2d, 0x48, 0x50, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+      0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00,
+      0x33, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00,
+      0x00, 0x6c, 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0xf0, 0x00,
+      0x00, 0x00, 0x14, 0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x02, 0x04,
+      0x00, 0x00, 0x00, 0x14, 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x02,
+      0x18, 0x00, 0x00, 0x00, 0x14, 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00,
+      0x02, 0x2c, 0x00, 0x00, 0x00, 0x14, 0x62, 0x58, 0x59, 0x5a, 0x00,
+      0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x14, 0x64, 0x6d, 0x6e, 0x64,
+      0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70, 0x64, 0x6d, 0x64,
+      0x64, 0x00, 0x00, 0x02, 0xc4, 0x00, 0x00, 0x00, 0x88, 0x76, 0x75,
+      0x65, 0x64, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x86, 0x76,
+      0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xd4, 0x00, 0x00, 0x00, 0x24,
+      0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00,
+      0x14, 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x04, 0x0c, 0x00, 0x00,
+      0x00, 0x24, 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x04, 0x30, 0x00,
+      0x00, 0x00, 0x0c, 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x3c,
+      0x00, 0x00, 0x08, 0x0c, 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04,
+      0x3c, 0x00, 0x00, 0x08, 0x0c, 0x62, 0x54, 0x52, 0x43, 0x00, 0x00,
+      0x04, 0x3c, 0x00, 0x00, 0x08, 0x0c, 0x74, 0x65, 0x78, 0x74, 0x00,
+      0x00, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
+      0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x38, 0x20,
+      0x48, 0x65, 0x77, 0x6c, 0x65, 0x74, 0x74, 0x2d, 0x50, 0x61, 0x63,
+      0x6b, 0x61, 0x72, 0x64, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e,
+      0x79, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x12, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45,
+      0x43, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
+      0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39,
+      0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xf3, 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xcc, 0x58,
+      0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5a,
+      0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa2, 0x00, 0x00,
+      0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x99, 0x00, 0x00, 0xb7, 0x85,
+      0x00, 0x00, 0x18, 0xda, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x24, 0xa0, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00,
+      0xb6, 0xcf, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74, 0x70,
+      0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
+      0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74, 0x70,
+      0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x65, 0x63, 0x2e,
+      0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43, 0x20, 0x36, 0x31,
+      0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44, 0x65, 0x66,
+      0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63, 0x6f,
+      0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
+      0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43, 0x20,
+      0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x20, 0x44,
+      0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20,
+      0x63, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63,
+      0x65, 0x20, 0x2d, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73,
+      0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x52, 0x65,
+      0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x56, 0x69, 0x65,
+      0x77, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
+      0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 0x43, 0x36,
+      0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x52, 0x65,
+      0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x56, 0x69, 0x65,
+      0x77, 0x69, 0x6e, 0x67, 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74,
+      0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 0x43, 0x36,
+      0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
+      0xa4, 0xfe, 0x00, 0x14, 0x5f, 0x2e, 0x00, 0x10, 0xcf, 0x14, 0x00,
+      0x03, 0xed, 0xcc, 0x00, 0x04, 0x13, 0x0b, 0x00, 0x03, 0x5c, 0x9e,
+      0x00, 0x00, 0x00, 0x01, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x4c, 0x09, 0x56, 0x00, 0x50, 0x00, 0x00, 0x00, 0x57,
+      0x1f, 0xe7, 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+      0x8f, 0x00, 0x00, 0x00, 0x02, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00,
+      0x00, 0x00, 0x43, 0x52, 0x54, 0x20, 0x63, 0x75, 0x72, 0x76, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05,
+      0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19, 0x00, 0x1e, 0x00,
+      0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3b,
+      0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54, 0x00,
+      0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
+      0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00,
+      0x90, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9,
+      0x00, 0xae, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00,
+      0xc6, 0x00, 0xcb, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0,
+      0x00, 0xe5, 0x00, 0xeb, 0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01,
+      0x01, 0x01, 0x07, 0x01, 0x0d, 0x01, 0x13, 0x01, 0x19, 0x01, 0x1f,
+      0x01, 0x25, 0x01, 0x2b, 0x01, 0x32, 0x01, 0x38, 0x01, 0x3e, 0x01,
+      0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59, 0x01, 0x60, 0x01, 0x67,
+      0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83, 0x01, 0x8b, 0x01,
+      0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1, 0x01, 0xb9,
+      0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1, 0x01,
+      0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
+      0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02,
+      0x4b, 0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a,
+      0x02, 0x84, 0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02,
+      0xb6, 0x02, 0xc1, 0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb,
+      0x02, 0xf5, 0x03, 0x00, 0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03,
+      0x2d, 0x03, 0x38, 0x03, 0x43, 0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66,
+      0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a, 0x03, 0x96, 0x03, 0xa2, 0x03,
+      0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3, 0x03, 0xe0, 0x03, 0xec,
+      0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20, 0x04, 0x2d, 0x04,
+      0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71, 0x04, 0x7e,
+      0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4, 0x04,
+      0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
+      0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05,
+      0x77, 0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5,
+      0x05, 0xd5, 0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06,
+      0x27, 0x06, 0x37, 0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b,
+      0x06, 0x8c, 0x06, 0x9d, 0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06,
+      0xe3, 0x06, 0xf5, 0x07, 0x07, 0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d,
+      0x07, 0x4f, 0x07, 0x61, 0x07, 0x74, 0x07, 0x86, 0x07, 0x99, 0x07,
+      0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5, 0x07, 0xf8, 0x08, 0x0b,
+      0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a, 0x08, 0x6e, 0x08,
+      0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2, 0x08, 0xe7,
+      0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f, 0x09,
+      0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
+      0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a,
+      0x54, 0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5,
+      0x0a, 0xdc, 0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b,
+      0x51, 0x0b, 0x69, 0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8,
+      0x0b, 0xe1, 0x0b, 0xf9, 0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c,
+      0x5c, 0x0c, 0x75, 0x0c, 0x8e, 0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9,
+      0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26, 0x0d, 0x40, 0x0d, 0x5a, 0x0d,
+      0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3, 0x0d, 0xde, 0x0d, 0xf8,
+      0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64, 0x0e, 0x7f, 0x0e,
+      0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09, 0x0f, 0x25,
+      0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3, 0x0f,
+      0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
+      0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11,
+      0x13, 0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa,
+      0x11, 0xc9, 0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12,
+      0x64, 0x12, 0x84, 0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03,
+      0x13, 0x23, 0x13, 0x43, 0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13,
+      0xc5, 0x13, 0xe5, 0x14, 0x06, 0x14, 0x27, 0x14, 0x49, 0x14, 0x6a,
+      0x14, 0x8b, 0x14, 0xad, 0x14, 0xce, 0x14, 0xf0, 0x15, 0x12, 0x15,
+      0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b, 0x15, 0xbd, 0x15, 0xe0,
+      0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c, 0x16, 0x8f, 0x16,
+      0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41, 0x17, 0x65,
+      0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b, 0x18,
+      0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
+      0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19,
+      0xdd, 0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e,
+      0x1a, 0xc5, 0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b,
+      0x8a, 0x1b, 0xb2, 0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52,
+      0x1c, 0x7b, 0x1c, 0xa3, 0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d,
+      0x47, 0x1d, 0x70, 0x1d, 0x99, 0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16,
+      0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94, 0x1e, 0xbe, 0x1e, 0xe9, 0x1f,
+      0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94, 0x1f, 0xbf, 0x1f, 0xea,
+      0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98, 0x20, 0xc4, 0x20,
+      0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1, 0x21, 0xce,
+      0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf, 0x22,
+      0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
+      0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24,
+      0xda, 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7,
+      0x25, 0xf7, 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26,
+      0xe8, 0x27, 0x18, 0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc,
+      0x28, 0x0d, 0x28, 0x3f, 0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29,
+      0x06, 0x29, 0x38, 0x29, 0x6b, 0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02,
+      0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b, 0x2a, 0xcf, 0x2b, 0x02, 0x2b,
+      0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1, 0x2c, 0x05, 0x2c, 0x39,
+      0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c, 0x2d, 0x41, 0x2d,
+      0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c, 0x2e, 0x82,
+      0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91, 0x2f,
+      0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
+      0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32,
+      0x2a, 0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46,
+      0x33, 0x7f, 0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34,
+      0x9e, 0x34, 0xd8, 0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2,
+      0x35, 0xfd, 0x36, 0x37, 0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37,
+      0x24, 0x37, 0x60, 0x37, 0x9c, 0x37, 0xd7, 0x38, 0x14, 0x38, 0x50,
+      0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05, 0x39, 0x42, 0x39, 0x7f, 0x39,
+      0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74, 0x3a, 0xb2, 0x3a, 0xef,
+      0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8, 0x3c, 0x27, 0x3c,
+      0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61, 0x3d, 0xa1,
+      0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0, 0x3f,
+      0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
+      0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41,
+      0xee, 0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a,
+      0x43, 0x7d, 0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44,
+      0xce, 0x45, 0x12, 0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22,
+      0x46, 0x67, 0x46, 0xab, 0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47,
+      0xc0, 0x48, 0x05, 0x48, 0x4b, 0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d,
+      0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0, 0x4a, 0x37, 0x4a, 0x7d, 0x4a,
+      0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a, 0x4b, 0xe2, 0x4c, 0x2a,
+      0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a, 0x4d, 0x93, 0x4d,
+      0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00, 0x4f, 0x49,
+      0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb, 0x51,
+      0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
+      0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54,
+      0x42, 0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2,
+      0x56, 0x0f, 0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57,
+      0x92, 0x57, 0xe0, 0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a,
+      0x59, 0x69, 0x59, 0xb8, 0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a,
+      0xf5, 0x5b, 0x45, 0x5b, 0x95, 0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86,
+      0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78, 0x5d, 0xc9, 0x5e, 0x1a, 0x5e,
+      0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61, 0x5f, 0xb3, 0x60, 0x05,
+      0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f, 0x61, 0xa2, 0x61,
+      0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43, 0x63, 0x97,
+      0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d, 0x65,
+      0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
+      0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69,
+      0x43, 0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7,
+      0x6b, 0x4f, 0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d,
+      0x08, 0x6d, 0x60, 0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4,
+      0x6f, 0x1e, 0x6f, 0x78, 0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70,
+      0xe0, 0x71, 0x3a, 0x71, 0x95, 0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6,
+      0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8, 0x74, 0x14, 0x74, 0x70, 0x74,
+      0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1, 0x76, 0x3e, 0x76, 0x9b,
+      0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11, 0x78, 0x6e, 0x78,
+      0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46, 0x7a, 0xa5,
+      0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81, 0x7c,
+      0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
+      0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81,
+      0x0a, 0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4,
+      0x83, 0x57, 0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85,
+      0x47, 0x85, 0xab, 0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b,
+      0x87, 0x9f, 0x88, 0x04, 0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89,
+      0x99, 0x89, 0xfe, 0x8a, 0x64, 0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96,
+      0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca, 0x8d, 0x31, 0x8d, 0x98, 0x8d,
+      0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36, 0x8f, 0x9e, 0x90, 0x06,
+      0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8, 0x92, 0x11, 0x92,
+      0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20, 0x94, 0x8a,
+      0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f, 0x97,
+      0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
+      0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b,
+      0xaf, 0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2,
+      0x9e, 0x40, 0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0,
+      0x69, 0xa0, 0xd8, 0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96,
+      0xa3, 0x06, 0xa3, 0x76, 0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5,
+      0x38, 0xa5, 0xa9, 0xa6, 0x1a, 0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e,
+      0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4, 0xa9, 0x37, 0xa9, 0xa9, 0xaa,
+      0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75, 0xab, 0xe9, 0xac, 0x5c,
+      0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d, 0xae, 0xa1, 0xaf,
+      0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea, 0xb1, 0x60,
+      0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae, 0xb4,
+      0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
+      0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9,
+      0x4a, 0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7,
+      0xbc, 0x21, 0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe,
+      0x84, 0xbe, 0xff, 0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec,
+      0xc1, 0x67, 0xc1, 0xe3, 0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3,
+      0xd4, 0xc4, 0x51, 0xc4, 0xce, 0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46,
+      0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf, 0xc8, 0x3d, 0xc8, 0xbc, 0xc9,
+      0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7, 0xcb, 0x36, 0xcb, 0xb6,
+      0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5, 0xce, 0x36, 0xce,
+      0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba, 0xd1, 0x3c,
+      0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6, 0xd4,
+      0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
+      0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9,
+      0xf1, 0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a,
+      0xdd, 0x10, 0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf,
+      0xaf, 0xe0, 0x36, 0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53,
+      0xe2, 0xdb, 0xe3, 0x63, 0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5,
+      0x84, 0xe6, 0x0d, 0xe6, 0x96, 0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32,
+      0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0, 0xea, 0x5b, 0xea, 0xe5, 0xeb,
+      0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11, 0xed, 0x9c, 0xee, 0x28,
+      0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58, 0xf0, 0xe5, 0xf1,
+      0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7, 0xf4, 0x34,
+      0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb, 0xf7,
+      0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
+      0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd,
+      0xba, 0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff
+    };
+
+  StringInfo
+    *profile;
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (GetImageProfile(image,"icm") != (const StringInfo *) NULL)
+    return(MagickFalse);
+  profile=AcquireStringInfo(sizeof(sRGBProfile));
+  SetStringInfoDatum(profile,sRGBProfile);
+  status=SetImageProfile(image,"icm",profile);
+  profile=DestroyStringInfo(profile);
+  return(status);
+}
+#if defined(MAGICKCORE_LCMS_DELEGATE)
+#if defined(LCMS_VERSION) && (LCMS_VERSION >= 2000)
+static void LCMSExceptionHandler(cmsContext context,cmsUInt32Number severity,
+  const char *message)
+{
+  Image
+    *image;
+
+  (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%u, %s",
+    severity,message != (char *) NULL ? message : "no message");
+  image=(Image *) context;
+  if (image != (Image *) NULL)
+    (void) ThrowMagickException(&image->exception,GetMagickModule(),
+      ImageWarning,"UnableToTransformColorspace","`%s'",image->filename);
+
+}
+#else
+static int LCMSExceptionHandler(int severity,const char *message)
+{
+  (void) LogMagickEvent(TransformEvent,GetMagickModule(),"lcms: #%d, %s",
+    severity,message != (char *) NULL ? message : "no message");
+  return(1);
+}
+#endif
+#endif
+
+MagickExport MagickBooleanType ProfileImage(Image *image,const char *name,
+  const void *datum,const size_t length,
+  const MagickBooleanType magick_unused(clone))
+{
+#define ProfileImageTag  "Profile/Image"
+#define ThrowProfileException(severity,tag,context) \
+{ \
+  if (source_profile != (cmsHPROFILE) NULL) \
+    (void) cmsCloseProfile(source_profile); \
+  if (target_profile != (cmsHPROFILE) NULL) \
+    (void) cmsCloseProfile(target_profile); \
+  ThrowBinaryException(severity,tag,context); \
+}
+
+  MagickBooleanType
+    status;
+
+  StringInfo
+    *profile;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(name != (const char *) NULL);
+  if ((datum == (const void *) NULL) || (length == 0))
+    {
+      char
+        **arguments,
+        *names;
+
+      int
+        number_arguments;
+
+      register ssize_t
+        i;
+
+      /*
+        Delete image profile(s).
+      */
+      names=ConstantString(name);
+      (void) SubstituteString(&names,","," ");
+      arguments=StringToArgv(names,&number_arguments);
+      names=DestroyString(names);
+      if (arguments == (char **) NULL)
+        return(MagickTrue);
+      ResetImageProfileIterator(image);
+      for (name=GetNextImageProfile(image); name != (const char *) NULL; )
+      {
+        for (i=1; i < (ssize_t) number_arguments; i++)
+        {
+          if ((*arguments[i] == '!') &&
+              (LocaleCompare(name,arguments[i]+1) == 0))
+            break;
+          if (GlobExpression(name,arguments[i],MagickTrue) != MagickFalse)
+            {
+              (void) DeleteImageProfile(image,name);
+              ResetImageProfileIterator(image);
+              break;
+            }
+        }
+        name=GetNextImageProfile(image);
+      }
+      for (i=0; i < (ssize_t) number_arguments; i++)
+        arguments[i]=DestroyString(arguments[i]);
+      arguments=(char **) RelinquishMagickMemory(arguments);
+      return(MagickTrue);
+    }
+  /*
+    Add a ICC, IPTC, or generic profile to the image.
+  */
+  status=MagickTrue;
+  profile=AcquireStringInfo((size_t) length);
+  SetStringInfoDatum(profile,(unsigned char *) datum);
+  if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
+    status=SetImageProfile(image,name,profile);
+  else
+    {
+      const StringInfo
+        *icc_profile;
+
+      icc_profile=GetImageProfile(image,"icc");
+      if ((icc_profile != (const StringInfo *) NULL) &&
+          (CompareStringInfo(icc_profile,profile) == 0))
+        {
+          const char
+            *value;
+
+          value=GetImageProperty(image,"exif:ColorSpace");
+          if (LocaleCompare(value,"1") != 0)
+            (void) SetsRGBImageProfile(image);
+          value=GetImageProperty(image,"exif:InteroperabilityIndex");
+          if (LocaleCompare(value,"R98.") != 0)
+            (void) SetsRGBImageProfile(image);
+          value=GetImageProperty(image,"exif:InteroperabilityIndex");
+          if (LocaleCompare(value,"R03.") != 0)
+            (void) SetAdobeRGB1998ImageProfile(image);
+          icc_profile=GetImageProfile(image,"icc");
+        }
+      if ((icc_profile != (const StringInfo *) NULL) &&
+          (CompareStringInfo(icc_profile,profile) == 0))
+        {
+          profile=DestroyStringInfo(profile);
+          return(MagickTrue);
+        }
+#if !defined(MAGICKCORE_LCMS_DELEGATE)
+      (void) ThrowMagickException(&image->exception,GetMagickModule(),
+        MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn","`%s' (LCMS)",
+        image->filename);
+#else
+      {
+        cmsHPROFILE
+          source_profile;
+
+        /*
+          Transform pixel colors as defined by the color profiles.
+        */
+        cmsSetLogErrorHandler(LCMSExceptionHandler);
+        source_profile=cmsOpenProfileFromMemTHR(image,
+          GetStringInfoDatum(profile),(cmsUInt32Number)
+          GetStringInfoLength(profile));
+        if (source_profile == (cmsHPROFILE) NULL)
+          ThrowBinaryException(ResourceLimitError,
+            "ColorspaceColorProfileMismatch",name);
+        if ((cmsGetDeviceClass(source_profile) != cmsSigLinkClass) &&
+            (icc_profile == (StringInfo *) NULL))
+          status=SetImageProfile(image,name,profile);
+        else
+          {
+            CacheView
+              *image_view;
+
+            ColorspaceType
+              source_colorspace,
+              target_colorspace;
+
+            cmsColorSpaceSignature
+              signature;
+
+            cmsHPROFILE
+              target_profile;
+
+            cmsHTRANSFORM
+              *restrict transform;
+
+            cmsUInt32Number
+              flags,
+              source_type,
+              target_type;
+
+            ExceptionInfo
+              *exception;
+
+            int
+              intent;
+
+            MagickBooleanType
+              status;
+
+            MagickOffsetType
+              progress;
+
+            size_t
+              source_channels,
+              target_channels;
+
+            ssize_t
+              y;
+
+            unsigned short
+              **restrict source_pixels,
+              **restrict target_pixels;
+
+            exception=(&image->exception);
+            target_profile=(cmsHPROFILE) NULL;
+            if (icc_profile != (StringInfo *) NULL)
+              {
+                target_profile=source_profile;
+                source_profile=cmsOpenProfileFromMemTHR(image,
+                  GetStringInfoDatum(icc_profile),(cmsUInt32Number)
+                  GetStringInfoLength(icc_profile));
+                if (source_profile == (cmsHPROFILE) NULL)
+                  ThrowProfileException(ResourceLimitError,
+                    "ColorspaceColorProfileMismatch",name);
+              }
+            switch (cmsGetColorSpace(source_profile))
+            {
+              case cmsSigCmykData:
+              {
+                source_colorspace=CMYKColorspace;
+                source_type=(cmsUInt32Number) TYPE_CMYK_16;
+                source_channels=4;
+                break;
+              }
+              case cmsSigGrayData:
+              {
+                source_colorspace=GRAYColorspace;
+                source_type=(cmsUInt32Number) TYPE_GRAY_16;
+                source_channels=1;
+                break;
+              }
+              case cmsSigLabData:
+              {
+                source_colorspace=LabColorspace;
+                source_type=(cmsUInt32Number) TYPE_Lab_16;
+                source_channels=3;
+                break;
+              }
+              case cmsSigLuvData:
+              {
+                source_colorspace=YUVColorspace;
+                source_type=(cmsUInt32Number) TYPE_YUV_16;
+                source_channels=3;
+                break;
+              }
+              case cmsSigRgbData:
+              {
+                source_colorspace=RGBColorspace;
+                source_type=(cmsUInt32Number) TYPE_RGB_16;
+                source_channels=3;
+                break;
+              }
+              case cmsSigXYZData:
+              {
+                source_colorspace=XYZColorspace;
+                source_type=(cmsUInt32Number) TYPE_XYZ_16;
+                source_channels=3;
+                break;
+              }
+              case cmsSigYCbCrData:
+              {
+                source_colorspace=YCbCrColorspace;
+                source_type=(cmsUInt32Number) TYPE_YCbCr_16;
+                source_channels=3;
+                break;
+              }
+              default:
+              {
+                source_colorspace=UndefinedColorspace;
+                source_type=(cmsUInt32Number) TYPE_RGB_16;
+                source_channels=3;
+                break;
+              }
+            }
+            signature=cmsGetPCS(source_profile);
+            if (target_profile != (cmsHPROFILE) NULL)
+              signature=cmsGetColorSpace(target_profile);
+            switch (signature)
+            {
+              case cmsSigCmykData:
+              {
+                target_colorspace=CMYKColorspace;
+                target_type=(cmsUInt32Number) TYPE_CMYK_16;
+                target_channels=4;
+                break;
+              }
+              case cmsSigLabData:
+              {
+                target_colorspace=LabColorspace;
+                target_type=(cmsUInt32Number) TYPE_Lab_16;
+                target_channels=3;
+                break;
+              }
+              case cmsSigGrayData:
+              {
+                target_colorspace=GRAYColorspace;
+                target_type=(cmsUInt32Number) TYPE_GRAY_16;
+                target_channels=1;
+                break;
+              }
+              case cmsSigLuvData:
+              {
+                target_colorspace=YUVColorspace;
+                target_type=(cmsUInt32Number) TYPE_YUV_16;
+                target_channels=3;
+                break;
+              }
+              case cmsSigRgbData:
+              {
+                target_colorspace=RGBColorspace;
+                target_type=(cmsUInt32Number) TYPE_RGB_16;
+                target_channels=3;
+                break;
+              }
+              case cmsSigXYZData:
+              {
+                target_colorspace=XYZColorspace;
+                target_type=(cmsUInt32Number) TYPE_XYZ_16;
+                target_channels=3;
+                break;
+              }
+              case cmsSigYCbCrData:
+              {
+                target_colorspace=YCbCrColorspace;
+                target_type=(cmsUInt32Number) TYPE_YCbCr_16;
+                target_channels=3;
+                break;
+              }
+              default:
+              {
+                target_colorspace=UndefinedColorspace;
+                target_type=(cmsUInt32Number) TYPE_RGB_16;
+                target_channels=3;
+                break;
+              }
+            }
+            if ((source_colorspace == UndefinedColorspace) ||
+                (target_colorspace == UndefinedColorspace))
+              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+                name);
+             if ((source_colorspace == GRAYColorspace) &&
+                 (IsImageGray(image,exception) == MagickFalse))
+              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+                name);
+             if ((source_colorspace == CMYKColorspace) &&
+                 (image->colorspace != CMYKColorspace))
+              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+                name);
+             if ((source_colorspace == XYZColorspace) &&
+                 (image->colorspace != XYZColorspace))
+              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+                name);
+             if ((source_colorspace == YCbCrColorspace) &&
+                 (image->colorspace != YCbCrColorspace))
+              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+                name);
+             if ((source_colorspace != CMYKColorspace) &&
+                 (source_colorspace != GRAYColorspace) &&
+                 (source_colorspace != LabColorspace) &&
+                 (source_colorspace != XYZColorspace) &&
+                 (source_colorspace != YCbCrColorspace) &&
+                 (image->colorspace != RGBColorspace))
+              ThrowProfileException(ImageError,"ColorspaceColorProfileMismatch",
+                name);
+            switch (image->rendering_intent)
+            {
+              case AbsoluteIntent: intent=INTENT_ABSOLUTE_COLORIMETRIC; break;
+              case PerceptualIntent: intent=INTENT_PERCEPTUAL; break;
+              case RelativeIntent: intent=INTENT_RELATIVE_COLORIMETRIC; break;
+              case SaturationIntent: intent=INTENT_SATURATION; break;
+              default: intent=INTENT_PERCEPTUAL; break;
+            }
+            flags=cmsFLAGS_HIGHRESPRECALC;
+#if defined(cmsFLAGS_BLACKPOINTCOMPENSATION)
+            if (image->black_point_compensation != MagickFalse)
+              flags|=cmsFLAGS_BLACKPOINTCOMPENSATION;
+#endif
+            transform=AcquireTransformThreadSet(image,source_profile,
+              source_type,target_profile,target_type,intent,flags);
+            if (transform == (cmsHTRANSFORM *) NULL)
+              ThrowProfileException(ImageError,"UnableToCreateColorTransform",
+                name);
+            /*
+              Transform image as dictated by the source & target image profiles.
+            */
+            source_pixels=AcquirePixelThreadSet(image->columns,source_channels);
+            target_pixels=AcquirePixelThreadSet(image->columns,target_channels);
+            if ((source_pixels == (unsigned short **) NULL) ||
+                (target_pixels == (unsigned short **) NULL))
+              {
+                transform=DestroyTransformThreadSet(transform);
+                ThrowProfileException(ResourceLimitError,
+                  "MemoryAllocationFailed",image->filename);
+              }
+            if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+              {
+                target_pixels=DestroyPixelThreadSet(target_pixels);
+                source_pixels=DestroyPixelThreadSet(source_pixels);
+                transform=DestroyTransformThreadSet(transform);
+                if (source_profile != (cmsHPROFILE) NULL)
+                  (void) cmsCloseProfile(source_profile);
+                if (target_profile != (cmsHPROFILE) NULL)
+                  (void) cmsCloseProfile(target_profile);
+                return(MagickFalse);
+              }
+            if (target_colorspace == CMYKColorspace)
+              (void) SetImageColorspace(image,target_colorspace);
+            status=MagickTrue;
+            progress=0;
+            image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+            #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+            for (y=0; y < (ssize_t) image->rows; y++)
+            {
+              const int
+                id = GetOpenMPThreadId();
+
+              MagickBooleanType
+                sync;
+
+              register ssize_t
+                x;
+
+              register Quantum
+                *restrict q;
+
+              register unsigned short
+                *p;
+
+              if (status == MagickFalse)
+                continue;
+              q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+                exception);
+              if (q == (const Quantum *) NULL)
+                {
+                  status=MagickFalse;
+                  continue;
+                }
+              p=source_pixels[id];
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                *p++=ScaleQuantumToShort(GetPixelRed(image,q));
+                if (source_channels > 1)
+                  {
+                    *p++=ScaleQuantumToShort(GetPixelGreen(image,q));
+                    *p++=ScaleQuantumToShort(GetPixelBlue(image,q));
+                  }
+                if (source_channels > 3)
+                  *p++=ScaleQuantumToShort(GetPixelBlack(image,q));
+                q+=GetPixelChannels(image);
+              }
+              cmsDoTransform(transform[id],source_pixels[id],target_pixels[id],
+                (unsigned int) image->columns);
+              p=target_pixels[id];
+              q-=image->columns;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                SetPixelRed(image,ScaleShortToQuantum(*p),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p++;
+                if (target_channels > 1)
+                  {
+                    SetPixelGreen(image,ScaleShortToQuantum(*p),q);
+                    p++;
+                    SetPixelBlue(image,ScaleShortToQuantum(*p),q);
+                    p++;
+                  }
+                if (target_channels > 3)
+                  {
+                    SetPixelBlack(image,ScaleShortToQuantum(*p),q);
+                    p++;
+                  }
+                q+=GetPixelChannels(image);
+              }
+              sync=SyncCacheViewAuthenticPixels(image_view,exception);
+              if (sync == MagickFalse)
+                status=MagickFalse;
+              if (image->progress_monitor != (MagickProgressMonitor) NULL)
+                {
+                  MagickBooleanType
+                    proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp critical (MagickCore_ProfileImage)
+#endif
+                  proceed=SetImageProgress(image,ProfileImageTag,progress++,
+                    image->rows);
+                  if (proceed == MagickFalse)
+                    status=MagickFalse;
+                }
+            }
+            image_view=DestroyCacheView(image_view);
+            (void) SetImageColorspace(image,target_colorspace);
+            switch (signature)
+            {
+              case cmsSigRgbData:
+              {
+                image->type=image->matte == MagickFalse ? TrueColorType :
+                  TrueColorMatteType;
+                break;
+              }
+              case cmsSigCmykData:
+              {
+                image->type=image->matte == MagickFalse ? ColorSeparationType :
+                  ColorSeparationMatteType;
+                break;
+              }
+              case cmsSigGrayData:
+              {
+                image->type=image->matte == MagickFalse ? GrayscaleType :
+                  GrayscaleMatteType;
+                break;
+              }
+              default:
+                break;
+            }
+            target_pixels=DestroyPixelThreadSet(target_pixels);
+            source_pixels=DestroyPixelThreadSet(source_pixels);
+            transform=DestroyTransformThreadSet(transform);
+            if (cmsGetDeviceClass(source_profile) != cmsSigLinkClass)
+              status=SetImageProfile(image,name,profile);
+            if (target_profile != (cmsHPROFILE) NULL)
+              (void) cmsCloseProfile(target_profile);
+          }
+        (void) cmsCloseProfile(source_profile);
+      }
+#endif
+    }
+  profile=DestroyStringInfo(profile);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e I m a g e P r o f i l e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveImageProfile() removes a named profile from the image and returns its
+%  value.
+%
+%  The format of the RemoveImageProfile method is:
+%
+%      void *RemoveImageProfile(Image *image,const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o name: the profile name.
+%
+*/
+MagickExport StringInfo *RemoveImageProfile(Image *image,const char *name)
+{
+  StringInfo
+    *profile;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->profiles == (SplayTreeInfo *) NULL)
+    return((StringInfo *) NULL);
+  profile=(StringInfo *) RemoveNodeFromSplayTree((SplayTreeInfo *)
+    image->profiles,name);
+  return(profile);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t P r o f i l e I t e r a t o r                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImageProfileIterator() resets the image profile iterator.  Use it in
+%  conjunction with GetNextImageProfile() to iterate over all the profiles
+%  associated with an image.
+%
+%  The format of the ResetImageProfileIterator method is:
+%
+%      ResetImageProfileIterator(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void ResetImageProfileIterator(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->profiles == (SplayTreeInfo *) NULL)
+    return;
+  ResetSplayTreeIterator((SplayTreeInfo *) image->profiles);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e P r o f i l e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageProfile() adds a named profile to the image.  If a profile with the
+%  same name already exists, it is replaced.  This method differs from the
+%  ProfileImage() method in that it does not apply CMS color profiles.
+%
+%  The format of the SetImageProfile method is:
+%
+%      MagickBooleanType SetImageProfile(Image *image,const char *name,
+%        const StringInfo *profile)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o name: the profile name, for example icc, exif, and 8bim (8bim is the
+%      Photoshop wrapper for iptc profiles).
+%
+%    o profile: A StringInfo structure that contains the named profile.
+%
+*/
+
+static void *DestroyProfile(void *profile)
+{
+  return((void *) DestroyStringInfo((StringInfo *) profile));
+}
+
+static inline const unsigned char *ReadResourceByte(const unsigned char *p,
+  unsigned char *quantum)
+{
+  *quantum=(*p++);
+  return(p);
+}
+
+static inline const unsigned char *ReadResourceBytes(const unsigned char *p,
+  const ssize_t count,unsigned char *quantum)
+{
+  register ssize_t
+    i;
+
+  for (i=0; i < count; i++)
+    *quantum++=(*p++);
+  return(p);
+}
+
+static inline const unsigned char *ReadResourceLong(const unsigned char *p,
+  size_t *quantum)
+{
+  *quantum=(size_t) (*p++ << 24);
+  *quantum|=(size_t) (*p++ << 16);
+  *quantum|=(size_t) (*p++ << 8);
+  *quantum|=(size_t) (*p++ << 0);
+  return(p);
+}
+
+static inline const unsigned char *ReadResourceShort(const unsigned char *p,
+  unsigned short *quantum)
+{
+  *quantum=(unsigned short) (*p++ << 8);
+  *quantum|=(unsigned short) (*p++ << 0);
+  return(p);
+}
+
+static MagickBooleanType GetProfilesFromResourceBlock(Image *image,
+  const StringInfo *resource_block)
+{
+  const unsigned char
+    *datum;
+
+  register const unsigned char
+    *p;
+
+  size_t
+    length;
+
+  StringInfo
+    *profile;
+
+  unsigned char
+    length_byte;
+
+  size_t
+    count;
+
+  unsigned short
+    id;
+
+  datum=GetStringInfoDatum(resource_block);
+  length=GetStringInfoLength(resource_block);
+  for (p=datum; p < (datum+length-16); )
+  {
+    if (LocaleNCompare((char *) p,"8BIM",4) != 0)
+      break;
+    p+=4;
+    p=ReadResourceShort(p,&id);
+    p=ReadResourceByte(p,&length_byte);
+    p+=length_byte;
+    if (((length_byte+1) & 0x01) != 0)
+      p++;
+    if (p > (datum+length-4))
+      break;
+    p=ReadResourceLong(p,&count);
+    if ((p > (datum+length-count)) || (count > length))
+      break;
+    switch (id)
+    {
+      case 0x03ed:
+      {
+        unsigned short
+          resolution;
+
+        /*
+          Resolution.
+        */
+        p=ReadResourceShort(p,&resolution)+6;
+        image->x_resolution=(double) resolution;
+        p=ReadResourceShort(p,&resolution)+6;
+        image->y_resolution=(double) resolution;
+        break;
+      }
+      case 0x0404:
+      {
+        /*
+          IPTC Profile
+        */
+        profile=AcquireStringInfo(count);
+        SetStringInfoDatum(profile,p);
+        (void) SetImageProfile(image,"iptc",profile);
+        profile=DestroyStringInfo(profile);
+        p+=count;
+        break;
+      }
+      case 0x040c:
+      {
+        /*
+          Thumbnail.
+        */
+        p+=count;
+        break;
+      }
+      case 0x040f:
+      {
+        /*
+          ICC Profile.
+        */
+        profile=AcquireStringInfo(count);
+        SetStringInfoDatum(profile,p);
+        (void) SetImageProfile(image,"icc",profile);
+        profile=DestroyStringInfo(profile);
+        p+=count;
+        break;
+      }
+      case 0x0422:
+      {
+        /*
+          EXIF Profile.
+        */
+        profile=AcquireStringInfo(count);
+        SetStringInfoDatum(profile,p);
+        (void) SetImageProfile(image,"exif",profile);
+        profile=DestroyStringInfo(profile);
+        p+=count;
+        break;
+      }
+      case 0x0424:
+      {
+        /*
+          XMP Profile.
+        */
+        profile=AcquireStringInfo(count);
+        SetStringInfoDatum(profile,p);
+        (void) SetImageProfile(image,"xmp",profile);
+        profile=DestroyStringInfo(profile);
+        p+=count;
+        break;
+      }
+      default:
+      {
+        p+=count;
+        break;
+      }
+    }
+    if ((count & 0x01) != 0)
+      p++;
+  }
+  return(MagickTrue);
+}
+
+MagickExport MagickBooleanType SetImageProfile(Image *image,const char *name,
+  const StringInfo *profile)
+{
+  char
+    key[MaxTextExtent],
+    property[MaxTextExtent];
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->profiles == (SplayTreeInfo *) NULL)
+    image->profiles=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+      DestroyProfile);
+  (void) CopyMagickString(key,name,MaxTextExtent);
+  status=AddValueToSplayTree((SplayTreeInfo *) image->profiles,
+    ConstantString(key),CloneStringInfo(profile));
+  if ((status != MagickFalse) &&
+      ((LocaleCompare(name,"iptc") == 0) || (LocaleCompare(name,"8bim") == 0)))
+    (void) GetProfilesFromResourceBlock(image,profile);
+  /*
+    Inject profile into image properties.
+  */
+  (void) FormatLocaleString(property,MaxTextExtent,"%s:sans",name);
+  (void) GetImageProperty(image,property);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y n c I m a g e P r o f i l e s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncImageProfiles() synchronizes image properties with the image profiles.
+%  Currently we only support updating the EXIF resolution and orientation.
+%
+%  The format of the SyncImageProfiles method is:
+%
+%      MagickBooleanType SyncImageProfiles(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+
+static inline int ReadProfileByte(unsigned char **p,size_t *length)
+{
+  int
+    c;
+
+  if (*length < 1)
+    return(EOF);
+  c=(int) (*(*p)++);
+  (*length)--;
+  return(c);
+}
+
+static inline unsigned short ReadProfileShort(const EndianType endian,
+  unsigned char *buffer)
+{
+  unsigned short
+    value;
+
+  if (endian == MSBEndian)
+    {
+      value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
+        ((unsigned char *) buffer)[1]);
+      return((unsigned short) (value & 0xffff));
+    }
+  value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
+  return((unsigned short) (value & 0xffff));
+}
+
+static inline size_t ReadProfileLong(const EndianType endian,
+  unsigned char *buffer)
+{
+  size_t
+    value;
+
+  if (endian == MSBEndian)
+    {
+      value=(size_t) ((buffer[0] << 24) | (buffer[1] << 16) |
+        (buffer[2] << 8) | buffer[3]);
+      return((size_t) (value & 0xffffffff));
+    }
+  value=(size_t) ((buffer[3] << 24) | (buffer[2] << 16) |
+    (buffer[1] << 8 ) | (buffer[0]));
+  return((size_t) (value & 0xffffffff));
+}
+
+static inline void WriteProfileLong(const EndianType endian,
+  const size_t value,unsigned char *p)
+{
+  unsigned char
+    buffer[4];
+
+  if (endian == MSBEndian)
+    {
+      buffer[0]=(unsigned char) (value >> 24);
+      buffer[1]=(unsigned char) (value >> 16);
+      buffer[2]=(unsigned char) (value >> 8);
+      buffer[3]=(unsigned char) value;
+      (void) CopyMagickMemory(p,buffer,4);
+      return;
+    }
+  buffer[0]=(unsigned char) value;
+  buffer[1]=(unsigned char) (value >> 8);
+  buffer[2]=(unsigned char) (value >> 16);
+  buffer[3]=(unsigned char) (value >> 24);
+  (void) CopyMagickMemory(p,buffer,4);
+}
+
+static void WriteProfileShort(const EndianType endian,
+  const unsigned short value,unsigned char *p)
+{
+  unsigned char
+    buffer[2];
+
+  if (endian == MSBEndian)
+    {
+      buffer[0]=(unsigned char) (value >> 8);
+      buffer[1]=(unsigned char) value;
+      (void) CopyMagickMemory(p,buffer,2);
+      return;
+    }
+  buffer[0]=(unsigned char) value;
+  buffer[1]=(unsigned char) (value >> 8);
+  (void) CopyMagickMemory(p,buffer,2);
+}
+
+MagickExport MagickBooleanType SyncImageProfiles(Image *image)
+{
+#define MaxDirectoryStack  16
+#define EXIF_DELIMITER  "\n"
+#define EXIF_NUM_FORMATS  12
+#define TAG_EXIF_OFFSET  0x8769
+#define TAG_INTEROP_OFFSET  0xa005
+
+  typedef struct _DirectoryInfo
+  {
+    unsigned char
+      *directory;
+
+    size_t
+      entry;
+  } DirectoryInfo;
+
+  DirectoryInfo
+    directory_stack[MaxDirectoryStack];
+
+  EndianType
+    endian;
+
+  int
+    offset;
+
+  size_t
+    entry,
+    length,
+    number_entries;
+
+  ssize_t
+    id,
+    level;
+
+  static int
+    format_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
+
+  StringInfo
+    *profile;
+
+  unsigned char
+    *directory,
+    *exif;
+
+  /*
+    Set EXIF resolution tag.
+  */
+  profile=(StringInfo *) GetImageProfile(image,"EXIF");
+  if (profile == (StringInfo *) NULL)
+    return(MagickTrue);
+  length=GetStringInfoLength(profile);
+  exif=GetStringInfoDatum(profile);
+  while (length != 0)
+  {
+    if (ReadProfileByte(&exif,&length) != 0x45)
+      continue;
+    if (ReadProfileByte(&exif,&length) != 0x78)
+      continue;
+    if (ReadProfileByte(&exif,&length) != 0x69)
+      continue;
+    if (ReadProfileByte(&exif,&length) != 0x66)
+      continue;
+    if (ReadProfileByte(&exif,&length) != 0x00)
+      continue;
+    if (ReadProfileByte(&exif,&length) != 0x00)
+      continue;
+    break;
+  }
+  if (length < 16)
+    return(MagickFalse);
+  id=(ssize_t) ReadProfileShort(LSBEndian,exif);
+  endian=LSBEndian;
+  if (id == 0x4949)
+    endian=LSBEndian;
+  else
+    if (id == 0x4D4D)
+      endian=MSBEndian;
+    else
+      return(MagickFalse);
+  if (ReadProfileShort(endian,exif+2) != 0x002a)
+    return(MagickFalse);
+  /*
+    This the offset to the first IFD.
+  */
+  offset=(int) ReadProfileLong(endian,exif+4);
+  if ((size_t) offset >= length)
+    return(MagickFalse);
+  directory=exif+offset;
+  level=0;
+  entry=0;
+  do
+  {
+    if (level > 0)
+      {
+        level--;
+        directory=directory_stack[level].directory;
+        entry=directory_stack[level].entry;
+      }
+    /*
+      Determine how many entries there are in the current IFD.
+    */
+    number_entries=ReadProfileShort(endian,directory);
+    for ( ; entry < number_entries; entry++)
+    {
+      int
+        components;
+
+      register unsigned char
+        *p,
+        *q;
+
+      size_t
+        number_bytes;
+
+      ssize_t
+        format,
+        tag_value;
+
+      q=(unsigned char *) (directory+2+(12*entry));
+      tag_value=(ssize_t) ReadProfileShort(endian,q);
+      format=(ssize_t) ReadProfileShort(endian,q+2);
+      if ((format-1) >= EXIF_NUM_FORMATS)
+        break;
+      components=(int) ReadProfileLong(endian,q+4);
+      number_bytes=(size_t) components*format_bytes[format];
+      if (number_bytes <= 4)
+        p=q+8;
+      else
+        {
+          int
+            offset;
+
+          /*
+            The directory entry contains an offset.
+          */
+          offset=(int) ReadProfileLong(endian,q+8);
+          if ((size_t) (offset+number_bytes) > length)
+            continue;
+          p=(unsigned char *) (exif+offset);
+        }
+      switch (tag_value)
+      {
+        case 0x011a:
+        {
+          (void) WriteProfileLong(endian,(size_t)
+            (image->x_resolution+0.5),p);
+          (void) WriteProfileLong(endian,1UL,p+4);
+          break;
+        }
+        case 0x011b:
+        {
+          (void) WriteProfileLong(endian,(size_t)
+            (image->y_resolution+0.5),p);
+          (void) WriteProfileLong(endian,1UL,p+4);
+          break;
+        }
+        case 0x0112:
+        {
+          (void) WriteProfileShort(endian,(unsigned short)
+            image->orientation,p);
+          break;
+        }
+        case 0x0128:
+        {
+          (void) WriteProfileShort(endian,(unsigned short)
+            (image->units+1),p);
+          break;
+        }
+        default:
+          break;
+      }
+      if ((tag_value == TAG_EXIF_OFFSET) || (tag_value == TAG_INTEROP_OFFSET))
+        {
+          size_t
+            offset;
+
+          offset=(size_t) ReadProfileLong(endian,p);
+          if ((offset < length) && (level < (MaxDirectoryStack-2)))
+            {
+              directory_stack[level].directory=directory;
+              entry++;
+              directory_stack[level].entry=entry;
+              level++;
+              directory_stack[level].directory=exif+offset;
+              directory_stack[level].entry=0;
+              level++;
+              if ((directory+2+(12*number_entries)) > (exif+length))
+                break;
+              offset=(size_t) ReadProfileLong(endian,directory+2+(12*
+                number_entries));
+              if ((offset != 0) && (offset < length) &&
+                  (level < (MaxDirectoryStack-2)))
+                {
+                  directory_stack[level].directory=exif+offset;
+                  directory_stack[level].entry=0;
+                  level++;
+                }
+            }
+          break;
+        }
+    }
+  } while (level > 0);
+  return(MagickTrue);
+}
diff --git a/MagickCore/profile.h b/MagickCore/profile.h
new file mode 100644
index 0000000..7896e7a
--- /dev/null
+++ b/MagickCore/profile.h
@@ -0,0 +1,75 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image profile methods.
+*/
+#ifndef _MAGICKCORE_PROFILE_H
+#define _MAGICKCORE_PROFILE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/string_.h"
+
+typedef struct _ProfileInfo
+{
+  char
+    *name;
+
+  size_t
+    length;
+
+  unsigned char
+    *info;
+
+  size_t
+    signature;
+} ProfileInfo;
+
+typedef enum
+{
+  UndefinedIntent,
+  SaturationIntent,
+  PerceptualIntent,
+  AbsoluteIntent,
+  RelativeIntent
+} RenderingIntent;
+
+extern MagickExport char
+  *GetNextImageProfile(const Image *);
+
+extern MagickExport const StringInfo
+  *GetImageProfile(const Image *,const char *);
+
+extern MagickExport MagickBooleanType
+  CloneImageProfiles(Image *,const Image *),
+  DeleteImageProfile(Image *,const char *),
+  ProfileImage(Image *,const char *,const void *,const size_t,
+    const MagickBooleanType),
+  SetImageProfile(Image *,const char *,const StringInfo *),
+  SyncImageProfiles(Image *);
+
+extern MagickExport StringInfo
+  *RemoveImageProfile(Image *,const char *);
+
+extern MagickExport void
+  DestroyImageProfiles(Image *),
+  ResetImageProfileIterator(const Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif 
+#endif
diff --git a/MagickCore/property.c b/MagickCore/property.c
new file mode 100644
index 0000000..f38915e
--- /dev/null
+++ b/MagickCore/property.c
@@ -0,0 +1,3561 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%            PPPP    RRRR    OOO   PPPP   EEEEE  RRRR   TTTTT  Y   Y          %
+%            P   P   R   R  O   O  P   P  E      R   R    T     Y Y           %
+%            PPPP    RRRR   O   O  PPPP   EEE    RRRR     T      Y            %
+%            P       R R    O   O  P      E      R R      T      Y            %
+%            P       R  R    OOO   P      EEEEE  R  R     T      Y            %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Property Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 March 2000                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/compare.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/fx-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/option.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e I m a g e P r o p e r t i e s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneImageProperties() clones one or more image properties.
+%
+%  The format of the CloneImageProperties method is:
+%
+%      MagickBooleanType CloneImageProperties(Image *image,
+%        const Image *clone_image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o clone_image: the clone image.
+%
+*/
+MagickExport MagickBooleanType CloneImageProperties(Image *image,
+  const Image *clone_image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(clone_image != (const Image *) NULL);
+  assert(clone_image->signature == MagickSignature);
+  if (clone_image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      clone_image->filename);
+  (void) CopyMagickString(image->filename,clone_image->filename,MaxTextExtent);
+  (void) CopyMagickString(image->magick_filename,clone_image->magick_filename,
+    MaxTextExtent);
+  image->compression=clone_image->compression;
+  image->quality=clone_image->quality;
+  image->depth=clone_image->depth;
+  image->background_color=clone_image->background_color;
+  image->border_color=clone_image->border_color;
+  image->matte_color=clone_image->matte_color;
+  image->transparent_color=clone_image->transparent_color;
+  image->gamma=clone_image->gamma;
+  image->chromaticity=clone_image->chromaticity;
+  image->rendering_intent=clone_image->rendering_intent;
+  image->black_point_compensation=clone_image->black_point_compensation;
+  image->units=clone_image->units;
+  image->montage=(char *) NULL;
+  image->directory=(char *) NULL;
+  (void) CloneString(&image->geometry,clone_image->geometry);
+  image->offset=clone_image->offset;
+  image->x_resolution=clone_image->x_resolution;
+  image->y_resolution=clone_image->y_resolution;
+  image->page=clone_image->page;
+  image->tile_offset=clone_image->tile_offset;
+  image->extract_info=clone_image->extract_info;
+  image->bias=clone_image->bias;
+  image->filter=clone_image->filter;
+  image->blur=clone_image->blur;
+  image->fuzz=clone_image->fuzz;
+  image->interlace=clone_image->interlace;
+  image->interpolate=clone_image->interpolate;
+  image->endian=clone_image->endian;
+  image->gravity=clone_image->gravity;
+  image->compose=clone_image->compose;
+  image->scene=clone_image->scene;
+  image->orientation=clone_image->orientation;
+  image->dispose=clone_image->dispose;
+  image->delay=clone_image->delay;
+  image->ticks_per_second=clone_image->ticks_per_second;
+  image->iterations=clone_image->iterations;
+  image->total_colors=clone_image->total_colors;
+  image->taint=clone_image->taint;
+  image->progress_monitor=clone_image->progress_monitor;
+  image->client_data=clone_image->client_data;
+  image->start_loop=clone_image->start_loop;
+  image->error=clone_image->error;
+  image->signature=clone_image->signature;
+  if (clone_image->properties != (void *) NULL)
+    {
+      if (image->properties != (void *) NULL)
+        DestroyImageProperties(image);
+      image->properties=CloneSplayTree((SplayTreeInfo *)
+        clone_image->properties,(void *(*)(void *)) ConstantString,
+        (void *(*)(void *)) ConstantString);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e f i n e I m a g e P r o p e r t y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineImageProperty() associates a key/value pair with an image property.
+%
+%  The format of the DefineImageProperty method is:
+%
+%      MagickBooleanType DefineImageProperty(Image *image,
+%        const char *property)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o property: the image property.
+%
+*/
+MagickExport MagickBooleanType DefineImageProperty(Image *image,
+  const char *property)
+{
+  char
+    key[MaxTextExtent],
+    value[MaxTextExtent];
+
+  register char
+    *p;
+
+  assert(image != (Image *) NULL);
+  assert(property != (const char *) NULL);
+  (void) CopyMagickString(key,property,MaxTextExtent-1);
+  for (p=key; *p != '\0'; p++)
+    if (*p == '=')
+      break;
+  *value='\0';
+  if (*p == '=')
+    (void) CopyMagickString(value,p+1,MaxTextExtent);
+  *p='\0';
+  return(SetImageProperty(image,key,value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e P r o p e r t y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageProperty() deletes an image property.
+%
+%  The format of the DeleteImageProperty method is:
+%
+%      MagickBooleanType DeleteImageProperty(Image *image,const char *property)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o property: the image property.
+%
+*/
+MagickExport MagickBooleanType DeleteImageProperty(Image *image,
+  const char *property)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->properties == (void *) NULL)
+    return(MagickFalse);
+  return(DeleteNodeFromSplayTree((SplayTreeInfo *) image->properties,property));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y I m a g e P r o p e r t i e s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyImageProperties() releases memory associated with image property
+%  values.
+%
+%  The format of the DestroyDefines method is:
+%
+%      void DestroyImageProperties(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void DestroyImageProperties(Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->properties != (void *) NULL)
+    image->properties=(void *) DestroySplayTree((SplayTreeInfo *)
+      image->properties);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  F o r m a t I m a g e P r o p e r t y                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatImageProperty() permits formatted property/value pairs to be saved as
+%  an image property.
+%
+%  The format of the FormatImageProperty method is:
+%
+%      MagickBooleanType FormatImageProperty(Image *image,const char *property,
+%        const char *format,...)
+%
+%  A description of each parameter follows.
+%
+%   o  image:  The image.
+%
+%   o  property:  The attribute property.
+%
+%   o  format:  A string describing the format to use to write the remaining
+%      arguments.
+%
+*/
+MagickExport MagickBooleanType FormatImageProperty(Image *image,
+  const char *property,const char *format,...)
+{
+  char
+    value[MaxTextExtent];
+
+  ssize_t
+    n;
+
+  va_list
+    operands;
+
+  va_start(operands,format);
+  n=FormatLocaleStringList(value,MaxTextExtent,format,operands);
+  (void) n;
+  va_end(operands);
+  return(SetImageProperty(image,property,value));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e P r o p e r t y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageProperty() gets a value associated with an image property.
+%
+%  The format of the GetImageProperty method is:
+%
+%      const char *GetImageProperty(const Image *image,const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o key: the key.
+%
+*/
+
+static char
+  *TracePSClippath(const unsigned char *,size_t,const size_t,
+    const size_t),
+  *TraceSVGClippath(const unsigned char *,size_t,const size_t,
+    const size_t);
+
+static MagickBooleanType GetIPTCProperty(const Image *image,const char *key)
+{
+  char
+    *attribute,
+    *message;
+
+  const StringInfo
+    *profile;
+
+  long
+    count,
+    dataset,
+    record;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  profile=GetImageProfile(image,"iptc");
+  if (profile == (StringInfo *) NULL)
+    profile=GetImageProfile(image,"8bim");
+  if (profile == (StringInfo *) NULL)
+    return(MagickFalse);
+  count=sscanf(key,"IPTC:%ld:%ld",&dataset,&record);
+  if (count != 2)
+    return(MagickFalse);
+  attribute=(char *) NULL;
+  for (i=0; i < (ssize_t) GetStringInfoLength(profile); i+=(ssize_t) length)
+  {
+    length=1;
+    if ((ssize_t) GetStringInfoDatum(profile)[i] != 0x1c)
+      continue;
+    length=(size_t) (GetStringInfoDatum(profile)[i+3] << 8);
+    length|=GetStringInfoDatum(profile)[i+4];
+    if (((long) GetStringInfoDatum(profile)[i+1] == dataset) &&
+        ((long) GetStringInfoDatum(profile)[i+2] == record))
+      {
+        message=(char *) NULL;
+        if (~length >= 1)
+          message=(char *) AcquireQuantumMemory(length+1UL,sizeof(*message));
+        if (message != (char *) NULL)
+          {
+            (void) CopyMagickString(message,(char *) GetStringInfoDatum(
+              profile)+i+5,length+1);
+            (void) ConcatenateString(&attribute,message);
+            (void) ConcatenateString(&attribute,";");
+            message=DestroyString(message);
+          }
+      }
+    i+=5;
+  }
+  if ((attribute == (char *) NULL) || (*attribute == ';'))
+    {
+      if (attribute != (char *) NULL)
+        attribute=DestroyString(attribute);
+      return(MagickFalse);
+    }
+  attribute[strlen(attribute)-1]='\0';
+  (void) SetImageProperty((Image *) image,key,(const char *) attribute);
+  attribute=DestroyString(attribute);
+  return(MagickTrue);
+}
+
+static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline int ReadPropertyByte(const unsigned char **p,size_t *length)
+{
+  int
+    c;
+
+  if (*length < 1)
+    return(EOF);
+  c=(int) (*(*p)++);
+  (*length)--;
+  return(c);
+}
+
+static inline size_t ReadPropertyMSBLong(const unsigned char **p,
+  size_t *length)
+{
+  int
+    c;
+
+  register ssize_t
+    i;
+
+  unsigned char
+    buffer[4];
+
+  size_t
+    value;
+
+  if (*length < 4)
+    return(~0UL);
+  for (i=0; i < 4; i++)
+  {
+    c=(int) (*(*p)++);
+    (*length)--;
+    buffer[i]=(unsigned char) c;
+  }
+  value=(size_t) (buffer[0] << 24);
+  value|=buffer[1] << 16;
+  value|=buffer[2] << 8;
+  value|=buffer[3];
+  return(value & 0xffffffff);
+}
+
+static inline unsigned short ReadPropertyMSBShort(const unsigned char **p,
+  size_t *length)
+{
+  int
+    c;
+
+  register ssize_t
+    i;
+
+  unsigned char
+    buffer[2];
+
+  unsigned short
+    value;
+
+  if (*length < 2)
+    return((unsigned short) ~0U);
+  for (i=0; i < 2; i++)
+  {
+    c=(int) (*(*p)++);
+    (*length)--;
+    buffer[i]=(unsigned char) c;
+  }
+  value=(unsigned short) (buffer[0] << 8);
+  value|=buffer[1];
+  return((unsigned short) (value & 0xffff));
+}
+
+static MagickBooleanType Get8BIMProperty(const Image *image,const char *key)
+{
+  char
+    *attribute,
+    format[MaxTextExtent],
+    name[MaxTextExtent],
+    *resource;
+
+  const StringInfo
+    *profile;
+
+  const unsigned char
+    *info;
+
+  long
+    start,
+    stop;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    count,
+    id,
+    sub_number;
+
+  size_t
+    length;
+
+  /*
+    There are no newlines in path names, so it's safe as terminator.
+  */
+  profile=GetImageProfile(image,"8bim");
+  if (profile == (StringInfo *) NULL)
+    return(MagickFalse);
+  count=(ssize_t) sscanf(key,"8BIM:%ld,%ld:%[^\n]\n%[^\n]",&start,&stop,name,
+    format);
+  if ((count != 2) && (count != 3) && (count != 4))
+    return(MagickFalse);
+  if (count < 4)
+    (void) CopyMagickString(format,"SVG",MaxTextExtent);
+  if (count < 3)
+    *name='\0';
+  sub_number=1;
+  if (*name == '#')
+    sub_number=(ssize_t) StringToLong(&name[1]);
+  sub_number=MagickMax(sub_number,1L);
+  resource=(char *) NULL;
+  status=MagickFalse;
+  length=GetStringInfoLength(profile);
+  info=GetStringInfoDatum(profile);
+  while ((length > 0) && (status == MagickFalse))
+  {
+    if (ReadPropertyByte(&info,&length) != (unsigned char) '8')
+      continue;
+    if (ReadPropertyByte(&info,&length) != (unsigned char) 'B')
+      continue;
+    if (ReadPropertyByte(&info,&length) != (unsigned char) 'I')
+      continue;
+    if (ReadPropertyByte(&info,&length) != (unsigned char) 'M')
+      continue;
+    id=(ssize_t) ReadPropertyMSBShort(&info,&length);
+    if (id < (ssize_t) start)
+      continue;
+    if (id > (ssize_t) stop)
+      continue;
+    if (resource != (char *) NULL)
+      resource=DestroyString(resource);
+    count=(ssize_t) ReadPropertyByte(&info,&length);
+    if ((count != 0) && ((size_t) count <= length))
+      {
+        resource=(char *) NULL;
+        if (~(1UL*count) >= (MaxTextExtent-1))
+          resource=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
+            sizeof(*resource));
+        if (resource != (char *) NULL)
+          {
+            for (i=0; i < (ssize_t) count; i++)
+              resource[i]=(char) ReadPropertyByte(&info,&length);
+            resource[count]='\0';
+          }
+      }
+    if ((count & 0x01) == 0)
+      (void) ReadPropertyByte(&info,&length);
+    count=(ssize_t) ((int) ReadPropertyMSBLong(&info,&length));
+    if ((*name != '\0') && (*name != '#'))
+      if ((resource == (char *) NULL) || (LocaleCompare(name,resource) != 0))
+        {
+          /*
+            No name match, scroll forward and try next.
+          */
+          info+=count;
+          length-=count;
+          continue;
+        }
+    if ((*name == '#') && (sub_number != 1))
+      {
+        /*
+          No numbered match, scroll forward and try next.
+        */
+        sub_number--;
+        info+=count;
+        length-=count;
+        continue;
+      }
+    /*
+      We have the resource of interest.
+    */
+    attribute=(char *) NULL;
+    if (~(1UL*count) >= (MaxTextExtent-1))
+      attribute=(char *) AcquireQuantumMemory((size_t) count+MaxTextExtent,
+        sizeof(*attribute));
+    if (attribute != (char *) NULL)
+      {
+        (void) CopyMagickMemory(attribute,(char *) info,(size_t) count);
+        attribute[count]='\0';
+        info+=count;
+        length-=count;
+        if ((id <= 1999) || (id >= 2999))
+          (void) SetImageProperty((Image *) image,key,(const char *)
+            attribute);
+        else
+          {
+            char
+              *path;
+
+            if (LocaleCompare(format,"svg") == 0)
+              path=TraceSVGClippath((unsigned char *) attribute,(size_t) count,
+                image->columns,image->rows);
+            else
+              path=TracePSClippath((unsigned char *) attribute,(size_t) count,
+                image->columns,image->rows);
+            (void) SetImageProperty((Image *) image,key,(const char *) path);
+            path=DestroyString(path);
+          }
+        attribute=DestroyString(attribute);
+        status=MagickTrue;
+      }
+  }
+  if (resource != (char *) NULL)
+    resource=DestroyString(resource);
+  return(status);
+}
+
+static inline unsigned short ReadPropertyShort(const EndianType endian,
+  const unsigned char *buffer)
+{
+  unsigned short
+    value;
+
+  if (endian == MSBEndian)
+    {
+      value=(unsigned short) ((((unsigned char *) buffer)[0] << 8) |
+        ((unsigned char *) buffer)[1]);
+      return((unsigned short) (value & 0xffff));
+    }
+  value=(unsigned short) ((buffer[1] << 8) | buffer[0]);
+  return((unsigned short) (value & 0xffff));
+}
+
+static inline size_t ReadPropertyLong(const EndianType endian,
+  const unsigned char *buffer)
+{
+  size_t
+    value;
+
+  if (endian == MSBEndian)
+    {
+      value=(size_t) ((buffer[0] << 24) | (buffer[1] << 16) |
+        (buffer[2] << 8) | buffer[3]);
+      return((size_t) (value & 0xffffffff));
+    }
+  value=(size_t) ((buffer[3] << 24) | (buffer[2] << 16) |
+    (buffer[1] << 8 ) | (buffer[0]));
+  return((size_t) (value & 0xffffffff));
+}
+
+static MagickBooleanType GetEXIFProperty(const Image *image,
+  const char *property)
+{
+#define MaxDirectoryStack  16
+#define EXIF_DELIMITER  "\n"
+#define EXIF_NUM_FORMATS  12
+#define EXIF_FMT_BYTE  1
+#define EXIF_FMT_STRING  2
+#define EXIF_FMT_USHORT  3
+#define EXIF_FMT_ULONG  4
+#define EXIF_FMT_URATIONAL  5
+#define EXIF_FMT_SBYTE  6
+#define EXIF_FMT_UNDEFINED  7
+#define EXIF_FMT_SSHORT  8
+#define EXIF_FMT_SLONG  9
+#define EXIF_FMT_SRATIONAL  10
+#define EXIF_FMT_SINGLE  11
+#define EXIF_FMT_DOUBLE  12
+#define TAG_EXIF_OFFSET  0x8769
+#define TAG_GPS_OFFSET  0x8825
+#define TAG_INTEROP_OFFSET  0xa005
+
+#define EXIFMultipleValues(size, format, arg) \
+{ \
+   ssize_t \
+     component; \
+ \
+   size_t \
+     length; \
+ \
+   unsigned char \
+     *p1; \
+ \
+   length=0; \
+   p1=p; \
+   for (component=0; component < components; component++) \
+   { \
+     length+=FormatLocaleString(buffer+length,MaxTextExtent-length, \
+       format", ",arg); \
+     if (length >= (MaxTextExtent-1)) \
+       length=MaxTextExtent-1; \
+     p1+=size; \
+   } \
+   if (length > 1) \
+     buffer[length-2]='\0'; \
+   value=AcquireString(buffer); \
+}
+
+#define EXIFMultipleFractions(size, format, arg1, arg2) \
+{ \
+   ssize_t \
+     component; \
+ \
+   size_t \
+     length; \
+ \
+   unsigned char \
+     *p1; \
+ \
+   length=0; \
+   p1=p; \
+   for (component=0; component < components; component++) \
+   { \
+     length+=FormatLocaleString(buffer+length,MaxTextExtent-length, \
+       format", ",arg1, arg2); \
+     if (length >= (MaxTextExtent-1)) \
+       length=MaxTextExtent-1; \
+     p1+=size; \
+   } \
+   if (length > 1) \
+     buffer[length-2]='\0'; \
+   value=AcquireString(buffer); \
+}
+
+  typedef struct _DirectoryInfo
+  {
+    const unsigned char
+      *directory;
+
+    size_t
+      entry,
+      offset;
+  } DirectoryInfo;
+
+  typedef struct _TagInfo
+  {
+    size_t
+      tag;
+
+    const char
+      *description;
+  } TagInfo;
+
+  static TagInfo
+    EXIFTag[] =
+    {
+      {  0x001, "exif:InteroperabilityIndex" },
+      {  0x002, "exif:InteroperabilityVersion" },
+      {  0x100, "exif:ImageWidth" },
+      {  0x101, "exif:ImageLength" },
+      {  0x102, "exif:BitsPerSample" },
+      {  0x103, "exif:Compression" },
+      {  0x106, "exif:PhotometricInterpretation" },
+      {  0x10a, "exif:FillOrder" },
+      {  0x10d, "exif:DocumentName" },
+      {  0x10e, "exif:ImageDescription" },
+      {  0x10f, "exif:Make" },
+      {  0x110, "exif:Model" },
+      {  0x111, "exif:StripOffsets" },
+      {  0x112, "exif:Orientation" },
+      {  0x115, "exif:SamplesPerPixel" },
+      {  0x116, "exif:RowsPerStrip" },
+      {  0x117, "exif:StripByteCounts" },
+      {  0x11a, "exif:XResolution" },
+      {  0x11b, "exif:YResolution" },
+      {  0x11c, "exif:PlanarConfiguration" },
+      {  0x11d, "exif:PageName" },
+      {  0x11e, "exif:XPosition" },
+      {  0x11f, "exif:YPosition" },
+      {  0x118, "exif:MinSampleValue" },
+      {  0x119, "exif:MaxSampleValue" },
+      {  0x120, "exif:FreeOffsets" },
+      {  0x121, "exif:FreeByteCounts" },
+      {  0x122, "exif:GrayResponseUnit" },
+      {  0x123, "exif:GrayResponseCurve" },
+      {  0x124, "exif:T4Options" },
+      {  0x125, "exif:T6Options" },
+      {  0x128, "exif:ResolutionUnit" },
+      {  0x12d, "exif:TransferFunction" },
+      {  0x131, "exif:Software" },
+      {  0x132, "exif:DateTime" },
+      {  0x13b, "exif:Artist" },
+      {  0x13e, "exif:WhitePoint" },
+      {  0x13f, "exif:PrimaryChromaticities" },
+      {  0x140, "exif:ColorMap" },
+      {  0x141, "exif:HalfToneHints" },
+      {  0x142, "exif:TileWidth" },
+      {  0x143, "exif:TileLength" },
+      {  0x144, "exif:TileOffsets" },
+      {  0x145, "exif:TileByteCounts" },
+      {  0x14a, "exif:SubIFD" },
+      {  0x14c, "exif:InkSet" },
+      {  0x14d, "exif:InkNames" },
+      {  0x14e, "exif:NumberOfInks" },
+      {  0x150, "exif:DotRange" },
+      {  0x151, "exif:TargetPrinter" },
+      {  0x152, "exif:ExtraSample" },
+      {  0x153, "exif:SampleFormat" },
+      {  0x154, "exif:SMinSampleValue" },
+      {  0x155, "exif:SMaxSampleValue" },
+      {  0x156, "exif:TransferRange" },
+      {  0x157, "exif:ClipPath" },
+      {  0x158, "exif:XClipPathUnits" },
+      {  0x159, "exif:YClipPathUnits" },
+      {  0x15a, "exif:Indexed" },
+      {  0x15b, "exif:JPEGTables" },
+      {  0x15f, "exif:OPIProxy" },
+      {  0x200, "exif:JPEGProc" },
+      {  0x201, "exif:JPEGInterchangeFormat" },
+      {  0x202, "exif:JPEGInterchangeFormatLength" },
+      {  0x203, "exif:JPEGRestartInterval" },
+      {  0x205, "exif:JPEGLosslessPredictors" },
+      {  0x206, "exif:JPEGPointTransforms" },
+      {  0x207, "exif:JPEGQTables" },
+      {  0x208, "exif:JPEGDCTables" },
+      {  0x209, "exif:JPEGACTables" },
+      {  0x211, "exif:YCbCrCoefficients" },
+      {  0x212, "exif:YCbCrSubSampling" },
+      {  0x213, "exif:YCbCrPositioning" },
+      {  0x214, "exif:ReferenceBlackWhite" },
+      {  0x2bc, "exif:ExtensibleMetadataPlatform" },
+      {  0x301, "exif:Gamma" },
+      {  0x302, "exif:ICCProfileDescriptor" },
+      {  0x303, "exif:SRGBRenderingIntent" },
+      {  0x320, "exif:ImageTitle" },
+      {  0x5001, "exif:ResolutionXUnit" },
+      {  0x5002, "exif:ResolutionYUnit" },
+      {  0x5003, "exif:ResolutionXLengthUnit" },
+      {  0x5004, "exif:ResolutionYLengthUnit" },
+      {  0x5005, "exif:PrintFlags" },
+      {  0x5006, "exif:PrintFlagsVersion" },
+      {  0x5007, "exif:PrintFlagsCrop" },
+      {  0x5008, "exif:PrintFlagsBleedWidth" },
+      {  0x5009, "exif:PrintFlagsBleedWidthScale" },
+      {  0x500A, "exif:HalftoneLPI" },
+      {  0x500B, "exif:HalftoneLPIUnit" },
+      {  0x500C, "exif:HalftoneDegree" },
+      {  0x500D, "exif:HalftoneShape" },
+      {  0x500E, "exif:HalftoneMisc" },
+      {  0x500F, "exif:HalftoneScreen" },
+      {  0x5010, "exif:JPEGQuality" },
+      {  0x5011, "exif:GridSize" },
+      {  0x5012, "exif:ThumbnailFormat" },
+      {  0x5013, "exif:ThumbnailWidth" },
+      {  0x5014, "exif:ThumbnailHeight" },
+      {  0x5015, "exif:ThumbnailColorDepth" },
+      {  0x5016, "exif:ThumbnailPlanes" },
+      {  0x5017, "exif:ThumbnailRawBytes" },
+      {  0x5018, "exif:ThumbnailSize" },
+      {  0x5019, "exif:ThumbnailCompressedSize" },
+      {  0x501a, "exif:ColorTransferFunction" },
+      {  0x501b, "exif:ThumbnailData" },
+      {  0x5020, "exif:ThumbnailImageWidth" },
+      {  0x5021, "exif:ThumbnailImageHeight" },
+      {  0x5022, "exif:ThumbnailBitsPerSample" },
+      {  0x5023, "exif:ThumbnailCompression" },
+      {  0x5024, "exif:ThumbnailPhotometricInterp" },
+      {  0x5025, "exif:ThumbnailImageDescription" },
+      {  0x5026, "exif:ThumbnailEquipMake" },
+      {  0x5027, "exif:ThumbnailEquipModel" },
+      {  0x5028, "exif:ThumbnailStripOffsets" },
+      {  0x5029, "exif:ThumbnailOrientation" },
+      {  0x502a, "exif:ThumbnailSamplesPerPixel" },
+      {  0x502b, "exif:ThumbnailRowsPerStrip" },
+      {  0x502c, "exif:ThumbnailStripBytesCount" },
+      {  0x502d, "exif:ThumbnailResolutionX" },
+      {  0x502e, "exif:ThumbnailResolutionY" },
+      {  0x502f, "exif:ThumbnailPlanarConfig" },
+      {  0x5030, "exif:ThumbnailResolutionUnit" },
+      {  0x5031, "exif:ThumbnailTransferFunction" },
+      {  0x5032, "exif:ThumbnailSoftwareUsed" },
+      {  0x5033, "exif:ThumbnailDateTime" },
+      {  0x5034, "exif:ThumbnailArtist" },
+      {  0x5035, "exif:ThumbnailWhitePoint" },
+      {  0x5036, "exif:ThumbnailPrimaryChromaticities" },
+      {  0x5037, "exif:ThumbnailYCbCrCoefficients" },
+      {  0x5038, "exif:ThumbnailYCbCrSubsampling" },
+      {  0x5039, "exif:ThumbnailYCbCrPositioning" },
+      {  0x503A, "exif:ThumbnailRefBlackWhite" },
+      {  0x503B, "exif:ThumbnailCopyRight" },
+      {  0x5090, "exif:LuminanceTable" },
+      {  0x5091, "exif:ChrominanceTable" },
+      {  0x5100, "exif:FrameDelay" },
+      {  0x5101, "exif:LoopCount" },
+      {  0x5110, "exif:PixelUnit" },
+      {  0x5111, "exif:PixelPerUnitX" },
+      {  0x5112, "exif:PixelPerUnitY" },
+      {  0x5113, "exif:PaletteHistogram" },
+      {  0x1000, "exif:RelatedImageFileFormat" },
+      {  0x1001, "exif:RelatedImageLength" },
+      {  0x1002, "exif:RelatedImageWidth" },
+      {  0x800d, "exif:ImageID" },
+      {  0x80e3, "exif:Matteing" },
+      {  0x80e4, "exif:DataType" },
+      {  0x80e5, "exif:ImageDepth" },
+      {  0x80e6, "exif:TileDepth" },
+      {  0x828d, "exif:CFARepeatPatternDim" },
+      {  0x828e, "exif:CFAPattern2" },
+      {  0x828f, "exif:BatteryLevel" },
+      {  0x8298, "exif:Copyright" },
+      {  0x829a, "exif:ExposureTime" },
+      {  0x829d, "exif:FNumber" },
+      {  0x83bb, "exif:IPTC/NAA" },
+      {  0x84e3, "exif:IT8RasterPadding" },
+      {  0x84e5, "exif:IT8ColorTable" },
+      {  0x8649, "exif:ImageResourceInformation" },
+      {  0x8769, "exif:ExifOffset" },
+      {  0x8773, "exif:InterColorProfile" },
+      {  0x8822, "exif:ExposureProgram" },
+      {  0x8824, "exif:SpectralSensitivity" },
+      {  0x8825, "exif:GPSInfo" },
+      {  0x8827, "exif:ISOSpeedRatings" },
+      {  0x8828, "exif:OECF" },
+      {  0x8829, "exif:Interlace" },
+      {  0x882a, "exif:TimeZoneOffset" },
+      {  0x882b, "exif:SelfTimerMode" },
+      {  0x9000, "exif:ExifVersion" },
+      {  0x9003, "exif:DateTimeOriginal" },
+      {  0x9004, "exif:DateTimeDigitized" },
+      {  0x9101, "exif:ComponentsConfiguration" },
+      {  0x9102, "exif:CompressedBitsPerPixel" },
+      {  0x9201, "exif:ShutterSpeedValue" },
+      {  0x9202, "exif:ApertureValue" },
+      {  0x9203, "exif:BrightnessValue" },
+      {  0x9204, "exif:ExposureBiasValue" },
+      {  0x9205, "exif:MaxApertureValue" },
+      {  0x9206, "exif:SubjectDistance" },
+      {  0x9207, "exif:MeteringMode" },
+      {  0x9208, "exif:LightSource" },
+      {  0x9209, "exif:Flash" },
+      {  0x920a, "exif:FocalLength" },
+      {  0x920b, "exif:FlashEnergy" },
+      {  0x920c, "exif:SpatialFrequencyResponse" },
+      {  0x920d, "exif:Noise" },
+      {  0x9211, "exif:ImageNumber" },
+      {  0x9212, "exif:SecurityClassification" },
+      {  0x9213, "exif:ImageHistory" },
+      {  0x9214, "exif:SubjectArea" },
+      {  0x9215, "exif:ExposureIndex" },
+      {  0x9216, "exif:TIFF-EPStandardID" },
+      {  0x927c, "exif:MakerNote" },
+      {  0x9C9b, "exif:WinXP-Title" },
+      {  0x9C9c, "exif:WinXP-Comments" },
+      {  0x9C9d, "exif:WinXP-Author" },
+      {  0x9C9e, "exif:WinXP-Keywords" },
+      {  0x9C9f, "exif:WinXP-Subject" },
+      {  0x9286, "exif:UserComment" },
+      {  0x9290, "exif:SubSecTime" },
+      {  0x9291, "exif:SubSecTimeOriginal" },
+      {  0x9292, "exif:SubSecTimeDigitized" },
+      {  0xa000, "exif:FlashPixVersion" },
+      {  0xa001, "exif:ColorSpace" },
+      {  0xa002, "exif:ExifImageWidth" },
+      {  0xa003, "exif:ExifImageLength" },
+      {  0xa004, "exif:RelatedSoundFile" },
+      {  0xa005, "exif:InteroperabilityOffset" },
+      {  0xa20b, "exif:FlashEnergy" },
+      {  0xa20c, "exif:SpatialFrequencyResponse" },
+      {  0xa20d, "exif:Noise" },
+      {  0xa20e, "exif:FocalPlaneXResolution" },
+      {  0xa20f, "exif:FocalPlaneYResolution" },
+      {  0xa210, "exif:FocalPlaneResolutionUnit" },
+      {  0xa214, "exif:SubjectLocation" },
+      {  0xa215, "exif:ExposureIndex" },
+      {  0xa216, "exif:TIFF/EPStandardID" },
+      {  0xa217, "exif:SensingMethod" },
+      {  0xa300, "exif:FileSource" },
+      {  0xa301, "exif:SceneType" },
+      {  0xa302, "exif:CFAPattern" },
+      {  0xa401, "exif:CustomRendered" },
+      {  0xa402, "exif:ExposureMode" },
+      {  0xa403, "exif:WhiteBalance" },
+      {  0xa404, "exif:DigitalZoomRatio" },
+      {  0xa405, "exif:FocalLengthIn35mmFilm" },
+      {  0xa406, "exif:SceneCaptureType" },
+      {  0xa407, "exif:GainControl" },
+      {  0xa408, "exif:Contrast" },
+      {  0xa409, "exif:Saturation" },
+      {  0xa40a, "exif:Sharpness" },
+      {  0xa40b, "exif:DeviceSettingDescription" },
+      {  0xa40c, "exif:SubjectDistanceRange" },
+      {  0xa420, "exif:ImageUniqueID" },
+      {  0xc4a5, "exif:PrintImageMatching" },
+      {  0xa500, "exif:Gamma" },
+      {  0xc640, "exif:CR2Slice" },
+      { 0x10000, "exif:GPSVersionID" },
+      { 0x10001, "exif:GPSLatitudeRef" },
+      { 0x10002, "exif:GPSLatitude" },
+      { 0x10003, "exif:GPSLongitudeRef" },
+      { 0x10004, "exif:GPSLongitude" },
+      { 0x10005, "exif:GPSAltitudeRef" },
+      { 0x10006, "exif:GPSAltitude" },
+      { 0x10007, "exif:GPSTimeStamp" },
+      { 0x10008, "exif:GPSSatellites" },
+      { 0x10009, "exif:GPSStatus" },
+      { 0x1000a, "exif:GPSMeasureMode" },
+      { 0x1000b, "exif:GPSDop" },
+      { 0x1000c, "exif:GPSSpeedRef" },
+      { 0x1000d, "exif:GPSSpeed" },
+      { 0x1000e, "exif:GPSTrackRef" },
+      { 0x1000f, "exif:GPSTrack" },
+      { 0x10010, "exif:GPSImgDirectionRef" },
+      { 0x10011, "exif:GPSImgDirection" },
+      { 0x10012, "exif:GPSMapDatum" },
+      { 0x10013, "exif:GPSDestLatitudeRef" },
+      { 0x10014, "exif:GPSDestLatitude" },
+      { 0x10015, "exif:GPSDestLongitudeRef" },
+      { 0x10016, "exif:GPSDestLongitude" },
+      { 0x10017, "exif:GPSDestBearingRef" },
+      { 0x10018, "exif:GPSDestBearing" },
+      { 0x10019, "exif:GPSDestDistanceRef" },
+      { 0x1001a, "exif:GPSDestDistance" },
+      { 0x1001b, "exif:GPSProcessingMethod" },
+      { 0x1001c, "exif:GPSAreaInformation" },
+      { 0x1001d, "exif:GPSDateStamp" },
+      { 0x1001e, "exif:GPSDifferential" },
+      {  0x0000, NULL}
+    };
+
+  const StringInfo
+    *profile;
+
+  const unsigned char
+    *directory,
+    *exif;
+
+  DirectoryInfo
+    directory_stack[MaxDirectoryStack];
+
+  EndianType
+    endian;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    entry,
+    length,
+    number_entries,
+    tag_offset,
+    tag;
+
+  ssize_t
+    all,
+    id,
+    level,
+    offset,
+    tag_value;
+
+  static int
+    tag_bytes[] = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
+
+  /*
+    If EXIF data exists, then try to parse the request for a tag.
+  */
+  profile=GetImageProfile(image,"exif");
+  if (profile == (StringInfo *) NULL)
+    return(MagickFalse);
+  if ((property == (const char *) NULL) || (*property == '\0'))
+    return(MagickFalse);
+  while (isspace((int) ((unsigned char) *property)) != 0)
+    property++;
+  all=0;
+  tag=(~0UL);
+  switch (*(property+5))
+  {
+    case '*':
+    {
+      /*
+        Caller has asked for all the tags in the EXIF data.
+      */
+      tag=0;
+      all=1; /* return the data in description=value format */
+      break;
+    }
+    case '!':
+    {
+      tag=0;
+      all=2; /* return the data in tagid=value format */
+      break;
+    }
+    case '#':
+    case '@':
+    {
+      int
+        c;
+
+      size_t
+        n;
+
+      /*
+        Check for a hex based tag specification first.
+      */
+      tag=(*(property+5) == '@') ? 1UL : 0UL;
+      property+=6;
+      n=strlen(property);
+      if (n != 4)
+        return(MagickFalse);
+      /*
+        Parse tag specification as a hex number.
+      */
+      n/=4;
+      do
+      {
+        for (i=(ssize_t) n-1L; i >= 0; i--)
+        {
+          c=(*property++);
+          tag<<=4;
+          if ((c >= '0') && (c <= '9'))
+            tag|=(c-'0');
+          else
+            if ((c >= 'A') && (c <= 'F'))
+              tag|=(c-('A'-10));
+            else
+              if ((c >= 'a') && (c <= 'f'))
+                tag|=(c-('a'-10));
+              else
+                return(MagickFalse);
+        }
+      } while (*property != '\0');
+      break;
+    }
+    default:
+    {
+      /*
+        Try to match the text with a tag name instead.
+      */
+      for (i=0; ; i++)
+      {
+        if (EXIFTag[i].tag == 0)
+          break;
+        if (LocaleCompare(EXIFTag[i].description,property) == 0)
+          {
+            tag=(size_t) EXIFTag[i].tag;
+            break;
+          }
+      }
+      break;
+    }
+  }
+  if (tag == (~0UL))
+    return(MagickFalse);
+  length=GetStringInfoLength(profile);
+  exif=GetStringInfoDatum(profile);
+  while (length != 0)
+  {
+    if (ReadPropertyByte(&exif,&length) != 0x45)
+      continue;
+    if (ReadPropertyByte(&exif,&length) != 0x78)
+      continue;
+    if (ReadPropertyByte(&exif,&length) != 0x69)
+      continue;
+    if (ReadPropertyByte(&exif,&length) != 0x66)
+      continue;
+    if (ReadPropertyByte(&exif,&length) != 0x00)
+      continue;
+    if (ReadPropertyByte(&exif,&length) != 0x00)
+      continue;
+    break;
+  }
+  if (length < 16)
+    return(MagickFalse);
+  id=(ssize_t) ReadPropertyShort(LSBEndian,exif);
+  endian=LSBEndian;
+  if (id == 0x4949)
+    endian=LSBEndian;
+  else
+    if (id == 0x4D4D)
+      endian=MSBEndian;
+    else
+      return(MagickFalse);
+  if (ReadPropertyShort(endian,exif+2) != 0x002a)
+    return(MagickFalse);
+  /*
+    This the offset to the first IFD.
+  */
+  offset=(ssize_t) ((int) ReadPropertyLong(endian,exif+4));
+  if ((size_t) offset >= length)
+    return(MagickFalse);
+  /*
+    Set the pointer to the first IFD and follow it were it leads.
+  */
+  status=MagickFalse;
+  directory=exif+offset;
+  level=0;
+  entry=0;
+  tag_offset=0;
+  do
+  {
+    /*
+      If there is anything on the stack then pop it off.
+    */
+    if (level > 0)
+      {
+        level--;
+        directory=directory_stack[level].directory;
+        entry=directory_stack[level].entry;
+        tag_offset=directory_stack[level].offset;
+      }
+    /*
+      Determine how many entries there are in the current IFD.
+    */
+    number_entries=ReadPropertyShort(endian,directory);
+    for ( ; entry < number_entries; entry++)
+    {
+      register unsigned char
+        *p,
+        *q;
+
+      size_t
+        format,
+        number_bytes;
+
+      ssize_t
+        components;
+
+      q=(unsigned char *) (directory+2+(12*entry));
+      tag_value=(ssize_t) (ReadPropertyShort(endian,q)+tag_offset);
+      format=(size_t) ReadPropertyShort(endian,q+2);
+      if (format >= (sizeof(tag_bytes)/sizeof(*tag_bytes)))
+        break;
+      components=(ssize_t) ((int) ReadPropertyLong(endian,q+4));
+      number_bytes=(size_t) components*tag_bytes[format];
+      if (number_bytes <= 4)
+        p=q+8;
+      else
+        {
+          ssize_t
+            offset;
+
+          /*
+            The directory entry contains an offset.
+          */
+          offset=(ssize_t) ((int) ReadPropertyLong(endian,q+8));
+          if ((size_t) (offset+number_bytes) > length)
+            continue;
+          p=(unsigned char *) (exif+offset);
+        }
+      if ((all != 0) || (tag == (size_t) tag_value))
+        {
+          char
+            buffer[MaxTextExtent],
+            *value;
+
+          switch (format)
+          {
+            case EXIF_FMT_BYTE:
+            case EXIF_FMT_UNDEFINED:
+            {
+              EXIFMultipleValues(1,"%.20g",(double)
+                (*(unsigned char *) p1));
+              break;
+            }
+            case EXIF_FMT_SBYTE:
+            {
+              EXIFMultipleValues(1,"%.20g",(double) (*(signed char *) p1));
+              break;
+            }
+            case EXIF_FMT_SSHORT:
+            {
+              EXIFMultipleValues(2,"%hd",ReadPropertyShort(endian,p1));
+              break;
+            }
+            case EXIF_FMT_USHORT:
+            {
+              EXIFMultipleValues(2,"%hu",ReadPropertyShort(endian,p1));
+              break;
+            }
+            case EXIF_FMT_ULONG:
+            {
+              EXIFMultipleValues(4,"%.20g",(double)
+                ReadPropertyLong(endian,p1));
+              break;
+            }
+            case EXIF_FMT_SLONG:
+            {
+              EXIFMultipleValues(4,"%.20g",(double)
+                ReadPropertyLong(endian,p1));
+              break;
+            }
+            case EXIF_FMT_URATIONAL:
+            {
+              EXIFMultipleFractions(8,"%.20g/%.20g",(double)
+                ReadPropertyLong(endian,p1),(double)
+                ReadPropertyLong(endian,p1+4));
+              break;
+            }
+            case EXIF_FMT_SRATIONAL:
+            {
+              EXIFMultipleFractions(8,"%.20g/%.20g",(double)
+                ReadPropertyLong(endian,p1),(double)
+                ReadPropertyLong(endian,p1+4));
+              break;
+            }
+            case EXIF_FMT_SINGLE:
+            {
+              EXIFMultipleValues(4,"%f",(double) *(float *) p1);
+              break;
+            }
+            case EXIF_FMT_DOUBLE:
+            {
+              EXIFMultipleValues(8,"%f",*(double *) p1);
+              break;
+            }
+            default:
+            case EXIF_FMT_STRING:
+            {
+              value=(char *) NULL;
+              if (~(1UL*number_bytes) >= 1)
+                value=(char *) AcquireQuantumMemory((size_t) number_bytes+1UL,
+                  sizeof(*value));
+              if (value != (char *) NULL)
+                {
+                  register ssize_t
+                    i;
+
+                  for (i=0; i < (ssize_t) number_bytes; i++)
+                  {
+                    value[i]='.';
+                    if ((isprint((int) p[i]) != 0) || (p[i] == '\0'))
+                      value[i]=(char) p[i];
+                  }
+                  value[i]='\0';
+                }
+              break;
+            }
+          }
+          if (value != (char *) NULL)
+            {
+              char
+                key[MaxTextExtent];
+
+              register const char
+                *p;
+
+              (void) CopyMagickString(key,property,MaxTextExtent);
+              switch (all)
+              {
+                case 1:
+                {
+                  const char
+                    *description;
+
+                  register ssize_t
+                    i;
+
+                  description="unknown";
+                  for (i=0; ; i++)
+                  {
+                    if (EXIFTag[i].tag == 0)
+                      break;
+                    if ((ssize_t) EXIFTag[i].tag == tag_value)
+                      {
+                        description=EXIFTag[i].description;
+                        break;
+                      }
+                  }
+                  (void) FormatLocaleString(key,MaxTextExtent,"%s",
+                    description);
+                  break;
+                }
+                case 2:
+                {
+                  if (tag_value < 0x10000)
+                    (void) FormatLocaleString(key,MaxTextExtent,"#%04lx",
+                      (unsigned long) tag_value);
+                  else
+                    if (tag_value < 0x20000)
+                      (void) FormatLocaleString(key,MaxTextExtent,"@%04lx",
+                        (unsigned long) (tag_value & 0xffff));
+                    else
+                      (void) FormatLocaleString(key,MaxTextExtent,"unknown");
+                  break;
+                }
+              }
+              p=(const char *) NULL;
+              if (image->properties != (void *) NULL)
+                p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                  image->properties,key);
+              if (p == (const char *) NULL)
+                (void) SetImageProperty((Image *) image,key,value);
+              value=DestroyString(value);
+              status=MagickTrue;
+            }
+        }
+        if ((tag_value == TAG_EXIF_OFFSET) ||
+            (tag_value == TAG_INTEROP_OFFSET) ||
+            (tag_value == TAG_GPS_OFFSET))
+          {
+            size_t
+              offset;
+
+            offset=(size_t) ReadPropertyLong(endian,p);
+            if ((offset < length) && (level < (MaxDirectoryStack-2)))
+              {
+                size_t
+                  tag_offset1;
+
+                tag_offset1=(tag_value == TAG_GPS_OFFSET) ? 0x10000UL : 0UL;
+                directory_stack[level].directory=directory;
+                entry++;
+                directory_stack[level].entry=entry;
+                directory_stack[level].offset=tag_offset;
+                level++;
+                directory_stack[level].directory=exif+offset;
+                directory_stack[level].offset=tag_offset1;
+                directory_stack[level].entry=0;
+                level++;
+                if ((directory+2+(12*number_entries)) > (exif+length))
+                  break;
+                offset=(size_t) ReadPropertyLong(endian,directory+2+(12*
+                  number_entries));
+                if ((offset != 0) && (offset < length) &&
+                    (level < (MaxDirectoryStack-2)))
+                  {
+                    directory_stack[level].directory=exif+offset;
+                    directory_stack[level].entry=0;
+                    directory_stack[level].offset=tag_offset1;
+                    level++;
+                  }
+              }
+            break;
+          }
+    }
+  } while (level > 0);
+  return(status);
+}
+
+static MagickBooleanType GetXMPProperty(const Image *image,
+  const char *property)
+{
+  char
+    *xmp_profile;
+
+  const StringInfo
+    *profile;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  register const char
+    *p;
+
+  XMLTreeInfo
+    *child,
+    *description,
+    *node,
+    *rdf,
+    *xmp;
+
+  profile=GetImageProfile(image,"xmp");
+  if (profile == (StringInfo *) NULL)
+    return(MagickFalse);
+  if ((property == (const char *) NULL) || (*property == '\0'))
+    return(MagickFalse);
+  xmp_profile=StringInfoToString(profile);
+  if (xmp_profile == (char *) NULL)
+    return(MagickFalse);
+  for (p=xmp_profile; *p != '\0'; p++)
+    if ((*p == '<') && (*(p+1) == 'x'))
+      break;
+  exception=AcquireExceptionInfo();
+  xmp=NewXMLTree((char *) p,exception);
+  xmp_profile=DestroyString(xmp_profile);
+  exception=DestroyExceptionInfo(exception);
+  if (xmp == (XMLTreeInfo *) NULL)
+    return(MagickFalse);
+  status=MagickFalse;
+  rdf=GetXMLTreeChild(xmp,"rdf:RDF");
+  if (rdf != (XMLTreeInfo *) NULL)
+    {
+      if (image->properties == (void *) NULL)
+        ((Image *) image)->properties=NewSplayTree(CompareSplayTreeString,
+          RelinquishMagickMemory,RelinquishMagickMemory);
+      description=GetXMLTreeChild(rdf,"rdf:Description");
+      while (description != (XMLTreeInfo *) NULL)
+      {
+        node=GetXMLTreeChild(description,(const char *) NULL);
+        while (node != (XMLTreeInfo *) NULL)
+        {
+          child=GetXMLTreeChild(node,(const char *) NULL);
+          if (child == (XMLTreeInfo *) NULL)
+            (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
+              ConstantString(GetXMLTreeTag(node)),
+              ConstantString(GetXMLTreeContent(node)));
+          while (child != (XMLTreeInfo *) NULL)
+          {
+            if (LocaleCompare(GetXMLTreeTag(child),"rdf:Seq") != 0)
+              (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
+                ConstantString(GetXMLTreeTag(child)),
+                ConstantString(GetXMLTreeContent(child)));
+            child=GetXMLTreeSibling(child);
+          }
+          node=GetXMLTreeSibling(node);
+        }
+        description=GetNextXMLTreeTag(description);
+      }
+    }
+  xmp=DestroyXMLTree(xmp);
+  return(status);
+}
+
+static char *TracePSClippath(const unsigned char *blob,size_t length,
+  const size_t magick_unused(columns),
+  const size_t magick_unused(rows))
+{
+  char
+    *path,
+    *message;
+
+  MagickBooleanType
+    in_subpath;
+
+  PointInfo
+    first[3],
+    last[3],
+    point[3];
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    knot_count,
+    selector,
+    y;
+
+  path=AcquireString((char *) NULL);
+  if (path == (char *) NULL)
+    return((char *) NULL);
+  message=AcquireString((char *) NULL);
+  (void) FormatLocaleString(message,MaxTextExtent,"/ClipImage\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"{\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"  /c {curveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"  /l {lineto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"  /m {moveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "  /v {currentpoint 6 2 roll curveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "  /y {2 copy curveto} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "  /z {closepath} bind def\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"  newpath\n");
+  (void) ConcatenateString(&path,message);
+  /*
+    The clipping path format is defined in "Adobe Photoshop File
+    Formats Specification" version 6.0 downloadable from adobe.com.
+  */
+  (void) ResetMagickMemory(point,0,sizeof(point));
+  (void) ResetMagickMemory(first,0,sizeof(first));
+  (void) ResetMagickMemory(last,0,sizeof(last));
+  knot_count=0;
+  in_subpath=MagickFalse;
+  while (length > 0)
+  {
+    selector=(ssize_t) ReadPropertyMSBShort(&blob,&length);
+    switch (selector)
+    {
+      case 0:
+      case 3:
+      {
+        if (knot_count != 0)
+          {
+            blob+=24;
+            length-=24;
+            break;
+          }
+        /*
+          Expected subpath length record.
+        */
+        knot_count=(ssize_t) ReadPropertyMSBShort(&blob,&length);
+        blob+=22;
+        length-=22;
+        break;
+      }
+      case 1:
+      case 2:
+      case 4:
+      case 5:
+      {
+        if (knot_count == 0)
+          {
+            /*
+              Unexpected subpath knot
+            */
+            blob+=24;
+            length-=24;
+            break;
+          }
+        /*
+          Add sub-path knot
+        */
+        for (i=0; i < 3; i++)
+        {
+          size_t
+            xx,
+            yy;
+
+          yy=ReadPropertyMSBLong(&blob,&length);
+          xx=ReadPropertyMSBLong(&blob,&length);
+          x=(ssize_t) xx;
+          if (xx > 2147483647)
+            x=(ssize_t) xx-4294967295U-1;
+          y=(ssize_t) yy;
+          if (yy > 2147483647)
+            y=(ssize_t) yy-4294967295U-1;
+          point[i].x=(double) x/4096/4096;
+          point[i].y=1.0-(double) y/4096/4096;
+        }
+        if (in_subpath == MagickFalse)
+          {
+            (void) FormatLocaleString(message,MaxTextExtent,"  %g %g m\n",
+              point[1].x,point[1].y);
+            for (i=0; i < 3; i++)
+            {
+              first[i]=point[i];
+              last[i]=point[i];
+            }
+          }
+        else
+          {
+            /*
+              Handle special cases when Bezier curves are used to describe
+              corners and straight lines.
+            */
+            if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
+                (point[0].x == point[1].x) && (point[0].y == point[1].y))
+              (void) FormatLocaleString(message,MaxTextExtent,
+                "  %g %g l\n",point[1].x,point[1].y);
+            else
+              if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
+                (void) FormatLocaleString(message,MaxTextExtent,
+                  "  %g %g %g %g v\n",point[0].x,point[0].y,
+                  point[1].x,point[1].y);
+              else
+                if ((point[0].x == point[1].x) && (point[0].y == point[1].y))
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "  %g %g %g %g y\n",last[2].x,last[2].y,
+                    point[1].x,point[1].y);
+                else
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "  %g %g %g %g %g %g c\n",last[2].x,
+                    last[2].y,point[0].x,point[0].y,point[1].x,point[1].y);
+            for (i=0; i < 3; i++)
+              last[i]=point[i];
+          }
+        (void) ConcatenateString(&path,message);
+        in_subpath=MagickTrue;
+        knot_count--;
+        /*
+          Close the subpath if there are no more knots.
+        */
+        if (knot_count == 0)
+          {
+            /*
+              Same special handling as above except we compare to the
+              first point in the path and close the path.
+            */
+            if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
+                (first[0].x == first[1].x) && (first[0].y == first[1].y))
+              (void) FormatLocaleString(message,MaxTextExtent,
+                "  %g %g l z\n",first[1].x,first[1].y);
+            else
+              if ((last[1].x == last[2].x) && (last[1].y == last[2].y))
+                (void) FormatLocaleString(message,MaxTextExtent,
+                  "  %g %g %g %g v z\n",first[0].x,first[0].y,
+                  first[1].x,first[1].y);
+              else
+                if ((first[0].x == first[1].x) && (first[0].y == first[1].y))
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "  %g %g %g %g y z\n",last[2].x,last[2].y,
+                    first[1].x,first[1].y);
+                else
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "  %g %g %g %g %g %g c z\n",last[2].x,
+                    last[2].y,first[0].x,first[0].y,first[1].x,first[1].y);
+            (void) ConcatenateString(&path,message);
+            in_subpath=MagickFalse;
+          }
+        break;
+      }
+      case 6:
+      case 7:
+      case 8:
+      default:
+      {
+        blob+=24;
+        length-=24;
+        break;
+      }
+    }
+  }
+  /*
+    Returns an empty PS path if the path has no knots.
+  */
+  (void) FormatLocaleString(message,MaxTextExtent,"  eoclip\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"} bind def");
+  (void) ConcatenateString(&path,message);
+  message=DestroyString(message);
+  return(path);
+}
+
+static char *TraceSVGClippath(const unsigned char *blob,size_t length,
+  const size_t columns,const size_t rows)
+{
+  char
+    *path,
+    *message;
+
+  MagickBooleanType
+    in_subpath;
+
+  PointInfo
+    first[3],
+    last[3],
+    point[3];
+
+  register ssize_t
+    i;
+
+  ssize_t
+    knot_count,
+    selector,
+    x,
+    y;
+
+  path=AcquireString((char *) NULL);
+  if (path == (char *) NULL)
+    return((char *) NULL);
+  message=AcquireString((char *) NULL);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "<svg width=\"%.20g\" height=\"%.20g\">\n",(double) columns,(double) rows);
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"<g>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "<path style=\"fill:#00000000;stroke:#00000000;");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,
+    "stroke-width:0;stroke-antialiasing:false\" d=\"\n");
+  (void) ConcatenateString(&path,message);
+  (void) ResetMagickMemory(point,0,sizeof(point));
+  (void) ResetMagickMemory(first,0,sizeof(first));
+  (void) ResetMagickMemory(last,0,sizeof(last));
+  knot_count=0;
+  in_subpath=MagickFalse;
+  while (length != 0)
+  {
+    selector=(ssize_t) ReadPropertyMSBShort(&blob,&length);
+    switch (selector)
+    {
+      case 0:
+      case 3:
+      {
+        if (knot_count != 0)
+          {
+            blob+=24;
+            length-=24;
+            break;
+          }
+        /*
+          Expected subpath length record.
+        */
+        knot_count=(ssize_t) ReadPropertyMSBShort(&blob,&length);
+        blob+=22;
+        length-=22;
+        break;
+      }
+      case 1:
+      case 2:
+      case 4:
+      case 5:
+      {
+        if (knot_count == 0)
+          {
+            /*
+              Unexpected subpath knot.
+            */
+            blob+=24;
+            length-=24;
+            break;
+          }
+        /*
+          Add sub-path knot
+        */
+        for (i=0; i < 3; i++)
+        {
+          size_t
+            xx,
+            yy;
+
+          yy=ReadPropertyMSBLong(&blob,&length);
+          xx=ReadPropertyMSBLong(&blob,&length);
+          x=(ssize_t) xx;
+          if (xx > 2147483647)
+            x=(ssize_t) xx-4294967295U-1;
+          y=(ssize_t) yy;
+          if (yy > 2147483647)
+            y=(ssize_t) yy-4294967295U-1;
+          point[i].x=(double) x*columns/4096/4096;
+          point[i].y=(double) y*rows/4096/4096;
+        }
+        if (in_subpath == MagickFalse)
+          {
+            (void) FormatLocaleString(message,MaxTextExtent,"M %g,%g\n",
+              point[1].x,point[1].y);
+            for (i=0; i < 3; i++)
+            {
+              first[i]=point[i];
+              last[i]=point[i];
+            }
+          }
+        else
+          {
+            if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
+                (point[0].x == point[1].x) && (point[0].y == point[1].y))
+              (void) FormatLocaleString(message,MaxTextExtent,"L %g,%g\n",
+                point[1].x,point[1].y);
+            else
+              (void) FormatLocaleString(message,MaxTextExtent,
+                "C %g,%g %g,%g %g,%g\n",last[2].x,last[2].y,
+                point[0].x,point[0].y,point[1].x,point[1].y);
+            for (i=0; i < 3; i++)
+              last[i]=point[i];
+          }
+        (void) ConcatenateString(&path,message);
+        in_subpath=MagickTrue;
+        knot_count--;
+        /*
+          Close the subpath if there are no more knots.
+        */
+        if (knot_count == 0)
+          {
+            if ((last[1].x == last[2].x) && (last[1].y == last[2].y) &&
+                (first[0].x == first[1].x) && (first[0].y == first[1].y))
+              (void) FormatLocaleString(message,MaxTextExtent,
+                "L %g,%g Z\n",first[1].x,first[1].y);
+            else
+              {
+                (void) FormatLocaleString(message,MaxTextExtent,
+                  "C %g,%g %g,%g %g,%g Z\n",last[2].x,
+                  last[2].y,first[0].x,first[0].y,first[1].x,first[1].y);
+                (void) ConcatenateString(&path,message);
+              }
+            in_subpath=MagickFalse;
+          }
+        break;
+      }
+      case 6:
+      case 7:
+      case 8:
+      default:
+      {
+        blob+=24;
+        length-=24;
+        break;
+      }
+    }
+  }
+  /*
+    Return an empty SVG image if the path does not have knots.
+  */
+  (void) FormatLocaleString(message,MaxTextExtent,"\"/>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"</g>\n");
+  (void) ConcatenateString(&path,message);
+  (void) FormatLocaleString(message,MaxTextExtent,"</svg>\n");
+  (void) ConcatenateString(&path,message);
+  message=DestroyString(message);
+  return(path);
+}
+
+MagickExport const char *GetImageProperty(const Image *image,
+  const char *property)
+{
+  ExceptionInfo
+    *exception;
+
+  FxInfo
+    *fx_info;
+
+  MagickRealType
+    alpha;
+
+  MagickStatusType
+    status;
+
+  register const char
+    *p;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  p=(const char *) NULL;
+  if (image->properties != (void *) NULL)
+    {
+      if (property == (const char *) NULL)
+        {
+          ResetSplayTreeIterator((SplayTreeInfo *) image->properties);
+          p=(const char *) GetNextValueInSplayTree((SplayTreeInfo *)
+            image->properties);
+          return(p);
+        }
+      if (LocaleNCompare("fx:",property,3) != 0)
+        {
+          p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+            image->properties,property);
+          if (p != (const char *) NULL)
+            return(p);
+        }
+    }
+  if ((property == (const char *) NULL) ||
+      (strchr(property,':') == (char *) NULL))
+    return(p);
+  exception=(&((Image *) image)->exception);
+  switch (*property)
+  {
+    case '8':
+    {
+      if (LocaleNCompare("8bim:",property,5) == 0)
+        {
+          if ((Get8BIMProperty(image,property) != MagickFalse) &&
+              (image->properties != (void *) NULL))
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      break;
+    }
+    case 'E':
+    case 'e':
+    {
+      if (LocaleNCompare("exif:",property,5) == 0)
+        {
+          if ((GetEXIFProperty(image,property) != MagickFalse) &&
+              (image->properties != (void *) NULL))
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      break;
+    }
+    case 'F':
+    case 'f':
+    {
+      if (LocaleNCompare("fx:",property,3) == 0)
+        {
+          fx_info=AcquireFxInfo(image,property+3);
+          status=FxEvaluateChannelExpression(fx_info,DefaultChannels,0,0,&alpha,
+            exception);
+          fx_info=DestroyFxInfo(fx_info);
+          if (status != MagickFalse)
+            {
+              char
+                value[MaxTextExtent];
+
+              (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+                GetMagickPrecision(),(double) alpha);
+              (void) SetImageProperty((Image *) image,property,value);
+            }
+          if (image->properties != (void *) NULL)
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      break;
+    }
+    case 'I':
+    case 'i':
+    {
+      if (LocaleNCompare("iptc:",property,5) == 0)
+        {
+          if ((GetIPTCProperty(image,property) != MagickFalse) &&
+              (image->properties != (void *) NULL))
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      break;
+    }
+    case 'P':
+    case 'p':
+    {
+      if (LocaleNCompare("pixel:",property,6) == 0)
+        {
+          PixelInfo
+            pixel;
+
+          GetPixelInfo(image,&pixel);
+          fx_info=AcquireFxInfo(image,property+6);
+          status=FxEvaluateChannelExpression(fx_info,RedChannel,0,0,&alpha,
+            exception);
+          pixel.red=(MagickRealType) QuantumRange*alpha;
+          status|=FxEvaluateChannelExpression(fx_info,GreenChannel,0,0,&alpha,
+            exception);
+          pixel.green=(MagickRealType) QuantumRange*alpha;
+          status|=FxEvaluateChannelExpression(fx_info,BlueChannel,0,0,&alpha,
+            exception);
+          pixel.blue=(MagickRealType) QuantumRange*alpha;
+          if (image->colorspace == CMYKColorspace)
+            {
+              status|=FxEvaluateChannelExpression(fx_info,BlackChannel,0,0,
+                &alpha,exception);
+              pixel.black=(MagickRealType) QuantumRange*alpha;
+            }
+          status|=FxEvaluateChannelExpression(fx_info,OpacityChannel,0,0,&alpha,
+            exception);
+          pixel.alpha=(MagickRealType) QuantumRange*(1.0-alpha);
+          fx_info=DestroyFxInfo(fx_info);
+          if (status != MagickFalse)
+            {
+              char
+                name[MaxTextExtent];
+
+              (void) QueryMagickColorname(image,&pixel,SVGCompliance,name,
+                exception);
+              (void) SetImageProperty((Image *) image,property,name);
+              return(GetImageProperty(image,property));
+            }
+        }
+      break;
+    }
+    case 'X':
+    case 'x':
+    {
+      if (LocaleNCompare("xmp:",property,4) == 0)
+        {
+          if ((GetXMPProperty(image,property) != MagickFalse) &&
+              (image->properties != (void *) NULL))
+            {
+              p=(const char *) GetValueFromSplayTree((SplayTreeInfo *)
+                image->properties,property);
+              return(p);
+            }
+        }
+      break;
+    }
+    default:
+      break;
+  }
+  return(p);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k P r o p e r t y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickProperty() gets a value associated with an image property.
+%
+%  The format of the GetMagickProperty method is:
+%
+%      const char *GetMagickProperty(const ImageInfo *image_info,
+%        Image *image,const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+%    o key: the key.
+%
+*/
+MagickExport const char *GetMagickProperty(const ImageInfo *image_info,
+  Image *image,const char *property)
+{
+  char
+    value[MaxTextExtent],
+    filename[MaxTextExtent];
+
+  *value='\0';
+  switch (*property)
+  {
+    case 'b':
+    {
+      if (LocaleNCompare("base",property,4) == 0)
+        {
+          GetPathComponent(image->magick_filename,BasePath,filename);
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'c':
+    {
+      if (LocaleNCompare("channels",property,8) == 0)
+        {
+          /*
+            Image channels.
+          */
+          (void) FormatLocaleString(value,MaxTextExtent,"%s",
+            CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
+            image->colorspace));
+          LocaleLower(value);
+          if (image->matte != MagickFalse)
+            (void) ConcatenateMagickString(value,"a",MaxTextExtent);
+          break;
+        }
+      if (LocaleNCompare("colorspace",property,10) == 0)
+        {
+          ColorspaceType
+            colorspace;
+
+          /*
+            Image storage class and colorspace.
+          */
+          colorspace=image->colorspace;
+          if (IsImageGray(image,&image->exception) != MagickFalse)
+            colorspace=GRAYColorspace;
+          (void) FormatLocaleString(value,MaxTextExtent,"%s",
+            CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
+            colorspace));
+          break;
+        }
+      if (LocaleNCompare("copyright",property,9) == 0)
+        {
+          (void) CopyMagickString(value,GetMagickCopyright(),MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'd':
+    {
+      if (LocaleNCompare("depth",property,5) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+            image->depth);
+          break;
+        }
+      if (LocaleNCompare("directory",property,9) == 0)
+        {
+          GetPathComponent(image->magick_filename,HeadPath,filename);
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'e':
+    {
+      if (LocaleNCompare("extension",property,9) == 0)
+        {
+          GetPathComponent(image->magick_filename,ExtensionPath,filename);
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'g':
+    {
+      if (LocaleNCompare("group",property,5) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"0x%lx",
+            (unsigned long) image_info->group);
+          break;
+        }
+      break;
+    }
+    case 'h':
+    {
+      if (LocaleNCompare("height",property,6) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",
+            image->magick_rows != 0 ? (double) image->magick_rows : 256.0);
+          break;
+        }
+      break;
+    }
+    case 'i':
+    {
+      if (LocaleNCompare("input",property,5) == 0)
+        {
+          (void) CopyMagickString(value,image->filename,MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'k':
+    {
+      if (LocaleNCompare("kurtosis",property,8) == 0)
+        {
+          double
+            kurtosis,
+            skewness;
+
+          (void) GetImageChannelKurtosis(image,image_info->channel,&kurtosis,
+            &skewness,&image->exception);
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),kurtosis);
+          break;
+        }
+      break;
+    }
+    case 'm':
+    {
+      if (LocaleNCompare("magick",property,6) == 0)
+        {
+          (void) CopyMagickString(value,image->magick,MaxTextExtent);
+          break;
+        }
+      if (LocaleNCompare("max",property,3) == 0)
+        {
+          double
+            maximum,
+            minimum;
+
+          (void) GetImageChannelRange(image,image_info->channel,&minimum,
+            &maximum,&image->exception);
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),maximum);
+          break;
+        }
+      if (LocaleNCompare("mean",property,4) == 0)
+        {
+          double
+            mean,
+            standard_deviation;
+
+          (void) GetImageChannelMean(image,image_info->channel,&mean,
+            &standard_deviation,&image->exception);
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),mean);
+          break;
+        }
+      if (LocaleNCompare("min",property,3) == 0)
+        {
+          double
+            maximum,
+            minimum;
+
+          (void) GetImageChannelRange(image,image_info->channel,&minimum,
+            &maximum,&image->exception);
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),minimum);
+          break;
+        }
+      break;
+    }
+    case 'n':
+    {
+      if (LocaleNCompare("name",property,4) == 0)
+        {
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+     break;
+    }
+    case 'o':
+    {
+      if (LocaleNCompare("opaque",property,6) == 0)
+        {
+          MagickBooleanType
+            opaque;
+
+          opaque=IsImageOpaque(image,&image->exception);
+          (void) CopyMagickString(value,opaque == MagickFalse ? "false" :
+            "true",MaxTextExtent);
+          break;
+        }
+      if (LocaleNCompare("output",property,6) == 0)
+        {
+          (void) CopyMagickString(value,image_info->filename,MaxTextExtent);
+          break;
+        }
+     break;
+    }
+    case 'p':
+    {
+      if (LocaleNCompare("page",property,4) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+              GetImageIndexInList(image)+1);
+          break;
+        }
+      break;
+    }
+    case 's':
+    {
+      if (LocaleNCompare("size",property,4) == 0)
+        {
+          char
+            format[MaxTextExtent];
+
+          (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format);
+          (void) FormatLocaleString(value,MaxTextExtent,"%sB",format);
+          break;
+        }
+      if (LocaleNCompare("scenes",property,6) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+            GetImageListLength(image));
+          break;
+        }
+      if (LocaleNCompare("scene",property,5) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+            image->scene);
+          if (image_info->number_scenes != 0)
+            (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+              image_info->scene);
+          break;
+        }
+      if (LocaleNCompare("skewness",property,8) == 0)
+        {
+          double
+            kurtosis,
+            skewness;
+
+          (void) GetImageChannelKurtosis(image,image_info->channel,&kurtosis,
+            &skewness,&image->exception);
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),skewness);
+          break;
+        }
+      if ((LocaleNCompare("standard-deviation",property,18) == 0) ||
+          (LocaleNCompare("standard_deviation",property,18) == 0))
+        {
+          double
+            mean,
+            standard_deviation;
+
+          (void) GetImageChannelMean(image,image_info->channel,&mean,
+            &standard_deviation,&image->exception);
+          (void) FormatLocaleString(value,MaxTextExtent,"%.*g",
+            GetMagickPrecision(),standard_deviation);
+          break;
+        }
+       break;
+    }
+    case 'u':
+    {
+      if (LocaleNCompare("unique",property,6) == 0)
+        {
+          (void) CopyMagickString(filename,image_info->unique,MaxTextExtent);
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'v':
+    {
+      if (LocaleNCompare("version",property,7) == 0)
+        {
+          (void) CopyMagickString(value,GetMagickVersion((size_t *) NULL),
+            MaxTextExtent);
+          break;
+        }
+      break;
+    }
+    case 'w':
+    {
+      if (LocaleNCompare("width",property,5) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+            (image->magick_columns != 0 ? image->magick_columns : 256));
+          break;
+        }
+      break;
+    }
+    case 'x':
+    {
+      if (LocaleNCompare("xresolution",property,11) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%g",
+            image->x_resolution);
+          break;
+        }
+      break;
+    }
+    case 'y':
+    {
+      if (LocaleNCompare("yresolution",property,11) == 0)
+        {
+          (void) FormatLocaleString(value,MaxTextExtent,"%g",
+            image->y_resolution);
+          break;
+        }
+      break;
+    }
+    case 'z':
+    {
+      if (LocaleNCompare("zero",property,4) == 0)
+        {
+          (void) CopyMagickString(filename,image_info->zero,MaxTextExtent);
+          (void) CopyMagickString(value,filename,MaxTextExtent);
+          break;
+        }
+      break;
+    }
+  }
+  if (*value != '\0')
+   {
+     if (image->properties == (void *) NULL)
+       image->properties=NewSplayTree(CompareSplayTreeString,
+         RelinquishMagickMemory,RelinquishMagickMemory);
+     (void) AddValueToSplayTree((SplayTreeInfo *) image->properties,
+       ConstantString(property),ConstantString(value));
+   }
+  return(GetImageProperty(image,property));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e P r o p e r t y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageProperty() gets the next image property value.
+%
+%  The format of the GetNextImageProperty method is:
+%
+%      char *GetNextImageProperty(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport char *GetNextImageProperty(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->properties == (void *) NULL)
+    return((char *) NULL);
+  return((char *) GetNextKeyInSplayTree((SplayTreeInfo *) image->properties));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p r e t I m a g e P r o p e r t i e s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpretImageProperties() replaces any embedded formatting characters with
+%  the appropriate image property and returns the interpretted text.
+%
+%  The format of the InterpretImageProperties method is:
+%
+%      char *InterpretImageProperties(const ImageInfo *image_info,Image *image,
+%        const char *embed_text)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+%    o embed_text: the address of a character string containing the embedded
+%      formatting characters.
+%
+*/
+MagickExport char *InterpretImageProperties(const ImageInfo *image_info,
+  Image *image,const char *embed_text)
+{
+  char
+    filename[MaxTextExtent],
+    *interpret_text,
+    *text;
+
+  const char
+    *value;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    extent,
+    length;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((embed_text == (const char *) NULL) || (*embed_text == '\0'))
+    return((char *) NULL);
+  text=(char *) embed_text;
+  if ((*text == '@') && ((*(text+1) == '-') ||
+      (IsPathAccessible(text+1) != MagickFalse)))
+    return(FileToString(embed_text+1,~0,&image->exception));
+  /*
+    Translate any embedded format characters.
+  */
+  interpret_text=AcquireString(text);
+  extent=MaxTextExtent;
+  p=text;
+  for (q=interpret_text; *p != '\0'; p++)
+  {
+    *q='\0';
+    if ((size_t) (q-interpret_text+MaxTextExtent) >= extent)
+      {
+        extent+=MaxTextExtent;
+        interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+
+          MaxTextExtent+1,sizeof(*interpret_text));
+        if (interpret_text == (char *) NULL)
+          break;
+        q=interpret_text+strlen(interpret_text);
+      }
+    /*
+      Process formatting characters in text.
+    */
+    if ((*p == '\\') && (*(p+1) == 'r'))
+      {
+        *q++='\r';
+        p++;
+        continue;
+      }
+    if ((*p == '\\') && (*(p+1) == 'n'))
+      {
+        *q++='\n';
+        p++;
+        continue;
+      }
+    if (*p == '\\')
+      {
+        p++;
+        *q++=(*p);
+        continue;
+      }
+    if (*p != '%')
+      {
+        *q++=(*p);
+        continue;
+      }
+    p++;
+    switch (*p)
+    {
+      case 'b':
+      {
+        char
+          format[MaxTextExtent];
+
+        /*
+          File size.
+        */
+        (void) FormatLocaleString(format,MaxTextExtent,"%.20g",(double)
+          ((MagickOffsetType) image->extent));
+        if (image->extent != (MagickSizeType) ((size_t) image->extent))
+          (void) FormatMagickSize(image->extent,MagickFalse,format);
+        q+=ConcatenateMagickString(q,format,extent);
+        q+=ConcatenateMagickString(q,"B",extent);
+        break;
+      }
+      case 'c':
+      {
+        /*
+          Image comment.
+        */
+        value=GetImageProperty(image,"comment");
+        if (value == (const char *) NULL)
+          break;
+        length=strlen(value);
+        if ((size_t) (q-interpret_text+length+1) >= extent)
+          {
+            extent+=length;
+            interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+
+              MaxTextExtent,sizeof(*interpret_text));
+            if (interpret_text == (char *) NULL)
+              break;
+            q=interpret_text+strlen(interpret_text);
+          }
+        (void) CopyMagickString(q,value,extent);
+        q+=length;
+        break;
+      }
+      case 'd':
+      case 'e':
+      case 'f':
+      case 't':
+      {
+        /*
+          Label segment is the base of the filename.
+        */
+        if (*image->magick_filename == '\0')
+          break;
+        switch (*p)
+        {
+          case 'd':
+          {
+            /*
+              Directory.
+            */
+            GetPathComponent(image->magick_filename,HeadPath,filename);
+            q+=CopyMagickString(q,filename,extent);
+            break;
+          }
+          case 'e':
+          {
+            /*
+              Filename extension.
+            */
+            GetPathComponent(image->magick_filename,ExtensionPath,filename);
+            q+=CopyMagickString(q,filename,extent);
+            break;
+          }
+          case 'f':
+          {
+            /*
+              Filename.
+            */
+            GetPathComponent(image->magick_filename,TailPath,filename);
+            q+=CopyMagickString(q,filename,extent);
+            break;
+          }
+          case 't':
+          {
+            /*
+              Base filename.
+            */
+            GetPathComponent(image->magick_filename,BasePath,filename);
+            q+=CopyMagickString(q,filename,extent);
+            break;
+          }
+        }
+        break;
+      }
+      case 'g':
+      {
+        /*
+          Image geometry.
+        */
+        q+=FormatLocaleString(q,extent,"%.20gx%.20g%+.20g%+.20g",(double)
+          image->page.width,(double) image->page.height,(double) image->page.x,
+          (double) image->page.y);
+        break;
+      }
+      case 'h':
+      {
+        /*
+          Image height.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double) (image->rows != 0 ?
+          image->rows : image->magick_rows));
+        break;
+      }
+      case 'i':
+      {
+        /*
+          Image filename.
+        */
+        q+=CopyMagickString(q,image->filename,extent);
+        break;
+      }
+      case 'k':
+      {
+        /*
+          Number of unique colors.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double) GetNumberColors(image,
+          (FILE *) NULL,&image->exception));
+        break;
+      }
+      case 'l':
+      {
+        /*
+          Image label.
+        */
+        value=GetImageProperty(image,"label");
+        if (value == (const char *) NULL)
+          break;
+        length=strlen(value);
+        if ((size_t) (q-interpret_text+length+1) >= extent)
+          {
+            extent+=length;
+            interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+
+              MaxTextExtent,sizeof(*interpret_text));
+            if (interpret_text == (char *) NULL)
+              break;
+            q=interpret_text+strlen(interpret_text);
+          }
+        q+=CopyMagickString(q,value,extent);
+        break;
+      }
+      case 'm':
+      {
+        /*
+          Image format.
+        */
+        q+=CopyMagickString(q,image->magick,extent);
+        break;
+      }
+      case 'M':
+      {
+        /*
+          Image magick filename.
+        */
+        q+=CopyMagickString(q,image->magick_filename,extent);
+        break;
+      }
+      case 'n':
+      {
+        /*
+          Number of images in the list.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double)
+             GetImageListLength(image));
+        break;
+      }
+      case 'o':
+      {
+        /*
+          Image output filename.
+        */
+        q+=CopyMagickString(q,image_info->filename,extent);
+        break;
+      }
+      case 'p':
+      {
+        /*
+          Image index in list.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double)
+            GetImageIndexInList(image));
+        break;
+      }
+      case 'q':
+      {
+        /*
+          Image depth.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double)
+          MAGICKCORE_QUANTUM_DEPTH);
+        break;
+      }
+      case 'r':
+      {
+        ColorspaceType
+          colorspace;
+
+        /*
+          Image storage class and colorspace.
+        */
+        colorspace=image->colorspace;
+        if (IsImageGray(image,&image->exception) != MagickFalse)
+          colorspace=GRAYColorspace;
+        q+=FormatLocaleString(q,extent,"%s%s%s",CommandOptionToMnemonic(
+          MagickClassOptions,(ssize_t) image->storage_class),
+          CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t) colorspace),
+          image->matte != MagickFalse ? "Matte" : "");
+        break;
+      }
+      case 's':
+      {
+        /*
+          Image scene number.
+        */
+        if (image_info->number_scenes == 0)
+          q+=FormatLocaleString(q,extent,"%.20g",(double) image->scene);
+        else
+          q+=FormatLocaleString(q,extent,"%.20g",(double) image_info->scene);
+        break;
+      }
+      case 'u':
+      {
+        /*
+          Unique filename.
+        */
+        (void) CopyMagickString(filename,image_info->unique,extent);
+        q+=CopyMagickString(q,filename,extent);
+        break;
+      }
+      case 'w':
+      {
+        /*
+          Image width.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double) (image->columns != 0 ?
+          image->columns : image->magick_columns));
+        break;
+      }
+      case 'x':
+      {
+        /*
+          Image horizontal resolution.
+        */
+        q+=FormatLocaleString(q,extent,"%g %s",image->x_resolution,
+          CommandOptionToMnemonic(MagickResolutionOptions,(ssize_t)
+            image->units));
+        break;
+      }
+      case 'y':
+      {
+        /*
+          Image vertical resolution.
+        */
+        q+=FormatLocaleString(q,extent,"%g %s",image->y_resolution,
+          CommandOptionToMnemonic(MagickResolutionOptions,(ssize_t)
+          image->units));
+        break;
+      }
+      case 'z':
+      {
+        /*
+          Image depth.
+        */
+        q+=FormatLocaleString(q,extent,"%.20g",(double) image->depth);
+        break;
+      }
+      case 'A':
+      {
+        /*
+          Image alpha channel.
+        */
+        q+=FormatLocaleString(q,extent,"%s",CommandOptionToMnemonic(
+          MagickBooleanOptions,(ssize_t) image->matte));
+        break;
+      }
+      case 'C':
+      {
+        /*
+          Image compression method.
+        */
+        q+=FormatLocaleString(q,extent,"%s",CommandOptionToMnemonic(
+          MagickCompressOptions,(ssize_t) image->compression));
+        break;
+      }
+      case 'D':
+      {
+        /*
+          Image dispose method.
+        */
+        q+=FormatLocaleString(q,extent,"%s",CommandOptionToMnemonic(
+          MagickDisposeOptions,(ssize_t) image->dispose));
+        break;
+      }
+      case 'G':
+      {
+        q+=FormatLocaleString(q,extent,"%.20gx%.20g",(double)
+          image->magick_columns,(double) image->magick_rows);
+        break;
+      }
+      case 'H':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) image->page.height);
+        break;
+      }
+      case 'O':
+      {
+        q+=FormatLocaleString(q,extent,"%+ld%+ld",(long) image->page.x,(long)
+          image->page.y);
+        break;
+      }
+      case 'P':
+      {
+        q+=FormatLocaleString(q,extent,"%.20gx%.20g",(double) image->page.width,
+          (double) image->page.height);
+        break;
+      }
+      case 'Q':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) image->quality);
+        break;
+      }
+      case 'S':
+      {
+        /*
+          Image scenes.
+        */
+        if (image_info->number_scenes == 0)
+          q+=CopyMagickString(q,"2147483647",extent);
+        else
+          q+=FormatLocaleString(q,extent,"%.20g",(double) (image_info->scene+
+            image_info->number_scenes));
+        break;
+      }
+      case 'T':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) image->delay);
+        break;
+      }
+      case 'W':
+      {
+        q+=FormatLocaleString(q,extent,"%.20g",(double) image->page.width);
+        break;
+      }
+      case 'X':
+      {
+        q+=FormatLocaleString(q,extent,"%+.20g",(double) image->page.x);
+        break;
+      }
+      case 'Y':
+      {
+        q+=FormatLocaleString(q,extent,"%+.20g",(double) image->page.y);
+        break;
+      }
+      case 'Z':
+      {
+        /*
+          Unique filename.
+        */
+        (void) CopyMagickString(filename,image_info->zero,extent);
+        q+=CopyMagickString(q,filename,extent);
+        break;
+      }
+      case '[':
+      {
+        char
+          pattern[MaxTextExtent];
+
+        const char
+          *key,
+          *value;
+
+        ssize_t
+          depth;
+
+        /*
+          Image value.
+        */
+        if (strchr(p,']') == (char *) NULL)
+          break;
+        depth=1;
+        p++;
+        for (i=0; (i < (MaxTextExtent-1L)) && (*p != '\0'); i++)
+        {
+          if (*p == '[')
+            depth++;
+          if (*p == ']')
+            depth--;
+          if (depth <= 0)
+            break;
+          pattern[i]=(*p++);
+        }
+        pattern[i]='\0';
+        value=GetImageProperty(image,pattern);
+        if (value != (const char *) NULL)
+          {
+            length=strlen(value);
+            if ((size_t) (q-interpret_text+length+1) >= extent)
+              {
+                extent+=length;
+                interpret_text=(char *) ResizeQuantumMemory(interpret_text,
+                  extent+MaxTextExtent,sizeof(*interpret_text));
+                if (interpret_text == (char *) NULL)
+                  break;
+                q=interpret_text+strlen(interpret_text);
+              }
+            (void) CopyMagickString(q,value,extent);
+            q+=length;
+            break;
+          }
+        else
+          if (IsGlob(pattern) != MagickFalse)
+            {
+              /*
+                Iterate over image properties.
+              */
+              ResetImagePropertyIterator(image);
+              key=GetNextImageProperty(image);
+              while (key != (const char *) NULL)
+              {
+                if (GlobExpression(key,pattern,MagickTrue) != MagickFalse)
+                  {
+                    value=GetImageProperty(image,key);
+                    if (value != (const char *) NULL)
+                      {
+                        length=strlen(key)+strlen(value)+2;
+                        if ((size_t) (q-interpret_text+length+1) >= extent)
+                          {
+                            extent+=length;
+                            interpret_text=(char *) ResizeQuantumMemory(
+                              interpret_text,extent+MaxTextExtent,
+                              sizeof(*interpret_text));
+                            if (interpret_text == (char *) NULL)
+                              break;
+                            q=interpret_text+strlen(interpret_text);
+                          }
+                        q+=FormatLocaleString(q,extent,"%s=%s\n",key,value);
+                      }
+                  }
+                key=GetNextImageProperty(image);
+              }
+            }
+        value=GetMagickProperty(image_info,image,pattern);
+        if (value != (const char *) NULL)
+          {
+            length=strlen(value);
+            if ((size_t) (q-interpret_text+length+1) >= extent)
+              {
+                extent+=length;
+                interpret_text=(char *) ResizeQuantumMemory(interpret_text,
+                  extent+MaxTextExtent,sizeof(*interpret_text));
+                if (interpret_text == (char *) NULL)
+                  break;
+                q=interpret_text+strlen(interpret_text);
+              }
+            (void) CopyMagickString(q,value,extent);
+            q+=length;
+            break;
+          }
+        if (image_info == (ImageInfo *) NULL)
+          break;
+        value=GetImageOption(image_info,pattern);
+        if (value != (char *) NULL)
+          {
+            length=strlen(value);
+            if ((size_t) (q-interpret_text+length+1) >= extent)
+              {
+                extent+=length;
+                interpret_text=(char *) ResizeQuantumMemory(interpret_text,
+                  extent+MaxTextExtent,sizeof(*interpret_text));
+                if (interpret_text == (char *) NULL)
+                  break;
+                q=interpret_text+strlen(interpret_text);
+              }
+            (void) CopyMagickString(q,value,extent);
+            q+=length;
+            break;
+          }
+        break;
+      }
+      case '@':
+      {
+        RectangleInfo
+          page;
+
+        /*
+          Image bounding box.
+        */
+        page=GetImageBoundingBox(image,&image->exception);
+        q+=FormatLocaleString(q,MaxTextExtent,"%.20gx%.20g%+.20g%+.20g",
+          (double) page.width,(double) page.height,(double) page.x,(double)
+          page.y);
+        break;
+      }
+      case '#':
+      {
+        /*
+          Image signature.
+        */
+        (void) SignatureImage(image);
+        value=GetImageProperty(image,"signature");
+        if (value == (const char *) NULL)
+          break;
+        q+=CopyMagickString(q,value,extent);
+        break;
+      }
+      case '%':
+      {
+        *q++=(*p);
+        break;
+      }
+      default:
+      {
+        *q++='%';
+        *q++=(*p);
+        break;
+      }
+    }
+  }
+  *q='\0';
+  if (text != (const char *) embed_text)
+    text=DestroyString(text);
+  (void) SubstituteString(&interpret_text,"&lt;","<");
+  (void) SubstituteString(&interpret_text,"&gt;",">");
+  return(interpret_text);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e I m a g e P r o p e r t y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveImageProperty() removes a property from the image and returns its
+%  value.
+%
+%  The format of the RemoveImageProperty method is:
+%
+%      char *RemoveImageProperty(Image *image,const char *property)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o property: the image property.
+%
+*/
+MagickExport char *RemoveImageProperty(Image *image,
+  const char *property)
+{
+  char
+    *value;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->properties == (void *) NULL)
+    return((char *) NULL);
+  value=(char *) RemoveNodeFromSplayTree((SplayTreeInfo *) image->properties,
+    property);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e P r o p e r t y I t e r a t o r                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImagePropertyIterator() resets the image properties iterator.  Use it
+%  in conjunction with GetNextImageProperty() to iterate over all the values
+%  associated with an image property.
+%
+%  The format of the ResetImagePropertyIterator method is:
+%
+%      ResetImagePropertyIterator(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void ResetImagePropertyIterator(const Image *image)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->properties == (void *) NULL)
+    return;
+  ResetSplayTreeIterator((SplayTreeInfo *) image->properties);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e P r o p e r t y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageProperty() associates an value with an image property.
+%
+%  The format of the SetImageProperty method is:
+%
+%      MagickBooleanType SetImageProperty(Image *image,const char *property,
+%        const char *value)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o property: the image property.
+%
+%    o values: the image property values.
+%
+*/
+MagickExport MagickBooleanType SetImageProperty(Image *image,
+  const char *property,const char *value)
+{
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickStatusType
+    flags;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image->filename);
+  if (image->properties == (void *) NULL)
+    image->properties=NewSplayTree(CompareSplayTreeString,
+      RelinquishMagickMemory,RelinquishMagickMemory);
+  if ((value == (const char *) NULL) || (*value == '\0'))
+    return(DeleteImageProperty(image,property));
+  status=MagickTrue;
+  exception=(&image->exception);
+  switch (*property)
+  {
+    case 'B':
+    case 'b':
+    {
+      if (LocaleCompare(property,"background") == 0)
+        {
+          (void) QueryColorDatabase(value,&image->background_color,exception);
+          break;
+        }
+      if (LocaleCompare(property,"bias") == 0)
+        {
+          image->bias=SiPrefixToDouble(value,QuantumRange);
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'C':
+    case 'c':
+    {
+      if (LocaleCompare(property,"colorspace") == 0)
+        {
+          ssize_t
+            colorspace;
+
+          colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
+            value);
+          if (colorspace < 0)
+            break;
+          (void) SetImageColorspace(image,(ColorspaceType) colorspace);
+          break;
+        }
+      if (LocaleCompare(property,"compose") == 0)
+        {
+          ssize_t
+            compose;
+
+          compose=ParseCommandOption(MagickComposeOptions,MagickFalse,value);
+          if (compose < 0)
+            break;
+          image->compose=(CompositeOperator) compose;
+          break;
+        }
+      if (LocaleCompare(property,"compress") == 0)
+        {
+          ssize_t
+            compression;
+
+          compression=ParseCommandOption(MagickCompressOptions,MagickFalse,
+            value);
+          if (compression < 0)
+            break;
+          image->compression=(CompressionType) compression;
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'D':
+    case 'd':
+    {
+      if (LocaleCompare(property,"delay") == 0)
+        {
+          GeometryInfo
+            geometry_info;
+
+          flags=ParseGeometry(value,&geometry_info);
+          if ((flags & GreaterValue) != 0)
+            {
+              if (image->delay > (size_t) floor(geometry_info.rho+0.5))
+                image->delay=(size_t) floor(geometry_info.rho+0.5);
+            }
+          else
+            if ((flags & LessValue) != 0)
+              {
+                if (image->delay < (size_t) floor(geometry_info.rho+0.5))
+                  image->ticks_per_second=(ssize_t)
+                    floor(geometry_info.sigma+0.5);
+              }
+            else
+              image->delay=(size_t) floor(geometry_info.rho+0.5);
+          if ((flags & SigmaValue) != 0)
+            image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
+          break;
+        }
+      if (LocaleCompare(property,"density") == 0)
+        {
+          GeometryInfo
+            geometry_info;
+
+          flags=ParseGeometry(value,&geometry_info);
+          image->x_resolution=geometry_info.rho;
+          image->y_resolution=geometry_info.sigma;
+          if ((flags & SigmaValue) == 0)
+            image->y_resolution=image->x_resolution;
+        }
+      if (LocaleCompare(property,"depth") == 0)
+        {
+          image->depth=StringToUnsignedLong(value);
+          break;
+        }
+      if (LocaleCompare(property,"dispose") == 0)
+        {
+          ssize_t
+            dispose;
+
+          dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,value);
+          if (dispose < 0)
+            break;
+          image->dispose=(DisposeType) dispose;
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'G':
+    case 'g':
+    {
+      if (LocaleCompare(property,"gravity") == 0)
+        {
+          ssize_t
+            gravity;
+
+          gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,value);
+          if (gravity < 0)
+            break;
+          image->gravity=(GravityType) gravity;
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'I':
+    case 'i':
+    {
+      if (LocaleCompare(property,"intent") == 0)
+        {
+          ssize_t
+            rendering_intent;
+
+          rendering_intent=ParseCommandOption(MagickIntentOptions,MagickFalse,
+            value);
+          if (rendering_intent < 0)
+            break;
+          image->rendering_intent=(RenderingIntent) rendering_intent;
+          break;
+        }
+      if (LocaleCompare(property,"interpolate") == 0)
+        {
+          ssize_t
+            interpolate;
+
+          interpolate=ParseCommandOption(MagickInterpolateOptions,MagickFalse,
+            value);
+          if (interpolate < 0)
+            break;
+          image->interpolate=(InterpolatePixelMethod) interpolate;
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'L':
+    case 'l':
+    {
+      if (LocaleCompare(property,"loop") == 0)
+        {
+          image->iterations=StringToUnsignedLong(value);
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'P':
+    case 'p':
+    {
+      if (LocaleCompare(property,"page") == 0)
+        {
+          char
+            *geometry;
+
+          geometry=GetPageGeometry(value);
+          flags=ParseAbsoluteGeometry(geometry,&image->page);
+          geometry=DestroyString(geometry);
+          break;
+        }
+      if (LocaleCompare(property,"profile") == 0)
+        {
+          ImageInfo
+            *image_info;
+
+          StringInfo
+            *profile;
+
+          image_info=AcquireImageInfo();
+          (void) CopyMagickString(image_info->filename,value,MaxTextExtent);
+          (void) SetImageInfo(image_info,1,exception);
+          profile=FileToStringInfo(image_info->filename,~0UL,exception);
+          if (profile != (StringInfo *) NULL)
+            status=SetImageProfile(image,image_info->magick,profile);
+          image_info=DestroyImageInfo(image_info);
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'R':
+    case 'r':
+    {
+      if (LocaleCompare(property,"rendering-intent") == 0)
+        {
+          ssize_t
+            rendering_intent;
+
+          rendering_intent=ParseCommandOption(MagickIntentOptions,MagickFalse,
+            value);
+          if (rendering_intent < 0)
+            break;
+          image->rendering_intent=(RenderingIntent) rendering_intent;
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'T':
+    case 't':
+    {
+      if (LocaleCompare(property,"tile-offset") == 0)
+        {
+          char
+            *geometry;
+
+          geometry=GetPageGeometry(value);
+          flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
+          geometry=DestroyString(geometry);
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    case 'U':
+    case 'u':
+    {
+      if (LocaleCompare(property,"units") == 0)
+        {
+          ssize_t
+            units;
+
+          units=ParseCommandOption(MagickResolutionOptions,MagickFalse,value);
+          if (units < 0)
+            break;
+          image->units=(ResolutionType) units;
+          break;
+        }
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+    default:
+    {
+      status=AddValueToSplayTree((SplayTreeInfo *) image->properties,
+        ConstantString(property),ConstantString(value));
+      break;
+    }
+  }
+  return(status);
+}
diff --git a/MagickCore/property.h b/MagickCore/property.h
new file mode 100644
index 0000000..a67af02
--- /dev/null
+++ b/MagickCore/property.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore property methods.
+*/
+#ifndef _MAGICKCORE_PROPERTY_H
+#define _MAGICKCORE_PROPERTY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport char
+  *GetNextImageProperty(const Image *),
+  *InterpretImageProperties(const ImageInfo *,Image *,const char *),
+  *RemoveImageProperty(Image *,const char *);
+
+extern MagickExport const char
+  *GetImageProperty(const Image *,const char *),
+  *GetMagickProperty(const ImageInfo *,Image *,const char *);
+
+extern MagickExport MagickBooleanType
+  CloneImageProperties(Image *,const Image *),
+  DefineImageProperty(Image *,const char *),
+  DeleteImageProperty(Image *,const char *),
+  FormatImageProperty(Image *,const char *,const char *,...)
+    magick_attribute((format (printf,3,4))),
+  SetImageProperty(Image *,const char *,const char *);
+
+extern MagickExport void
+  DestroyImageProperties(Image *),
+  ResetImagePropertyIterator(const Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/quantize.c b/MagickCore/quantize.c
new file mode 100644
index 0000000..b14e54b
--- /dev/null
+++ b/MagickCore/quantize.c
@@ -0,0 +1,3310 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           QQQ   U   U   AAA   N   N  TTTTT  IIIII   ZZZZZ  EEEEE            %
+%          Q   Q  U   U  A   A  NN  N    T      I        ZZ  E                %
+%          Q   Q  U   U  AAAAA  N N N    T      I      ZZZ   EEEEE            %
+%          Q  QQ  U   U  A   A  N  NN    T      I     ZZ     E                %
+%           QQQQ   UUU   A   A  N   N    T    IIIII   ZZZZZ  EEEEE            %
+%                                                                             %
+%                                                                             %
+%    MagickCore Methods to Reduce the Number of Unique Colors in an Image     %
+%                                                                             %
+%                           Software Design                                   %
+%                             John Cristy                                     %
+%                              July 1992                                      %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Realism in computer graphics typically requires using 24 bits/pixel to
+%  generate an image.  Yet many graphic display devices do not contain the
+%  amount of memory necessary to match the spatial and color resolution of
+%  the human eye.  The Quantize methods takes a 24 bit image and reduces
+%  the number of colors so it can be displayed on raster device with less
+%  bits per pixel.  In most instances, the quantized image closely
+%  resembles the original reference image.
+%
+%  A reduction of colors in an image is also desirable for image
+%  transmission and real-time animation.
+%
+%  QuantizeImage() takes a standard RGB or monochrome images and quantizes
+%  them down to some fixed number of colors.
+%
+%  For purposes of color allocation, an image is a set of n pixels, where
+%  each pixel is a point in RGB space.  RGB space is a 3-dimensional
+%  vector space, and each pixel, Pi,  is defined by an ordered triple of
+%  red, green, and blue coordinates, (Ri, Gi, Bi).
+%
+%  Each primary color component (red, green, or blue) represents an
+%  intensity which varies linearly from 0 to a maximum value, Cmax, which
+%  corresponds to full saturation of that color.  Color allocation is
+%  defined over a domain consisting of the cube in RGB space with opposite
+%  vertices at (0,0,0) and (Cmax, Cmax, Cmax).  QUANTIZE requires Cmax =
+%  255.
+%
+%  The algorithm maps this domain onto a tree in which each node
+%  represents a cube within that domain.  In the following discussion
+%  these cubes are defined by the coordinate of two opposite vertices:
+%  The vertex nearest the origin in RGB space and the vertex farthest from
+%  the origin.
+%
+%  The tree's root node represents the entire domain, (0,0,0) through
+%  (Cmax,Cmax,Cmax).  Each lower level in the tree is generated by
+%  subdividing one node's cube into eight smaller cubes of equal size.
+%  This corresponds to bisecting the parent cube with planes passing
+%  through the midpoints of each edge.
+%
+%  The basic algorithm operates in three phases: Classification,
+%  Reduction, and Assignment.  Classification builds a color description
+%  tree for the image.  Reduction collapses the tree until the number it
+%  represents, at most, the number of colors desired in the output image.
+%  Assignment defines the output image's color map and sets each pixel's
+%  color by restorage_class in the reduced tree.  Our goal is to minimize
+%  the numerical discrepancies between the original colors and quantized
+%  colors (quantization error).
+%
+%  Classification begins by initializing a color description tree of
+%  sufficient depth to represent each possible input color in a leaf.
+%  However, it is impractical to generate a fully-formed color description
+%  tree in the storage_class phase for realistic values of Cmax.  If
+%  colors components in the input image are quantized to k-bit precision,
+%  so that Cmax= 2k-1, the tree would need k levels below the root node to
+%  allow representing each possible input color in a leaf.  This becomes
+%  prohibitive because the tree's total number of nodes is 1 +
+%  sum(i=1, k, 8k).
+%
+%  A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
+%  Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
+%  Initializes data structures for nodes only as they are needed;  (2)
+%  Chooses a maximum depth for the tree as a function of the desired
+%  number of colors in the output image (currently log2(colormap size)).
+%
+%  For each pixel in the input image, storage_class scans downward from
+%  the root of the color description tree.  At each level of the tree it
+%  identifies the single node which represents a cube in RGB space
+%  containing the pixel's color.  It updates the following data for each
+%  such node:
+%
+%    n1: Number of pixels whose color is contained in the RGB cube which
+%    this node represents;
+%
+%    n2: Number of pixels whose color is not represented in a node at
+%    lower depth in the tree;  initially,  n2 = 0 for all nodes except
+%    leaves of the tree.
+%
+%    Sr, Sg, Sb: Sums of the red, green, and blue component values for all
+%    pixels not classified at a lower depth. The combination of these sums
+%    and n2  will ultimately characterize the mean color of a set of
+%    pixels represented by this node.
+%
+%    E: the distance squared in RGB space between each pixel contained
+%    within a node and the nodes' center.  This represents the
+%    quantization error for a node.
+%
+%  Reduction repeatedly prunes the tree until the number of nodes with n2
+%  > 0 is less than or equal to the maximum number of colors allowed in
+%  the output image.  On any given iteration over the tree, it selects
+%  those nodes whose E count is minimal for pruning and merges their color
+%  statistics upward. It uses a pruning threshold, Ep, to govern node
+%  selection as follows:
+%
+%    Ep = 0
+%    while number of nodes with (n2 > 0) > required maximum number of colors
+%      prune all nodes such that E <= Ep
+%      Set Ep to minimum E in remaining nodes
+%
+%  This has the effect of minimizing any quantization error when merging
+%  two nodes together.
+%
+%  When a node to be pruned has offspring, the pruning procedure invokes
+%  itself recursively in order to prune the tree from the leaves upward.
+%  n2,  Sr, Sg,  and  Sb in a node being pruned are always added to the
+%  corresponding data in that node's parent.  This retains the pruned
+%  node's color characteristics for later averaging.
+%
+%  For each node, n2 pixels exist for which that node represents the
+%  smallest volume in RGB space containing those pixel's colors.  When n2
+%  > 0 the node will uniquely define a color in the output image. At the
+%  beginning of reduction,  n2 = 0  for all nodes except a the leaves of
+%  the tree which represent colors present in the input image.
+%
+%  The other pixel count, n1, indicates the total number of colors within
+%  the cubic volume which the node represents.  This includes n1 - n2
+%  pixels whose colors should be defined by nodes at a lower level in the
+%  tree.
+%
+%  Assignment generates the output image from the pruned tree.  The output
+%  image consists of two parts: (1)  A color map, which is an array of
+%  color descriptions (RGB triples) for each color present in the output
+%  image;  (2)  A pixel array, which represents each pixel as an index
+%  into the color map array.
+%
+%  First, the assignment phase makes one pass over the pruned color
+%  description tree to establish the image's color map.  For each node
+%  with n2  > 0, it divides Sr, Sg, and Sb by n2 .  This produces the mean
+%  color of all pixels that classify no lower than this node.  Each of
+%  these colors becomes an entry in the color map.
+%
+%  Finally,  the assignment phase reclassifies each pixel in the pruned
+%  tree to identify the deepest node containing the pixel's color.  The
+%  pixel's value in the pixel array becomes the index of this node's mean
+%  color in the color map.
+%
+%  This method is based on a similar algorithm written by Paul Raveling.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/histogram.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+
+/*
+  Define declarations.
+*/
+#if !defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
+#define CacheShift  2
+#else
+#define CacheShift  3
+#endif
+#define ErrorQueueLength  16
+#define MaxNodes  266817
+#define MaxTreeDepth  8
+#define NodesInAList  1920
+
+/*
+  Typdef declarations.
+*/
+typedef struct _RealPixelPacket
+{
+  MagickRealType
+    red,
+    green,
+    blue,
+    alpha;
+} RealPixelPacket;
+
+typedef struct _NodeInfo
+{
+  struct _NodeInfo
+    *parent,
+    *child[16];
+
+  MagickSizeType
+    number_unique;
+
+  RealPixelPacket
+    total_color;
+
+  MagickRealType
+    quantize_error;
+
+  size_t
+    color_number,
+    id,
+    level;
+} NodeInfo;
+
+typedef struct _Nodes
+{
+  NodeInfo
+    *nodes;
+
+  struct _Nodes
+    *next;
+} Nodes;
+
+typedef struct _CubeInfo
+{
+  NodeInfo
+    *root;
+
+  size_t
+    colors,
+    maximum_colors;
+
+  ssize_t
+    transparent_index;
+
+  MagickSizeType
+    transparent_pixels;
+
+  RealPixelPacket
+    target;
+
+  MagickRealType
+    distance,
+    pruning_threshold,
+    next_threshold;
+
+  size_t
+    nodes,
+    free_nodes,
+    color_number;
+
+  NodeInfo
+    *next_node;
+
+  Nodes
+    *node_queue;
+
+  ssize_t
+    *cache;
+
+  RealPixelPacket
+    error[ErrorQueueLength];
+
+  MagickRealType
+    weights[ErrorQueueLength];
+
+  QuantizeInfo
+    *quantize_info;
+
+  MagickBooleanType
+    associate_alpha;
+
+  ssize_t
+    x,
+    y;
+
+  size_t
+    depth;
+
+  MagickOffsetType
+    offset;
+
+  MagickSizeType
+    span;
+} CubeInfo;
+
+/*
+  Method prototypes.
+*/
+static CubeInfo
+  *GetCubeInfo(const QuantizeInfo *,const size_t,const size_t);
+
+static NodeInfo
+  *GetNodeInfo(CubeInfo *,const size_t,const size_t,NodeInfo *);
+
+static MagickBooleanType
+  AssignImageColors(Image *,CubeInfo *),
+  ClassifyImageColors(CubeInfo *,const Image *,ExceptionInfo *),
+  DitherImage(Image *,CubeInfo *),
+  SetGrayscaleImage(Image *);
+
+static size_t
+  DefineImageColormap(Image *,CubeInfo *,NodeInfo *);
+
+static void
+  ClosestColor(const Image *,CubeInfo *,const NodeInfo *),
+  DestroyCubeInfo(CubeInfo *),
+  PruneLevel(const Image *,CubeInfo *,const NodeInfo *),
+  PruneToCubeDepth(const Image *,CubeInfo *,const NodeInfo *),
+  ReduceImageColors(const Image *,CubeInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e Q u a n t i z e I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireQuantizeInfo() allocates the QuantizeInfo structure.
+%
+%  The format of the AcquireQuantizeInfo method is:
+%
+%      QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport QuantizeInfo *AcquireQuantizeInfo(const ImageInfo *image_info)
+{
+  QuantizeInfo
+    *quantize_info;
+
+  quantize_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*quantize_info));
+  if (quantize_info == (QuantizeInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetQuantizeInfo(quantize_info);
+  if (image_info != (ImageInfo *) NULL)
+    {
+      const char
+        *option;
+
+      quantize_info->dither=image_info->dither;
+      option=GetImageOption(image_info,"dither");
+      if (option != (const char *) NULL)
+        quantize_info->dither_method=(DitherMethod) ParseCommandOption(
+          MagickDitherOptions,MagickFalse,option);
+      quantize_info->measure_error=image_info->verbose;
+    }
+  return(quantize_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A s s i g n I m a g e C o l o r s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AssignImageColors() generates the output image from the pruned tree.  The
+%  output image consists of two parts: (1)  A color map, which is an array
+%  of color descriptions (RGB triples) for each color present in the
+%  output image;  (2)  A pixel array, which represents each pixel as an
+%  index into the color map array.
+%
+%  First, the assignment phase makes one pass over the pruned color
+%  description tree to establish the image's color map.  For each node
+%  with n2  > 0, it divides Sr, Sg, and Sb by n2 .  This produces the mean
+%  color of all pixels that classify no lower than this node.  Each of
+%  these colors becomes an entry in the color map.
+%
+%  Finally,  the assignment phase reclassifies each pixel in the pruned
+%  tree to identify the deepest node containing the pixel's color.  The
+%  pixel's value in the pixel array becomes the index of this node's mean
+%  color in the color map.
+%
+%  The format of the AssignImageColors() method is:
+%
+%      MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+*/
+
+static inline void AssociateAlphaPixel(const Image *image,
+  const CubeInfo *cube_info,const Quantum *pixel,
+  RealPixelPacket *alpha_pixel)
+{
+  MagickRealType
+    alpha;
+
+  if ((cube_info->associate_alpha == MagickFalse) ||
+      (GetPixelAlpha(image,pixel)== OpaqueAlpha))
+    {
+      alpha_pixel->red=(MagickRealType) GetPixelRed(image,pixel);
+      alpha_pixel->green=(MagickRealType) GetPixelGreen(image,pixel);
+      alpha_pixel->blue=(MagickRealType) GetPixelBlue(image,pixel);
+      alpha_pixel->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+      return;
+    }
+  alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,pixel));
+  alpha_pixel->red=alpha*GetPixelRed(image,pixel);
+  alpha_pixel->green=alpha*GetPixelGreen(image,pixel);
+  alpha_pixel->blue=alpha*GetPixelBlue(image,pixel);
+  alpha_pixel->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+}
+
+static inline void AssociateAlphaPixelPacket(const Image *image,
+  const CubeInfo *cube_info,const PixelPacket *pixel,
+  RealPixelPacket *alpha_pixel)
+{
+  MagickRealType
+    alpha;
+
+  if ((cube_info->associate_alpha == MagickFalse) ||
+      (pixel->alpha == OpaqueAlpha))
+    {
+      alpha_pixel->red=(MagickRealType) pixel->red;
+      alpha_pixel->green=(MagickRealType) pixel->green;
+      alpha_pixel->blue=(MagickRealType) pixel->blue;
+      alpha_pixel->alpha=(MagickRealType) pixel->alpha;
+      return;
+    }
+  alpha=(MagickRealType) (QuantumScale*pixel->alpha);
+  alpha_pixel->red=alpha*pixel->red;
+  alpha_pixel->green=alpha*pixel->green;
+  alpha_pixel->blue=alpha*pixel->blue;
+  alpha_pixel->alpha=(MagickRealType) pixel->alpha;
+}
+
+static inline Quantum ClampToUnsignedQuantum(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= QuantumRange)
+    return((Quantum) QuantumRange);
+  return((Quantum) (value+0.5));
+}
+
+static inline size_t ColorToNodeId(const CubeInfo *cube_info,
+  const RealPixelPacket *pixel,size_t index)
+{
+  size_t
+    id;
+
+  id=(size_t) (((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->red)) >> index) & 0x01) |
+    ((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->green)) >> index) & 0x01) << 1 |
+    ((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->blue)) >> index) & 0x01) << 2);
+  if (cube_info->associate_alpha != MagickFalse)
+    id|=((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->alpha)) >> index) & 0x1) << 3;
+  return(id);
+}
+
+static MagickBooleanType AssignImageColors(Image *image,CubeInfo *cube_info)
+{
+#define AssignImageTag  "Assign/Image"
+
+  ssize_t
+    y;
+
+  /*
+    Allocate image colormap.
+  */
+  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
+      (cube_info->quantize_info->colorspace != CMYKColorspace))
+    (void) TransformImageColorspace((Image *) image,
+      cube_info->quantize_info->colorspace);
+  else
+    if ((image->colorspace != GRAYColorspace) &&
+        (image->colorspace != RGBColorspace) &&
+        (image->colorspace != CMYColorspace))
+      (void) TransformImageColorspace((Image *) image,RGBColorspace);
+  if (AcquireImageColormap(image,cube_info->colors) == MagickFalse)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  image->colors=0;
+  cube_info->transparent_pixels=0;
+  cube_info->transparent_index=(-1);
+  (void) DefineImageColormap(image,cube_info,cube_info->root);
+  /*
+    Create a reduced color image.
+  */
+  if ((cube_info->quantize_info->dither != MagickFalse) &&
+      (cube_info->quantize_info->dither_method != NoDitherMethod))
+    (void) DitherImage(image,cube_info);
+  else
+    {
+      CacheView
+        *image_view;
+
+      ExceptionInfo
+        *exception;
+
+      MagickBooleanType
+        status;
+
+      status=MagickTrue;
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        CubeInfo
+          cube;
+
+        register Quantum
+          *restrict q;
+
+        register ssize_t
+          x;
+
+        ssize_t
+          count;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        cube=(*cube_info);
+        for (x=0; x < (ssize_t) image->columns; x+=count)
+        {
+          RealPixelPacket
+            pixel;
+
+          register const NodeInfo
+            *node_info;
+
+          register ssize_t
+            i;
+
+          size_t
+            id,
+            index;
+
+          /*
+            Identify the deepest node containing the pixel's color.
+          */
+          for (count=1; (x+count) < (ssize_t) image->columns; count++)
+          {
+            PixelPacket
+              packet;
+
+            GetPixelPacket(image,q+count*GetPixelChannels(image),&packet);
+            if (IsPixelEquivalent(image,q,&packet) == MagickFalse)
+              break;
+          }
+          AssociateAlphaPixel(image,&cube,q,&pixel);
+          node_info=cube.root;
+          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
+          {
+            id=ColorToNodeId(&cube,&pixel,index);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              break;
+            node_info=node_info->child[id];
+          }
+          /*
+            Find closest color among siblings and their children.
+          */
+          cube.target=pixel;
+          cube.distance=(MagickRealType) (4.0*(QuantumRange+1.0)*
+            (QuantumRange+1.0)+1.0);
+          ClosestColor(image,&cube,node_info->parent);
+          index=cube.color_number;
+          for (i=0; i < (ssize_t) count; i++)
+          {
+            if (image->storage_class == PseudoClass)
+              SetPixelIndex(image,(Quantum) index,q);
+            if (cube.quantize_info->measure_error == MagickFalse)
+              {
+                SetPixelRed(image,image->colormap[index].red,q);
+                SetPixelGreen(image,image->colormap[index].green,q);
+                SetPixelBlue(image,image->colormap[index].blue,q);
+                if (cube.associate_alpha != MagickFalse)
+                  SetPixelAlpha(image,image->colormap[index].alpha,q);
+              }
+            q+=GetPixelChannels(image);
+          }
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+            #pragma omp critical (MagickCore_AssignImageColors)
+#endif
+            proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      image_view=DestroyCacheView(image_view);
+    }
+  if (cube_info->quantize_info->measure_error != MagickFalse)
+    (void) GetImageQuantizeError(image);
+  if ((cube_info->quantize_info->number_colors == 2) &&
+      (cube_info->quantize_info->colorspace == GRAYColorspace))
+    {
+      Quantum
+        intensity;
+
+      register PixelPacket
+        *restrict q;
+
+      register ssize_t
+        i;
+
+      /*
+        Monochrome image.
+      */
+      q=image->colormap;
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        intensity=(Quantum) ((MagickRealType) GetPixelPacketIntensity(q) <
+          ((MagickRealType) QuantumRange/2.0) ? 0 : QuantumRange);
+        q->red=intensity;
+        q->green=intensity;
+        q->blue=intensity;
+        q++;
+      }
+    }
+  (void) SyncImage(image);
+  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
+      (cube_info->quantize_info->colorspace != CMYKColorspace))
+    (void) TransformImageColorspace((Image *) image,RGBColorspace);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l a s s i f y I m a g e C o l o r s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClassifyImageColors() begins by initializing a color description tree
+%  of sufficient depth to represent each possible input color in a leaf.
+%  However, it is impractical to generate a fully-formed color
+%  description tree in the storage_class phase for realistic values of
+%  Cmax.  If colors components in the input image are quantized to k-bit
+%  precision, so that Cmax= 2k-1, the tree would need k levels below the
+%  root node to allow representing each possible input color in a leaf.
+%  This becomes prohibitive because the tree's total number of nodes is
+%  1 + sum(i=1,k,8k).
+%
+%  A complete tree would require 19,173,961 nodes for k = 8, Cmax = 255.
+%  Therefore, to avoid building a fully populated tree, QUANTIZE: (1)
+%  Initializes data structures for nodes only as they are needed;  (2)
+%  Chooses a maximum depth for the tree as a function of the desired
+%  number of colors in the output image (currently log2(colormap size)).
+%
+%  For each pixel in the input image, storage_class scans downward from
+%  the root of the color description tree.  At each level of the tree it
+%  identifies the single node which represents a cube in RGB space
+%  containing It updates the following data for each such node:
+%
+%    n1 : Number of pixels whose color is contained in the RGB cube
+%    which this node represents;
+%
+%    n2 : Number of pixels whose color is not represented in a node at
+%    lower depth in the tree;  initially,  n2 = 0 for all nodes except
+%    leaves of the tree.
+%
+%    Sr, Sg, Sb : Sums of the red, green, and blue component values for
+%    all pixels not classified at a lower depth. The combination of
+%    these sums and n2  will ultimately characterize the mean color of a
+%    set of pixels represented by this node.
+%
+%    E: the distance squared in RGB space between each pixel contained
+%    within a node and the nodes' center.  This represents the quantization
+%    error for a node.
+%
+%  The format of the ClassifyImageColors() method is:
+%
+%      MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
+%        const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o image: the image.
+%
+*/
+
+static inline void SetAssociatedAlpha(const Image *image,CubeInfo *cube_info)
+{
+  MagickBooleanType
+    associate_alpha;
+
+  associate_alpha=image->matte;
+  if (cube_info->quantize_info->colorspace == TransparentColorspace)
+    associate_alpha=MagickFalse;
+  if ((cube_info->quantize_info->number_colors == 2) &&
+      (cube_info->quantize_info->colorspace == GRAYColorspace))
+    associate_alpha=MagickFalse;
+  cube_info->associate_alpha=associate_alpha;
+}
+
+static MagickBooleanType ClassifyImageColors(CubeInfo *cube_info,
+  const Image *image,ExceptionInfo *exception)
+{
+#define ClassifyImageTag  "Classify/Image"
+
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    proceed;
+
+  MagickRealType
+    bisect;
+
+  NodeInfo
+    *node_info;
+
+  RealPixelPacket
+    error,
+    mid,
+    midpoint,
+    pixel;
+
+  size_t
+    count,
+    id,
+    index,
+    level;
+
+  ssize_t
+    y;
+
+  /*
+    Classify the first cube_info->maximum_colors colors to a tree depth of 8.
+  */
+  SetAssociatedAlpha(image,cube_info);
+  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
+      (cube_info->quantize_info->colorspace != CMYKColorspace))
+    (void) TransformImageColorspace((Image *) image,
+      cube_info->quantize_info->colorspace);
+  else
+    if ((image->colorspace != GRAYColorspace) &&
+        (image->colorspace != CMYColorspace) &&
+        (image->colorspace != RGBColorspace))
+      (void) TransformImageColorspace((Image *) image,RGBColorspace);
+  midpoint.red=(MagickRealType) QuantumRange/2.0;
+  midpoint.green=(MagickRealType) QuantumRange/2.0;
+  midpoint.blue=(MagickRealType) QuantumRange/2.0;
+  midpoint.alpha=(MagickRealType) QuantumRange/2.0;
+  error.alpha=0.0;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    if (cube_info->nodes > MaxNodes)
+      {
+        /*
+          Prune one level if the color tree is too large.
+        */
+        PruneLevel(image,cube_info,cube_info->root);
+        cube_info->depth--;
+      }
+    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
+    {
+      /*
+        Start at the root and descend the color cube tree.
+      */
+      for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
+      {
+        PixelPacket
+          packet;
+
+        GetPixelPacket(image,p+count*GetPixelChannels(image),&packet);
+        if (IsPixelEquivalent(image,p,&packet) == MagickFalse)
+          break;
+      }
+      AssociateAlphaPixel(image,cube_info,p,&pixel);
+      index=MaxTreeDepth-1;
+      bisect=((MagickRealType) QuantumRange+1.0)/2.0;
+      mid=midpoint;
+      node_info=cube_info->root;
+      for (level=1; level <= MaxTreeDepth; level++)
+      {
+        bisect*=0.5;
+        id=ColorToNodeId(cube_info,&pixel,index);
+        mid.red+=(id & 1) != 0 ? bisect : -bisect;
+        mid.green+=(id & 2) != 0 ? bisect : -bisect;
+        mid.blue+=(id & 4) != 0 ? bisect : -bisect;
+        mid.alpha+=(id & 8) != 0 ? bisect : -bisect;
+        if (node_info->child[id] == (NodeInfo *) NULL)
+          {
+            /*
+              Set colors of new node to contain pixel.
+            */
+            node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'",
+                image->filename);
+            if (level == MaxTreeDepth)
+              cube_info->colors++;
+          }
+        /*
+          Approximate the quantization error represented by this node.
+        */
+        node_info=node_info->child[id];
+        error.red=QuantumScale*(pixel.red-mid.red);
+        error.green=QuantumScale*(pixel.green-mid.green);
+        error.blue=QuantumScale*(pixel.blue-mid.blue);
+        if (cube_info->associate_alpha != MagickFalse)
+          error.alpha=QuantumScale*(pixel.alpha-mid.alpha);
+        node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
+          count*error.green*error.green+count*error.blue*error.blue+
+          count*error.alpha*error.alpha));
+        cube_info->root->quantize_error+=node_info->quantize_error;
+        index--;
+      }
+      /*
+        Sum RGB for this leaf for later derivation of the mean cube color.
+      */
+      node_info->number_unique+=count;
+      node_info->total_color.red+=count*QuantumScale*pixel.red;
+      node_info->total_color.green+=count*QuantumScale*pixel.green;
+      node_info->total_color.blue+=count*QuantumScale*pixel.blue;
+      if (cube_info->associate_alpha != MagickFalse)
+        node_info->total_color.alpha+=count*QuantumScale*pixel.alpha;
+      p+=count*GetPixelChannels(image);
+    }
+    if (cube_info->colors > cube_info->maximum_colors)
+      {
+        PruneToCubeDepth(image,cube_info,cube_info->root);
+        break;
+      }
+    proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  for (y++; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    if (cube_info->nodes > MaxNodes)
+      {
+        /*
+          Prune one level if the color tree is too large.
+        */
+        PruneLevel(image,cube_info,cube_info->root);
+        cube_info->depth--;
+      }
+    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) count)
+    {
+      /*
+        Start at the root and descend the color cube tree.
+      */
+      for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
+      {
+        PixelPacket
+          packet;
+
+        GetPixelPacket(image,p+count*GetPixelChannels(image),&packet);
+        if (IsPixelEquivalent(image,p,&packet) == MagickFalse)
+          break;
+      }
+      AssociateAlphaPixel(image,cube_info,p,&pixel);
+      index=MaxTreeDepth-1;
+      bisect=((MagickRealType) QuantumRange+1.0)/2.0;
+      mid=midpoint;
+      node_info=cube_info->root;
+      for (level=1; level <= cube_info->depth; level++)
+      {
+        bisect*=0.5;
+        id=ColorToNodeId(cube_info,&pixel,index);
+        mid.red+=(id & 1) != 0 ? bisect : -bisect;
+        mid.green+=(id & 2) != 0 ? bisect : -bisect;
+        mid.blue+=(id & 4) != 0 ? bisect : -bisect;
+        mid.alpha+=(id & 8) != 0 ? bisect : -bisect;
+        if (node_info->child[id] == (NodeInfo *) NULL)
+          {
+            /*
+              Set colors of new node to contain pixel.
+            */
+            node_info->child[id]=GetNodeInfo(cube_info,id,level,node_info);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","%s",
+                image->filename);
+            if (level == cube_info->depth)
+              cube_info->colors++;
+          }
+        /*
+          Approximate the quantization error represented by this node.
+        */
+        node_info=node_info->child[id];
+        error.red=QuantumScale*(pixel.red-mid.red);
+        error.green=QuantumScale*(pixel.green-mid.green);
+        error.blue=QuantumScale*(pixel.blue-mid.blue);
+        if (cube_info->associate_alpha != MagickFalse)
+          error.alpha=QuantumScale*(pixel.alpha-mid.alpha);
+        node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
+          count*error.green*error.green+count*error.blue*error.blue+
+          count*error.alpha*error.alpha));
+        cube_info->root->quantize_error+=node_info->quantize_error;
+        index--;
+      }
+      /*
+        Sum RGB for this leaf for later derivation of the mean cube color.
+      */
+      node_info->number_unique+=count;
+      node_info->total_color.red+=count*QuantumScale*pixel.red;
+      node_info->total_color.green+=count*QuantumScale*pixel.green;
+      node_info->total_color.blue+=count*QuantumScale*pixel.blue;
+      if (cube_info->associate_alpha != MagickFalse)
+        node_info->total_color.alpha+=count*QuantumScale*pixel.alpha;
+      p+=count*GetPixelChannels(image);
+    }
+    proceed=SetImageProgress(image,ClassifyImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  image_view=DestroyCacheView(image_view);
+  if ((cube_info->quantize_info->colorspace != UndefinedColorspace) &&
+      (cube_info->quantize_info->colorspace != CMYKColorspace))
+    (void) TransformImageColorspace((Image *) image,RGBColorspace);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e Q u a n t i z e I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneQuantizeInfo() makes a duplicate of the given quantize info structure,
+%  or if quantize info is NULL, a new one.
+%
+%  The format of the CloneQuantizeInfo method is:
+%
+%      QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
+%
+%  A description of each parameter follows:
+%
+%    o clone_info: Method CloneQuantizeInfo returns a duplicate of the given
+%      quantize info, or if image info is NULL a new one.
+%
+%    o quantize_info: a structure of type info.
+%
+*/
+MagickExport QuantizeInfo *CloneQuantizeInfo(const QuantizeInfo *quantize_info)
+{
+  QuantizeInfo
+    *clone_info;
+
+  clone_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*clone_info));
+  if (clone_info == (QuantizeInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  GetQuantizeInfo(clone_info);
+  if (quantize_info == (QuantizeInfo *) NULL)
+    return(clone_info);
+  clone_info->number_colors=quantize_info->number_colors;
+  clone_info->tree_depth=quantize_info->tree_depth;
+  clone_info->dither=quantize_info->dither;
+  clone_info->dither_method=quantize_info->dither_method;
+  clone_info->colorspace=quantize_info->colorspace;
+  clone_info->measure_error=quantize_info->measure_error;
+  return(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l o s e s t C o l o r                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClosestColor() traverses the color cube tree at a particular node and
+%  determines which colormap entry best represents the input color.
+%
+%  The format of the ClosestColor method is:
+%
+%      void ClosestColor(const Image *image,CubeInfo *cube_info,
+%        const NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o node_info: the address of a structure of type NodeInfo which points to a
+%      node in the color cube tree that is to be pruned.
+%
+*/
+static void ClosestColor(const Image *image,CubeInfo *cube_info,
+  const NodeInfo *node_info)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      ClosestColor(image,cube_info,node_info->child[i]);
+  if (node_info->number_unique != 0)
+    {
+      MagickRealType
+        pixel;
+
+      register MagickRealType
+        alpha,
+        beta,
+        distance;
+
+      register PixelPacket
+        *restrict p;
+
+      register RealPixelPacket
+        *restrict q;
+
+      /*
+        Determine if this color is "closest".
+      */
+      p=image->colormap+node_info->color_number;
+      q=(&cube_info->target);
+      alpha=1.0;
+      beta=1.0;
+      if (cube_info->associate_alpha != MagickFalse)
+        {
+          alpha=(MagickRealType) (QuantumScale*p->alpha);
+          beta=(MagickRealType) (QuantumScale*q->alpha);
+        }
+      pixel=alpha*p->red-beta*q->red;
+      distance=pixel*pixel;
+      if (distance <= cube_info->distance)
+        {
+          pixel=alpha*p->green-beta*q->green;
+          distance+=pixel*pixel;
+          if (distance <= cube_info->distance)
+            {
+              pixel=alpha*p->blue-beta*q->blue;
+              distance+=pixel*pixel;
+              if (distance <= cube_info->distance)
+                {
+                  pixel=alpha-beta;
+                  distance+=pixel*pixel;
+                  if (distance <= cube_info->distance)
+                    {
+                      cube_info->distance=distance;
+                      cube_info->color_number=node_info->color_number;
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p r e s s I m a g e C o l o r m a p                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompressImageColormap() compresses an image colormap by removing any
+%  duplicate or unused color entries.
+%
+%  The format of the CompressImageColormap method is:
+%
+%      MagickBooleanType CompressImageColormap(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType CompressImageColormap(Image *image)
+{
+  QuantizeInfo
+    quantize_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (IsPaletteImage(image,&image->exception) == MagickFalse)
+    return(MagickFalse);
+  GetQuantizeInfo(&quantize_info);
+  quantize_info.number_colors=image->colors;
+  quantize_info.tree_depth=MaxTreeDepth;
+  return(QuantizeImage(&quantize_info,image));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f i n e I m a g e C o l o r m a p                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineImageColormap() traverses the color cube tree and notes each colormap
+%  entry.  A colormap entry is any node in the color cube tree where the
+%  of unique colors is not zero.  DefineImageColormap() returns the number of
+%  colors in the image colormap.
+%
+%  The format of the DefineImageColormap method is:
+%
+%      size_t DefineImageColormap(Image *image,CubeInfo *cube_info,
+%        NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o node_info: the address of a structure of type NodeInfo which points to a
+%      node in the color cube tree that is to be pruned.
+%
+*/
+static size_t DefineImageColormap(Image *image,CubeInfo *cube_info,
+  NodeInfo *node_info)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      (void) DefineImageColormap(image,cube_info,node_info->child[i]);
+  if (node_info->number_unique != 0)
+    {
+      register MagickRealType
+        alpha;
+
+      register PixelPacket
+        *restrict q;
+
+      /*
+        Colormap entry is defined by the mean color in this cube.
+      */
+      q=image->colormap+image->colors;
+      alpha=(MagickRealType) ((MagickOffsetType) node_info->number_unique);
+      alpha=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+      if (cube_info->associate_alpha == MagickFalse)
+        {
+          q->red=ClampToQuantum((MagickRealType)
+            (alpha*QuantumRange*node_info->total_color.red));
+          q->green=ClampToQuantum((MagickRealType)
+            (alpha*QuantumRange*node_info->total_color.green));
+          q->blue=ClampToQuantum((MagickRealType)
+            (alpha*QuantumRange*node_info->total_color.blue));
+          q->alpha=OpaqueAlpha;
+        }
+      else
+        {
+          MagickRealType
+            opacity;
+
+          opacity=(MagickRealType) (alpha*QuantumRange*
+            node_info->total_color.alpha);
+          q->alpha=ClampToQuantum(opacity);
+          if (q->alpha == OpaqueAlpha)
+            {
+              q->red=ClampToQuantum((MagickRealType)
+                (alpha*QuantumRange*node_info->total_color.red));
+              q->green=ClampToQuantum((MagickRealType)
+                (alpha*QuantumRange*node_info->total_color.green));
+              q->blue=ClampToQuantum((MagickRealType)
+                (alpha*QuantumRange*node_info->total_color.blue));
+            }
+          else
+            {
+              MagickRealType
+                gamma;
+
+              gamma=(MagickRealType) (QuantumScale*q->alpha);
+              gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+              q->red=ClampToQuantum((MagickRealType)
+                (alpha*gamma*QuantumRange*node_info->total_color.red));
+              q->green=ClampToQuantum((MagickRealType)
+                (alpha*gamma*QuantumRange*node_info->total_color.green));
+              q->blue=ClampToQuantum((MagickRealType)
+                (alpha*gamma*QuantumRange*node_info->total_color.blue));
+              if (node_info->number_unique > cube_info->transparent_pixels)
+                {
+                  cube_info->transparent_pixels=node_info->number_unique;
+                  cube_info->transparent_index=(ssize_t) image->colors;
+                }
+            }
+        }
+      node_info->color_number=image->colors++;
+    }
+  return(image->colors);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y C u b e I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyCubeInfo() deallocates memory associated with an image.
+%
+%  The format of the DestroyCubeInfo method is:
+%
+%      DestroyCubeInfo(CubeInfo *cube_info)
+%
+%  A description of each parameter follows:
+%
+%    o cube_info: the address of a structure of type CubeInfo.
+%
+*/
+static void DestroyCubeInfo(CubeInfo *cube_info)
+{
+  register Nodes
+    *nodes;
+
+  /*
+    Release color cube tree storage.
+  */
+  do
+  {
+    nodes=cube_info->node_queue->next;
+    cube_info->node_queue->nodes=(NodeInfo *) RelinquishMagickMemory(
+      cube_info->node_queue->nodes);
+    cube_info->node_queue=(Nodes *) RelinquishMagickMemory(
+      cube_info->node_queue);
+    cube_info->node_queue=nodes;
+  } while (cube_info->node_queue != (Nodes *) NULL);
+  if (cube_info->cache != (ssize_t *) NULL)
+    cube_info->cache=(ssize_t *) RelinquishMagickMemory(cube_info->cache);
+  cube_info->quantize_info=DestroyQuantizeInfo(cube_info->quantize_info);
+  cube_info=(CubeInfo *) RelinquishMagickMemory(cube_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y Q u a n t i z e I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyQuantizeInfo() deallocates memory associated with an QuantizeInfo
+%  structure.
+%
+%  The format of the DestroyQuantizeInfo method is:
+%
+%      QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+*/
+MagickExport QuantizeInfo *DestroyQuantizeInfo(QuantizeInfo *quantize_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(quantize_info != (QuantizeInfo *) NULL);
+  assert(quantize_info->signature == MagickSignature);
+  quantize_info->signature=(~MagickSignature);
+  quantize_info=(QuantizeInfo *) RelinquishMagickMemory(quantize_info);
+  return(quantize_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D i t h e r I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DitherImage() distributes the difference between an original image and
+%  the corresponding color reduced algorithm to neighboring pixels using
+%  serpentine-scan Floyd-Steinberg error diffusion. DitherImage returns
+%  MagickTrue if the image is dithered otherwise MagickFalse.
+%
+%  The format of the DitherImage method is:
+%
+%      MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+*/
+
+static RealPixelPacket **DestroyPixelThreadSet(RealPixelPacket **pixels)
+{
+  register ssize_t
+    i;
+
+  assert(pixels != (RealPixelPacket **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (pixels[i] != (RealPixelPacket *) NULL)
+      pixels[i]=(RealPixelPacket *) RelinquishMagickMemory(pixels[i]);
+  pixels=(RealPixelPacket **) RelinquishMagickMemory(pixels);
+  return(pixels);
+}
+
+static RealPixelPacket **AcquirePixelThreadSet(const size_t count)
+{
+  RealPixelPacket
+    **pixels;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixels=(RealPixelPacket **) AcquireQuantumMemory(number_threads,
+    sizeof(*pixels));
+  if (pixels == (RealPixelPacket **) NULL)
+    return((RealPixelPacket **) NULL);
+  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    pixels[i]=(RealPixelPacket *) AcquireQuantumMemory(count,
+      2*sizeof(**pixels));
+    if (pixels[i] == (RealPixelPacket *) NULL)
+      return(DestroyPixelThreadSet(pixels));
+  }
+  return(pixels);
+}
+
+static inline ssize_t CacheOffset(CubeInfo *cube_info,
+  const RealPixelPacket *pixel)
+{
+#define RedShift(pixel) (((pixel) >> CacheShift) << (0*(8-CacheShift)))
+#define GreenShift(pixel) (((pixel) >> CacheShift) << (1*(8-CacheShift)))
+#define BlueShift(pixel) (((pixel) >> CacheShift) << (2*(8-CacheShift)))
+#define AlphaShift(pixel) (((pixel) >> CacheShift) << (3*(8-CacheShift)))
+
+  ssize_t
+    offset;
+
+  offset=(ssize_t)
+    (RedShift(ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->red))) |
+    GreenShift(ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->green))) |
+    BlueShift(ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->blue))));
+  if (cube_info->associate_alpha != MagickFalse)
+    offset|=AlphaShift(ScaleQuantumToChar(ClampToUnsignedQuantum(
+      pixel->alpha)));
+  return(offset);
+}
+
+static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info)
+{
+#define DitherImageTag  "Dither/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  RealPixelPacket
+    **pixels;
+
+  ssize_t
+    y;
+
+  /*
+    Distribute quantization error using Floyd-Steinberg.
+  */
+  pixels=AcquirePixelThreadSet(image->columns);
+  if (pixels == (RealPixelPacket **) NULL)
+    return(MagickFalse);
+  exception=(&image->exception);
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    CubeInfo
+      cube;
+
+    RealPixelPacket
+      *current,
+      *previous;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    size_t
+      index;
+
+    ssize_t
+      v;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    q+=(y & 0x01)*image->columns*GetPixelChannels(image);
+    cube=(*cube_info);
+    current=pixels[id]+(y & 0x01)*image->columns;
+    previous=pixels[id]+((y+1) & 0x01)*image->columns;
+    v=(ssize_t) ((y & 0x01) != 0 ? -1 : 1);
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      RealPixelPacket
+        color,
+        pixel;
+
+      register ssize_t
+        i;
+
+      ssize_t
+        u;
+
+      q-=(y & 0x01)*GetPixelChannels(image);
+      u=(y & 0x01) != 0 ? (ssize_t) image->columns-1-x : x;
+      AssociateAlphaPixel(image,&cube,q,&pixel);
+      if (x > 0)
+        {
+          pixel.red+=7*current[u-v].red/16;
+          pixel.green+=7*current[u-v].green/16;
+          pixel.blue+=7*current[u-v].blue/16;
+          if (cube.associate_alpha != MagickFalse)
+            pixel.alpha+=7*current[u-v].alpha/16;
+        }
+      if (y > 0)
+        {
+          if (x < (ssize_t) (image->columns-1))
+            {
+              pixel.red+=previous[u+v].red/16;
+              pixel.green+=previous[u+v].green/16;
+              pixel.blue+=previous[u+v].blue/16;
+              if (cube.associate_alpha != MagickFalse)
+                pixel.alpha+=previous[u+v].alpha/16;
+            }
+          pixel.red+=5*previous[u].red/16;
+          pixel.green+=5*previous[u].green/16;
+          pixel.blue+=5*previous[u].blue/16;
+          if (cube.associate_alpha != MagickFalse)
+            pixel.alpha+=5*previous[u].alpha/16;
+          if (x > 0)
+            {
+              pixel.red+=3*previous[u-v].red/16;
+              pixel.green+=3*previous[u-v].green/16;
+              pixel.blue+=3*previous[u-v].blue/16;
+              if (cube.associate_alpha != MagickFalse)
+                pixel.alpha+=3*previous[u-v].alpha/16;
+            }
+        }
+      pixel.red=(MagickRealType) ClampToUnsignedQuantum(pixel.red);
+      pixel.green=(MagickRealType) ClampToUnsignedQuantum(pixel.green);
+      pixel.blue=(MagickRealType) ClampToUnsignedQuantum(pixel.blue);
+      if (cube.associate_alpha != MagickFalse)
+        pixel.alpha=(MagickRealType) ClampToUnsignedQuantum(pixel.alpha);
+      i=CacheOffset(&cube,&pixel);
+      if (cube.cache[i] < 0)
+        {
+          register NodeInfo
+            *node_info;
+
+          register size_t
+            id;
+
+          /*
+            Identify the deepest node containing the pixel's color.
+          */
+          node_info=cube.root;
+          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
+          {
+            id=ColorToNodeId(&cube,&pixel,index);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              break;
+            node_info=node_info->child[id];
+          }
+          /*
+            Find closest color among siblings and their children.
+          */
+          cube.target=pixel;
+          cube.distance=(MagickRealType) (4.0*(QuantumRange+1.0)*(QuantumRange+
+            1.0)+1.0);
+          ClosestColor(image,&cube,node_info->parent);
+          cube.cache[i]=(ssize_t) cube.color_number;
+        }
+      /*
+        Assign pixel to closest colormap entry.
+      */
+      index=(size_t) cube.cache[i];
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(image,(Quantum) index,q);
+      if (cube.quantize_info->measure_error == MagickFalse)
+        {
+          SetPixelRed(image,image->colormap[index].red,q);
+          SetPixelGreen(image,image->colormap[index].green,q);
+          SetPixelBlue(image,image->colormap[index].blue,q);
+          if (cube.associate_alpha != MagickFalse)
+            SetPixelAlpha(image,image->colormap[index].alpha,q);
+        }
+      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+        status=MagickFalse;
+      /*
+        Store the error.
+      */
+      AssociateAlphaPixelPacket(image,&cube,image->colormap+index,&color);
+      current[u].red=pixel.red-color.red;
+      current[u].green=pixel.green-color.green;
+      current[u].blue=pixel.blue-color.blue;
+      if (cube.associate_alpha != MagickFalse)
+        current[u].alpha=pixel.alpha-color.alpha;
+      if (image->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp critical (MagickCore_FloydSteinbergDither)
+#endif
+          proceed=SetImageProgress(image,DitherImageTag,(MagickOffsetType) y,
+            image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+      q+=((y+1) & 0x01)*GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  pixels=DestroyPixelThreadSet(pixels);
+  return(MagickTrue);
+}
+
+static MagickBooleanType
+  RiemersmaDither(Image *,CacheView *,CubeInfo *,const unsigned int);
+
+static void Riemersma(Image *image,CacheView *image_view,CubeInfo *cube_info,
+  const size_t level,const unsigned int direction)
+{
+  if (level == 1)
+    switch (direction)
+    {
+      case WestGravity:
+      {
+        (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
+        break;
+      }
+      case EastGravity:
+      {
+        (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
+        break;
+      }
+      case NorthGravity:
+      {
+        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
+        break;
+      }
+      case SouthGravity:
+      {
+        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
+        break;
+      }
+      default:
+        break;
+    }
+  else
+    switch (direction)
+    {
+      case WestGravity:
+      {
+        Riemersma(image,image_view,cube_info,level-1,NorthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
+        Riemersma(image,image_view,cube_info,level-1,WestGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
+        Riemersma(image,image_view,cube_info,level-1,WestGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
+        Riemersma(image,image_view,cube_info,level-1,SouthGravity);
+        break;
+      }
+      case EastGravity:
+      {
+        Riemersma(image,image_view,cube_info,level-1,SouthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
+        Riemersma(image,image_view,cube_info,level-1,EastGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
+        Riemersma(image,image_view,cube_info,level-1,EastGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
+        Riemersma(image,image_view,cube_info,level-1,NorthGravity);
+        break;
+      }
+      case NorthGravity:
+      {
+        Riemersma(image,image_view,cube_info,level-1,WestGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
+        Riemersma(image,image_view,cube_info,level-1,NorthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,EastGravity);
+        Riemersma(image,image_view,cube_info,level-1,NorthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
+        Riemersma(image,image_view,cube_info,level-1,EastGravity);
+        break;
+      }
+      case SouthGravity:
+      {
+        Riemersma(image,image_view,cube_info,level-1,EastGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,NorthGravity);
+        Riemersma(image,image_view,cube_info,level-1,SouthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,WestGravity);
+        Riemersma(image,image_view,cube_info,level-1,SouthGravity);
+        (void) RiemersmaDither(image,image_view,cube_info,SouthGravity);
+        Riemersma(image,image_view,cube_info,level-1,WestGravity);
+        break;
+      }
+      default:
+        break;
+    }
+}
+
+static MagickBooleanType RiemersmaDither(Image *image,CacheView *image_view,
+  CubeInfo *cube_info,const unsigned int direction)
+{
+#define DitherImageTag  "Dither/Image"
+
+  MagickBooleanType
+    proceed;
+
+  RealPixelPacket
+    color,
+    pixel;
+
+  register CubeInfo
+    *p;
+
+  size_t
+    index;
+
+  p=cube_info;
+  if ((p->x >= 0) && (p->x < (ssize_t) image->columns) &&
+      (p->y >= 0) && (p->y < (ssize_t) image->rows))
+    {
+      ExceptionInfo
+        *exception;
+
+      register Quantum
+        *restrict q;
+
+      register ssize_t
+        i;
+
+      /*
+        Distribute error.
+      */
+      exception=(&image->exception);
+      q=GetCacheViewAuthenticPixels(image_view,p->x,p->y,1,1,exception);
+      if (q == (const Quantum *) NULL)
+        return(MagickFalse);
+      AssociateAlphaPixel(image,cube_info,q,&pixel);
+      for (i=0; i < ErrorQueueLength; i++)
+      {
+        pixel.red+=p->weights[i]*p->error[i].red;
+        pixel.green+=p->weights[i]*p->error[i].green;
+        pixel.blue+=p->weights[i]*p->error[i].blue;
+        if (cube_info->associate_alpha != MagickFalse)
+          pixel.alpha+=p->weights[i]*p->error[i].alpha;
+      }
+      pixel.red=(MagickRealType) ClampToUnsignedQuantum(pixel.red);
+      pixel.green=(MagickRealType) ClampToUnsignedQuantum(pixel.green);
+      pixel.blue=(MagickRealType) ClampToUnsignedQuantum(pixel.blue);
+      if (cube_info->associate_alpha != MagickFalse)
+        pixel.alpha=(MagickRealType) ClampToUnsignedQuantum(pixel.alpha);
+      i=CacheOffset(cube_info,&pixel);
+      if (p->cache[i] < 0)
+        {
+          register NodeInfo
+            *node_info;
+
+          register size_t
+            id;
+
+          /*
+            Identify the deepest node containing the pixel's color.
+          */
+          node_info=p->root;
+          for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
+          {
+            id=ColorToNodeId(cube_info,&pixel,index);
+            if (node_info->child[id] == (NodeInfo *) NULL)
+              break;
+            node_info=node_info->child[id];
+          }
+          node_info=node_info->parent;
+          /*
+            Find closest color among siblings and their children.
+          */
+          p->target=pixel;
+          p->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*((MagickRealType)
+            QuantumRange+1.0)+1.0);
+          ClosestColor(image,p,node_info->parent);
+          p->cache[i]=(ssize_t) p->color_number;
+        }
+      /*
+        Assign pixel to closest colormap entry.
+      */
+      index=(size_t) p->cache[i];
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(image,(Quantum) index,q);
+      if (cube_info->quantize_info->measure_error == MagickFalse)
+        {
+          SetPixelRed(image,image->colormap[index].red,q);
+          SetPixelGreen(image,image->colormap[index].green,q);
+          SetPixelBlue(image,image->colormap[index].blue,q);
+          if (cube_info->associate_alpha != MagickFalse)
+            SetPixelAlpha(image,image->colormap[index].alpha,q);
+        }
+      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+        return(MagickFalse);
+      /*
+        Propagate the error as the last entry of the error queue.
+      */
+      (void) CopyMagickMemory(p->error,p->error+1,(ErrorQueueLength-1)*
+        sizeof(p->error[0]));
+      AssociateAlphaPixelPacket(image,cube_info,image->colormap+index,&color);
+      p->error[ErrorQueueLength-1].red=pixel.red-color.red;
+      p->error[ErrorQueueLength-1].green=pixel.green-color.green;
+      p->error[ErrorQueueLength-1].blue=pixel.blue-color.blue;
+      if (cube_info->associate_alpha != MagickFalse)
+        p->error[ErrorQueueLength-1].alpha=pixel.alpha-color.alpha;
+      proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
+      if (proceed == MagickFalse)
+        return(MagickFalse);
+      p->offset++;
+    }
+  switch (direction)
+  {
+    case WestGravity: p->x--; break;
+    case EastGravity: p->x++; break;
+    case NorthGravity: p->y--; break;
+    case SouthGravity: p->y++; break;
+  }
+  return(MagickTrue);
+}
+
+static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickBooleanType DitherImage(Image *image,CubeInfo *cube_info)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  size_t
+    depth;
+
+  if (cube_info->quantize_info->dither_method != RiemersmaDitherMethod)
+    return(FloydSteinbergDither(image,cube_info));
+  /*
+    Distribute quantization error along a Hilbert curve.
+  */
+  (void) ResetMagickMemory(cube_info->error,0,ErrorQueueLength*
+    sizeof(*cube_info->error));
+  cube_info->x=0;
+  cube_info->y=0;
+  i=MagickMax((ssize_t) image->columns,(ssize_t) image->rows);
+  for (depth=1; i != 0; depth++)
+    i>>=1;
+  if ((ssize_t) (1L << depth) < MagickMax((ssize_t) image->columns,(ssize_t) image->rows))
+    depth++;
+  cube_info->offset=0;
+  cube_info->span=(MagickSizeType) image->columns*image->rows;
+  image_view=AcquireCacheView(image);
+  if (depth > 1)
+    Riemersma(image,image_view,cube_info,depth-1,NorthGravity);
+  status=RiemersmaDither(image,image_view,cube_info,ForgetGravity);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t C u b e I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetCubeInfo() initialize the Cube data structure.
+%
+%  The format of the GetCubeInfo method is:
+%
+%      CubeInfo GetCubeInfo(const QuantizeInfo *quantize_info,
+%        const size_t depth,const size_t maximum_colors)
+%
+%  A description of each parameter follows.
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o depth: Normally, this integer value is zero or one.  A zero or
+%      one tells Quantize to choose a optimal tree depth of Log4(number_colors).
+%      A tree of this depth generally allows the best representation of the
+%      reference image with the least amount of memory and the fastest
+%      computational speed.  In some cases, such as an image with low color
+%      dispersion (a few number of colors), a value other than
+%      Log4(number_colors) is required.  To expand the color tree completely,
+%      use a value of 8.
+%
+%    o maximum_colors: maximum colors.
+%
+*/
+static CubeInfo *GetCubeInfo(const QuantizeInfo *quantize_info,
+  const size_t depth,const size_t maximum_colors)
+{
+  CubeInfo
+    *cube_info;
+
+  MagickRealType
+    sum,
+    weight;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  /*
+    Initialize tree to describe color cube_info.
+  */
+  cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
+  if (cube_info == (CubeInfo *) NULL)
+    return((CubeInfo *) NULL);
+  (void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
+  cube_info->depth=depth;
+  if (cube_info->depth > MaxTreeDepth)
+    cube_info->depth=MaxTreeDepth;
+  if (cube_info->depth < 2)
+    cube_info->depth=2;
+  cube_info->maximum_colors=maximum_colors;
+  /*
+    Initialize root node.
+  */
+  cube_info->root=GetNodeInfo(cube_info,0,0,(NodeInfo *) NULL);
+  if (cube_info->root == (NodeInfo *) NULL)
+    return((CubeInfo *) NULL);
+  cube_info->root->parent=cube_info->root;
+  cube_info->quantize_info=CloneQuantizeInfo(quantize_info);
+  if (cube_info->quantize_info->dither == MagickFalse)
+    return(cube_info);
+  /*
+    Initialize dither resources.
+  */
+  length=(size_t) (1UL << (4*(8-CacheShift)));
+  cube_info->cache=(ssize_t *) AcquireQuantumMemory(length,
+    sizeof(*cube_info->cache));
+  if (cube_info->cache == (ssize_t *) NULL)
+    return((CubeInfo *) NULL);
+  /*
+    Initialize color cache.
+  */
+  for (i=0; i < (ssize_t) length; i++)
+    cube_info->cache[i]=(-1);
+  /*
+    Distribute weights along a curve of exponential decay.
+  */
+  weight=1.0;
+  for (i=0; i < ErrorQueueLength; i++)
+  {
+    cube_info->weights[ErrorQueueLength-i-1]=1.0/weight;
+    weight*=exp(log(((double) QuantumRange+1.0))/(ErrorQueueLength-1.0));
+  }
+  /*
+    Normalize the weighting factors.
+  */
+  weight=0.0;
+  for (i=0; i < ErrorQueueLength; i++)
+    weight+=cube_info->weights[i];
+  sum=0.0;
+  for (i=0; i < ErrorQueueLength; i++)
+  {
+    cube_info->weights[i]/=weight;
+    sum+=cube_info->weights[i];
+  }
+  cube_info->weights[0]+=1.0-sum;
+  return(cube_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t N o d e I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNodeInfo() allocates memory for a new node in the color cube tree and
+%  presets all fields to zero.
+%
+%  The format of the GetNodeInfo method is:
+%
+%      NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t id,
+%        const size_t level,NodeInfo *parent)
+%
+%  A description of each parameter follows.
+%
+%    o node: The GetNodeInfo method returns a pointer to a queue of nodes.
+%
+%    o id: Specifies the child number of the node.
+%
+%    o level: Specifies the level in the storage_class the node resides.
+%
+*/
+static NodeInfo *GetNodeInfo(CubeInfo *cube_info,const size_t id,
+  const size_t level,NodeInfo *parent)
+{
+  NodeInfo
+    *node_info;
+
+  if (cube_info->free_nodes == 0)
+    {
+      Nodes
+        *nodes;
+
+      /*
+        Allocate a new queue of nodes.
+      */
+      nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
+      if (nodes == (Nodes *) NULL)
+        return((NodeInfo *) NULL);
+      nodes->nodes=(NodeInfo *) AcquireQuantumMemory(NodesInAList,
+        sizeof(*nodes->nodes));
+      if (nodes->nodes == (NodeInfo *) NULL)
+        return((NodeInfo *) NULL);
+      nodes->next=cube_info->node_queue;
+      cube_info->node_queue=nodes;
+      cube_info->next_node=nodes->nodes;
+      cube_info->free_nodes=NodesInAList;
+    }
+  cube_info->nodes++;
+  cube_info->free_nodes--;
+  node_info=cube_info->next_node++;
+  (void) ResetMagickMemory(node_info,0,sizeof(*node_info));
+  node_info->parent=parent;
+  node_info->id=id;
+  node_info->level=level;
+  return(node_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t I m a g e Q u a n t i z e E r r o r                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageQuantizeError() measures the difference between the original
+%  and quantized images.  This difference is the total quantization error.
+%  The error is computed by summing over all pixels in an image the distance
+%  squared in RGB space between each reference pixel value and its quantized
+%  value.  These values are computed:
+%
+%    o mean_error_per_pixel:  This value is the mean error for any single
+%      pixel in the image.
+%
+%    o normalized_mean_square_error:  This value is the normalized mean
+%      quantization error for any single pixel in the image.  This distance
+%      measure is normalized to a range between 0 and 1.  It is independent
+%      of the range of red, green, and blue values in the image.
+%
+%    o normalized_maximum_square_error:  Thsi value is the normalized
+%      maximum quantization error for any single pixel in the image.  This
+%      distance measure is normalized to a range between 0 and 1.  It is
+%      independent of the range of red, green, and blue values in your image.
+%
+%  The format of the GetImageQuantizeError method is:
+%
+%      MagickBooleanType GetImageQuantizeError(Image *image)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType GetImageQuantizeError(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickRealType
+    alpha,
+    area,
+    beta,
+    distance,
+    maximum_error,
+    mean_error,
+    mean_error_per_pixel;
+
+  size_t
+    index;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  image->total_colors=GetNumberColors(image,(FILE *) NULL,&image->exception);
+  (void) ResetMagickMemory(&image->error,0,sizeof(image->error));
+  if (image->storage_class == DirectClass)
+    return(MagickTrue);
+  alpha=1.0;
+  beta=1.0;
+  area=3.0*image->columns*image->rows;
+  maximum_error=0.0;
+  mean_error_per_pixel=0.0;
+  mean_error=0.0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      index=1UL*GetPixelIndex(image,p);
+      if (image->matte != MagickFalse)
+        {
+          alpha=(MagickRealType) (QuantumScale*GetPixelAlpha(image,p));
+          beta=(MagickRealType) (QuantumScale*image->colormap[index].alpha);
+        }
+      distance=fabs(alpha*GetPixelRed(image,p)-beta*
+        image->colormap[index].red);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      distance=fabs(alpha*GetPixelGreen(image,p)-beta*
+        image->colormap[index].green);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      distance=fabs(alpha*GetPixelBlue(image,p)-beta*
+        image->colormap[index].blue);
+      mean_error_per_pixel+=distance;
+      mean_error+=distance*distance;
+      if (distance > maximum_error)
+        maximum_error=distance;
+      p+=GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  image->error.mean_error_per_pixel=(double) mean_error_per_pixel/area;
+  image->error.normalized_mean_error=(double) QuantumScale*QuantumScale*
+    mean_error/area;
+  image->error.normalized_maximum_error=(double) QuantumScale*maximum_error;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t Q u a n t i z e I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetQuantizeInfo() initializes the QuantizeInfo structure.
+%
+%  The format of the GetQuantizeInfo method is:
+%
+%      GetQuantizeInfo(QuantizeInfo *quantize_info)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to a QuantizeInfo structure.
+%
+*/
+MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(quantize_info != (QuantizeInfo *) NULL);
+  (void) ResetMagickMemory(quantize_info,0,sizeof(*quantize_info));
+  quantize_info->number_colors=256;
+  quantize_info->dither=MagickTrue;
+  quantize_info->dither_method=RiemersmaDitherMethod;
+  quantize_info->colorspace=UndefinedColorspace;
+  quantize_info->measure_error=MagickFalse;
+  quantize_info->signature=MagickSignature;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     P o s t e r i z e I m a g e C h a n n e l                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PosterizeImage() reduces the image to a limited number of colors for a
+%  "poster" effect.
+%
+%  The format of the PosterizeImage method is:
+%
+%      MagickBooleanType PosterizeImage(Image *image,const size_t levels,
+%        const MagickBooleanType dither)
+%      MagickBooleanType PosterizeImageChannel(Image *image,
+%        const ChannelType channel,const size_t levels,
+%        const MagickBooleanType dither)
+%
+%  A description of each parameter follows:
+%
+%    o image: Specifies a pointer to an Image structure.
+%
+%    o levels: Number of color levels allowed in each channel.  Very low values
+%      (2, 3, or 4) have the most visible effect.
+%
+%    o dither: Set this integer value to something other than zero to dither
+%      the mapped image.
+%
+*/
+
+static inline ssize_t MagickRound(MagickRealType x)
+{
+  /*
+    Round the fraction to nearest integer.
+  */
+  if (x >= 0.0)
+    return((ssize_t) (x+0.5));
+  return((ssize_t) (x-0.5));
+}
+
+MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
+  const MagickBooleanType dither)
+{
+  MagickBooleanType
+    status;
+
+  status=PosterizeImageChannel(image,DefaultChannels,levels,dither);
+  return(status);
+}
+
+MagickExport MagickBooleanType PosterizeImageChannel(Image *image,
+  const ChannelType channel,const size_t levels,const MagickBooleanType dither)
+{
+#define PosterizeImageTag  "Posterize/Image"
+#define PosterizePixel(pixel) (Quantum) (QuantumRange*(MagickRound( \
+  QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  QuantizeInfo
+    *quantize_info;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->storage_class == PseudoClass)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+    #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (i=0; i < (ssize_t) image->colors; i++)
+    {
+      /*
+        Posterize colormap.
+      */
+      if ((channel & RedChannel) != 0)
+        image->colormap[i].red=PosterizePixel(image->colormap[i].red);
+      if ((channel & GreenChannel) != 0)
+        image->colormap[i].green=PosterizePixel(image->colormap[i].green);
+      if ((channel & BlueChannel) != 0)
+        image->colormap[i].blue=PosterizePixel(image->colormap[i].blue);
+      if ((channel & OpacityChannel) != 0)
+        image->colormap[i].alpha=PosterizePixel(image->colormap[i].alpha);
+    }
+  /*
+    Posterize image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,PosterizePixel(GetPixelRed(image,q)),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,PosterizePixel(GetPixelGreen(image,q)),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,PosterizePixel(GetPixelBlue(image,q)),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,PosterizePixel(GetPixelBlack(image,q)),q);
+      if (((channel & OpacityChannel) != 0) &&
+          (image->matte == MagickTrue))
+        SetPixelAlpha(image,PosterizePixel(GetPixelAlpha(image,q)),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_PosterizeImageChannel)
+#endif
+        proceed=SetImageProgress(image,PosterizeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
+  quantize_info->number_colors=(size_t) MagickMin((ssize_t) levels*levels*
+    levels,MaxColormapSize+1);
+  quantize_info->dither=dither;
+  quantize_info->tree_depth=MaxTreeDepth;
+  status=QuantizeImage(quantize_info,image);
+  quantize_info=DestroyQuantizeInfo(quantize_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   P r u n e C h i l d                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PruneChild() deletes the given node and merges its statistics into its
+%  parent.
+%
+%  The format of the PruneSubtree method is:
+%
+%      PruneChild(const Image *image,CubeInfo *cube_info,
+%        const NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o node_info: pointer to node in color cube tree that is to be pruned.
+%
+*/
+static void PruneChild(const Image *image,CubeInfo *cube_info,
+  const NodeInfo *node_info)
+{
+  NodeInfo
+    *parent;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      PruneChild(image,cube_info,node_info->child[i]);
+  /*
+    Merge color statistics into parent.
+  */
+  parent=node_info->parent;
+  parent->number_unique+=node_info->number_unique;
+  parent->total_color.red+=node_info->total_color.red;
+  parent->total_color.green+=node_info->total_color.green;
+  parent->total_color.blue+=node_info->total_color.blue;
+  parent->total_color.alpha+=node_info->total_color.alpha;
+  parent->child[node_info->id]=(NodeInfo *) NULL;
+  cube_info->nodes--;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  P r u n e L e v e l                                                        %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PruneLevel() deletes all nodes at the bottom level of the color tree merging
+%  their color statistics into their parent node.
+%
+%  The format of the PruneLevel method is:
+%
+%      PruneLevel(const Image *image,CubeInfo *cube_info,
+%        const NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o node_info: pointer to node in color cube tree that is to be pruned.
+%
+*/
+static void PruneLevel(const Image *image,CubeInfo *cube_info,
+  const NodeInfo *node_info)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      PruneLevel(image,cube_info,node_info->child[i]);
+  if (node_info->level == cube_info->depth)
+    PruneChild(image,cube_info,node_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  P r u n e T o C u b e D e p t h                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PruneToCubeDepth() deletes any nodes at a depth greater than
+%  cube_info->depth while merging their color statistics into their parent
+%  node.
+%
+%  The format of the PruneToCubeDepth method is:
+%
+%      PruneToCubeDepth(const Image *image,CubeInfo *cube_info,
+%        const NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o node_info: pointer to node in color cube tree that is to be pruned.
+%
+*/
+static void PruneToCubeDepth(const Image *image,CubeInfo *cube_info,
+  const NodeInfo *node_info)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      PruneToCubeDepth(image,cube_info,node_info->child[i]);
+  if (node_info->level > cube_info->depth)
+    PruneChild(image,cube_info,node_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  Q u a n t i z e I m a g e                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QuantizeImage() analyzes the colors within a reference image and chooses a
+%  fixed number of colors to represent the image.  The goal of the algorithm
+%  is to minimize the color difference between the input and output image while
+%  minimizing the processing time.
+%
+%  The format of the QuantizeImage method is:
+%
+%      MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
+%        Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info,
+  Image *image)
+{
+  CubeInfo
+    *cube_info;
+
+  MagickBooleanType
+    status;
+
+  size_t
+    depth,
+    maximum_colors;
+
+  assert(quantize_info != (const QuantizeInfo *) NULL);
+  assert(quantize_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  maximum_colors=quantize_info->number_colors;
+  if (maximum_colors == 0)
+    maximum_colors=MaxColormapSize;
+  if (maximum_colors > MaxColormapSize)
+    maximum_colors=MaxColormapSize;
+  if ((IsImageGray(image,&image->exception) != MagickFalse) &&
+      (image->matte == MagickFalse))
+    (void) SetGrayscaleImage(image);
+  if ((image->storage_class == PseudoClass) &&
+      (image->colors <= maximum_colors))
+    return(MagickTrue);
+  depth=quantize_info->tree_depth;
+  if (depth == 0)
+    {
+      size_t
+        colors;
+
+      /*
+        Depth of color tree is: Log4(colormap size)+2.
+      */
+      colors=maximum_colors;
+      for (depth=1; colors != 0; depth++)
+        colors>>=2;
+      if ((quantize_info->dither != MagickFalse) && (depth > 2))
+        depth--;
+      if ((image->matte != MagickFalse) && (depth > 5))
+        depth--;
+    }
+  /*
+    Initialize color cube.
+  */
+  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
+  if (cube_info == (CubeInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  status=ClassifyImageColors(cube_info,image,&image->exception);
+  if (status != MagickFalse)
+    {
+      /*
+        Reduce the number of colors in the image.
+      */
+      ReduceImageColors(image,cube_info);
+      status=AssignImageColors(image,cube_info);
+    }
+  DestroyCubeInfo(cube_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   Q u a n t i z e I m a g e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QuantizeImages() analyzes the colors within a set of reference images and
+%  chooses a fixed number of colors to represent the set.  The goal of the
+%  algorithm is to minimize the color difference between the input and output
+%  images while minimizing the processing time.
+%
+%  The format of the QuantizeImages method is:
+%
+%      MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
+%        Image *images)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o images: Specifies a pointer to a list of Image structures.
+%
+*/
+MagickExport MagickBooleanType QuantizeImages(const QuantizeInfo *quantize_info,
+  Image *images)
+{
+  CubeInfo
+    *cube_info;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    proceed,
+    status;
+
+  MagickProgressMonitor
+    progress_monitor;
+
+  register ssize_t
+    i;
+
+  size_t
+    depth,
+    maximum_colors,
+    number_images;
+
+  assert(quantize_info != (const QuantizeInfo *) NULL);
+  assert(quantize_info->signature == MagickSignature);
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  if (GetNextImageInList(images) == (Image *) NULL)
+    {
+      /*
+        Handle a single image with QuantizeImage.
+      */
+      status=QuantizeImage(quantize_info,images);
+      return(status);
+    }
+  status=MagickFalse;
+  maximum_colors=quantize_info->number_colors;
+  if (maximum_colors == 0)
+    maximum_colors=MaxColormapSize;
+  if (maximum_colors > MaxColormapSize)
+    maximum_colors=MaxColormapSize;
+  depth=quantize_info->tree_depth;
+  if (depth == 0)
+    {
+      size_t
+        colors;
+
+      /*
+        Depth of color tree is: Log4(colormap size)+2.
+      */
+      colors=maximum_colors;
+      for (depth=1; colors != 0; depth++)
+        colors>>=2;
+      if (quantize_info->dither != MagickFalse)
+        depth--;
+    }
+  /*
+    Initialize color cube.
+  */
+  cube_info=GetCubeInfo(quantize_info,depth,maximum_colors);
+  if (cube_info == (CubeInfo *) NULL)
+    {
+      (void) ThrowMagickException(&images->exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      return(MagickFalse);
+    }
+  number_images=GetImageListLength(images);
+  image=images;
+  for (i=0; image != (Image *) NULL; i++)
+  {
+    progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
+      image->client_data);
+    status=ClassifyImageColors(cube_info,image,&image->exception);
+    if (status == MagickFalse)
+      break;
+    (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
+    proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
+      number_images);
+    if (proceed == MagickFalse)
+      break;
+    image=GetNextImageInList(image);
+  }
+  if (status != MagickFalse)
+    {
+      /*
+        Reduce the number of colors in an image sequence.
+      */
+      ReduceImageColors(images,cube_info);
+      image=images;
+      for (i=0; image != (Image *) NULL; i++)
+      {
+        progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor)
+          NULL,image->client_data);
+        status=AssignImageColors(image,cube_info);
+        if (status == MagickFalse)
+          break;
+        (void) SetImageProgressMonitor(image,progress_monitor,
+          image->client_data);
+        proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) i,
+          number_images);
+        if (proceed == MagickFalse)
+          break;
+        image=GetNextImageInList(image);
+      }
+    }
+  DestroyCubeInfo(cube_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e d u c e                                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Reduce() traverses the color cube tree and prunes any node whose
+%  quantization error falls below a particular threshold.
+%
+%  The format of the Reduce method is:
+%
+%      Reduce(const Image *image,CubeInfo *cube_info,const NodeInfo *node_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+%    o node_info: pointer to node in color cube tree that is to be pruned.
+%
+*/
+static void Reduce(const Image *image,CubeInfo *cube_info,
+  const NodeInfo *node_info)
+{
+  register ssize_t
+    i;
+
+  size_t
+    number_children;
+
+  /*
+    Traverse any children.
+  */
+  number_children=cube_info->associate_alpha == MagickFalse ? 8UL : 16UL;
+  for (i=0; i < (ssize_t) number_children; i++)
+    if (node_info->child[i] != (NodeInfo *) NULL)
+      Reduce(image,cube_info,node_info->child[i]);
+  if (node_info->quantize_error <= cube_info->pruning_threshold)
+    PruneChild(image,cube_info,node_info);
+  else
+    {
+      /*
+        Find minimum pruning threshold.
+      */
+      if (node_info->number_unique > 0)
+        cube_info->colors++;
+      if (node_info->quantize_error < cube_info->next_threshold)
+        cube_info->next_threshold=node_info->quantize_error;
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e d u c e I m a g e C o l o r s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReduceImageColors() repeatedly prunes the tree until the number of nodes
+%  with n2 > 0 is less than or equal to the maximum number of colors allowed
+%  in the output image.  On any given iteration over the tree, it selects
+%  those nodes whose E value is minimal for pruning and merges their
+%  color statistics upward. It uses a pruning threshold, Ep, to govern
+%  node selection as follows:
+%
+%    Ep = 0
+%    while number of nodes with (n2 > 0) > required maximum number of colors
+%      prune all nodes such that E <= Ep
+%      Set Ep to minimum E in remaining nodes
+%
+%  This has the effect of minimizing any quantization error when merging
+%  two nodes together.
+%
+%  When a node to be pruned has offspring, the pruning procedure invokes
+%  itself recursively in order to prune the tree from the leaves upward.
+%  n2,  Sr, Sg,  and  Sb in a node being pruned are always added to the
+%  corresponding data in that node's parent.  This retains the pruned
+%  node's color characteristics for later averaging.
+%
+%  For each node, n2 pixels exist for which that node represents the
+%  smallest volume in RGB space containing those pixel's colors.  When n2
+%  > 0 the node will uniquely define a color in the output image. At the
+%  beginning of reduction,  n2 = 0  for all nodes except a the leaves of
+%  the tree which represent colors present in the input image.
+%
+%  The other pixel count, n1, indicates the total number of colors
+%  within the cubic volume which the node represents.  This includes n1 -
+%  n2  pixels whose colors should be defined by nodes at a lower level in
+%  the tree.
+%
+%  The format of the ReduceImageColors method is:
+%
+%      ReduceImageColors(const Image *image,CubeInfo *cube_info)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cube_info: A pointer to the Cube structure.
+%
+*/
+static void ReduceImageColors(const Image *image,CubeInfo *cube_info)
+{
+#define ReduceImageTag  "Reduce/Image"
+
+  MagickBooleanType
+    proceed;
+
+  MagickOffsetType
+    offset;
+
+  size_t
+    span;
+
+  cube_info->next_threshold=0.0;
+  for (span=cube_info->colors; cube_info->colors > cube_info->maximum_colors; )
+  {
+    cube_info->pruning_threshold=cube_info->next_threshold;
+    cube_info->next_threshold=cube_info->root->quantize_error-1;
+    cube_info->colors=0;
+    Reduce(image,cube_info,cube_info->root);
+    offset=(MagickOffsetType) span-cube_info->colors;
+    proceed=SetImageProgress(image,ReduceImageTag,offset,span-
+      cube_info->maximum_colors+1);
+    if (proceed == MagickFalse)
+      break;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m a p I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemapImage() replaces the colors of an image with the closest color from
+%  a reference image.
+%
+%  The format of the RemapImage method is:
+%
+%      MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
+%        Image *image,const Image *remap_image)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o image: the image.
+%
+%    o remap_image: the reference image.
+%
+*/
+MagickExport MagickBooleanType RemapImage(const QuantizeInfo *quantize_info,
+  Image *image,const Image *remap_image)
+{
+  CubeInfo
+    *cube_info;
+
+  MagickBooleanType
+    status;
+
+  /*
+    Initialize color cube.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(remap_image != (Image *) NULL);
+  assert(remap_image->signature == MagickSignature);
+  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
+    quantize_info->number_colors);
+  if (cube_info == (CubeInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  status=ClassifyImageColors(cube_info,remap_image,&image->exception);
+  if (status != MagickFalse)
+    {
+      /*
+        Classify image colors from the reference image.
+      */
+      cube_info->quantize_info->number_colors=cube_info->colors;
+      status=AssignImageColors(image,cube_info);
+    }
+  DestroyCubeInfo(cube_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m a p I m a g e s                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemapImages() replaces the colors of a sequence of images with the
+%  closest color from a reference image.
+%
+%  The format of the RemapImage method is:
+%
+%      MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
+%        Image *images,Image *remap_image)
+%
+%  A description of each parameter follows:
+%
+%    o quantize_info: Specifies a pointer to an QuantizeInfo structure.
+%
+%    o images: the image sequence.
+%
+%    o remap_image: the reference image.
+%
+*/
+MagickExport MagickBooleanType RemapImages(const QuantizeInfo *quantize_info,
+  Image *images,const Image *remap_image)
+{
+  CubeInfo
+    *cube_info;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  image=images;
+  if (remap_image == (Image *) NULL)
+    {
+      /*
+        Create a global colormap for an image sequence.
+      */
+      status=QuantizeImages(quantize_info,images);
+      return(status);
+    }
+  /*
+    Classify image colors from the reference image.
+  */
+  cube_info=GetCubeInfo(quantize_info,MaxTreeDepth,
+    quantize_info->number_colors);
+  if (cube_info == (CubeInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  status=ClassifyImageColors(cube_info,remap_image,&image->exception);
+  if (status != MagickFalse)
+    {
+      /*
+        Classify image colors from the reference image.
+      */
+      cube_info->quantize_info->number_colors=cube_info->colors;
+      image=images;
+      for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
+      {
+        status=AssignImageColors(image,cube_info);
+        if (status == MagickFalse)
+          break;
+      }
+    }
+  DestroyCubeInfo(cube_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t G r a y s c a l e I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetGrayscaleImage() converts an image to a PseudoClass grayscale image.
+%
+%  The format of the SetGrayscaleImage method is:
+%
+%      MagickBooleanType SetGrayscaleImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: The image.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int IntensityCompare(const void *x,const void *y)
+{
+  PixelPacket
+    *color_1,
+    *color_2;
+
+  ssize_t
+    intensity;
+
+  color_1=(PixelPacket *) x;
+  color_2=(PixelPacket *) y;
+  intensity=GetPixelPacketIntensity(color_1)-(ssize_t)
+    GetPixelPacketIntensity(color_2);
+  return((int) intensity);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static MagickBooleanType SetGrayscaleImage(Image *image)
+{
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  PixelPacket
+    *colormap;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    *colormap_index,
+    j,
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->type != GrayscaleType)
+    (void) TransformImageColorspace(image,GRAYColorspace);
+  colormap_index=(ssize_t *) AcquireQuantumMemory(MaxMap+1,
+    sizeof(*colormap_index));
+  if (colormap_index == (ssize_t *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  if (image->storage_class != PseudoClass)
+    {
+      ExceptionInfo
+        *exception;
+
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+        colormap_index[i]=(-1);
+      if (AcquireImageColormap(image,MaxMap+1) == MagickFalse)
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename);
+      image->colors=0;
+      status=MagickTrue;
+      exception=(&image->exception);
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        register Quantum
+          *restrict q;
+
+        register ssize_t
+          x;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          register size_t
+            intensity;
+
+          intensity=ScaleQuantumToMap(GetPixelRed(image,q));
+          if (colormap_index[intensity] < 0)
+            {
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+    #pragma omp critical (MagickCore_SetGrayscaleImage)
+#endif
+              if (colormap_index[intensity] < 0)
+                {
+                  colormap_index[intensity]=(ssize_t) image->colors;
+                  image->colormap[image->colors].red=GetPixelRed(image,q);
+                  image->colormap[image->colors].green=GetPixelGreen(image,q);
+                  image->colormap[image->colors].blue=GetPixelBlue(image,q);
+                  image->colors++;
+               }
+            }
+          SetPixelIndex(image,(Quantum) 
+            colormap_index[intensity],q);
+          q+=GetPixelChannels(image);
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+    }
+  for (i=0; i < (ssize_t) image->colors; i++)
+    image->colormap[i].alpha=(unsigned short) i;
+  qsort((void *) image->colormap,image->colors,sizeof(PixelPacket),
+    IntensityCompare);
+  colormap=(PixelPacket *) AcquireQuantumMemory(image->colors,
+    sizeof(*colormap));
+  if (colormap == (PixelPacket *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  j=0;
+  colormap[j]=image->colormap[0];
+  for (i=0; i < (ssize_t) image->colors; i++)
+  {
+    if (IsPixelPacketEquivalent(&colormap[j],&image->colormap[i]) == MagickFalse)
+      {
+        j++;
+        colormap[j]=image->colormap[i];
+      }
+    colormap_index[(ssize_t) image->colormap[i].alpha]=j;
+  }
+  image->colors=(size_t) (j+1);
+  image->colormap=(PixelPacket *) RelinquishMagickMemory(image->colormap);
+  image->colormap=colormap;
+  status=MagickTrue;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelIndex(image,(Quantum) colormap_index[ScaleQuantumToMap(
+        GetPixelIndex(image,q))],q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
+  image->type=GrayscaleType;
+  if (IsImageMonochrome(image,&image->exception) != MagickFalse)
+    image->type=BilevelType;
+  return(status);
+}
diff --git a/MagickCore/quantize.h b/MagickCore/quantize.h
new file mode 100644
index 0000000..e0303ea
--- /dev/null
+++ b/MagickCore/quantize.h
@@ -0,0 +1,82 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image quantization methods.
+*/
+#ifndef _MAGICKCORE_QUANTIZE_H
+#define _MAGICKCORE_QUANTIZE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/colorspace.h"
+
+typedef enum
+{
+  UndefinedDitherMethod,
+  NoDitherMethod,
+  RiemersmaDitherMethod,
+  FloydSteinbergDitherMethod
+} DitherMethod;
+
+typedef struct _QuantizeInfo
+{
+  size_t
+    number_colors;
+
+  size_t
+    tree_depth;
+
+  MagickBooleanType
+    dither;
+
+  ColorspaceType
+    colorspace;
+
+  MagickBooleanType
+    measure_error;
+
+  size_t
+    signature;
+
+  DitherMethod
+    dither_method;
+} QuantizeInfo;
+
+extern MagickExport MagickBooleanType
+  CompressImageColormap(Image *),
+  GetImageQuantizeError(Image *),
+  PosterizeImage(Image *,const size_t,const MagickBooleanType),
+  PosterizeImageChannel(Image *,const ChannelType,const size_t,
+    const MagickBooleanType),
+  QuantizeImage(const QuantizeInfo *,Image *),
+  QuantizeImages(const QuantizeInfo *,Image *),
+  RemapImage(const QuantizeInfo *,Image *,const Image *),
+  RemapImages(const QuantizeInfo *,Image *,const Image *);
+
+extern MagickExport QuantizeInfo
+  *AcquireQuantizeInfo(const ImageInfo *),
+  *CloneQuantizeInfo(const QuantizeInfo *),
+  *DestroyQuantizeInfo(QuantizeInfo *);
+
+extern MagickExport void
+  GetQuantizeInfo(QuantizeInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/quantum-export.c b/MagickCore/quantum-export.c
new file mode 100644
index 0000000..cef5547
--- /dev/null
+++ b/MagickCore/quantum-export.c
@@ -0,0 +1,3337 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                QQQ   U   U   AAA   N   N  TTTTT  U   U  M   M               %
+%               Q   Q  U   U  A   A  NN  N    T    U   U  MM MM               %
+%               Q   Q  U   U  AAAAA  N N N    T    U   U  M M M               %
+%               Q  QQ  U   U  A   A  N  NN    T    U   U  M   M               %
+%                QQQQ   UUU   A   A  N   N    T     UUU   M   M               %
+%                                                                             %
+%                   EEEEE  X   X  PPPP    OOO   RRRR   TTTTT                  %
+%                   E       X X   P   P  O   O  R   R    T                    %
+%                   EEE      X    PPPP   O   O  RRRR     T                    %
+%                   E       X X   P      O   O  R R      T                    %
+%                   EEEEE  X   X  P       OOO   R  R     T                    %
+%                                                                             %
+%                 MagickCore Methods to Export Quantum Pixels                 %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               October 1998                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   E x p o r t Q u a n t u m P i x e l s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExportQuantumPixels() transfers one or more pixel components from the image
+%  pixel cache to a user supplied buffer.  The pixels are returned in network
+%  byte order.  MagickTrue is returned if the pixels are successfully
+%  transferred, otherwise MagickFalse.
+%
+%  The format of the ExportQuantumPixels method is:
+%
+%      size_t ExportQuantumPixels(const Image *image,
+%        const CacheView *image_view,const QuantumInfo *quantum_info,
+%        const QuantumType quantum_type,unsigned char *pixels,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o image_view: the image cache view.
+%
+%    o quantum_info: the quantum info.
+%
+%    o quantum_type: Declare which pixel components to transfer (RGB, RGBA,
+%      etc).
+%
+%    o pixels:  The components are transferred to this buffer.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline unsigned char *PopDoublePixel(const QuantumState *quantum_state,
+  const double pixel,unsigned char *pixels)
+{
+  double
+    *p;
+
+  unsigned char
+    quantum[8];
+
+  p=(double *) quantum;
+  *p=(double) (pixel*quantum_state->inverse_scale+quantum_state->minimum);
+  if (quantum_state->endian != LSBEndian)
+    {
+      *pixels++=quantum[7];
+      *pixels++=quantum[6];
+      *pixels++=quantum[5];
+      *pixels++=quantum[4];
+      *pixels++=quantum[3];
+      *pixels++=quantum[2];
+      *pixels++=quantum[1];
+      *pixels++=quantum[0];
+      return(pixels);
+    }
+  *pixels++=quantum[0];
+  *pixels++=quantum[1];
+  *pixels++=quantum[2];
+  *pixels++=quantum[3];
+  *pixels++=quantum[4];
+  *pixels++=quantum[5];
+  *pixels++=quantum[6];
+  *pixels++=quantum[7];
+  return(pixels);
+}
+
+static inline unsigned char *PopFloatPixel(const QuantumState *quantum_state,
+  const float pixel,unsigned char *pixels)
+{
+  float
+    *p;
+
+  unsigned char
+    quantum[4];
+
+  p=(float *) quantum;
+  *p=(float) ((double) pixel*quantum_state->inverse_scale+
+    quantum_state->minimum);
+  if (quantum_state->endian != LSBEndian)
+    {
+      *pixels++=quantum[3];
+      *pixels++=quantum[2];
+      *pixels++=quantum[1];
+      *pixels++=quantum[0];
+      return(pixels);
+    }
+  *pixels++=quantum[0];
+  *pixels++=quantum[1];
+  *pixels++=quantum[2];
+  *pixels++=quantum[3];
+  return(pixels);
+}
+
+static inline unsigned char *PopQuantumPixel(QuantumState *quantum_state,
+  const size_t depth,const QuantumAny pixel,unsigned char *pixels)
+{
+  register ssize_t
+    i;
+
+  size_t
+    quantum_bits;
+
+  if (quantum_state->bits == 0UL)
+    quantum_state->bits=8U;
+  for (i=(ssize_t) depth; i > 0L; )
+  {
+    quantum_bits=(size_t) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    i-=(ssize_t) quantum_bits;
+    if (quantum_state->bits == 8UL)
+      *pixels='\0';
+    quantum_state->bits-=quantum_bits;
+    *pixels|=(((pixel >> i) &~ ((~0UL) << quantum_bits)) <<
+      quantum_state->bits);
+    if (quantum_state->bits == 0UL)
+      {
+        pixels++;
+        quantum_state->bits=8UL;
+      }
+  }
+  return(pixels);
+}
+
+static inline unsigned char *PopQuantumLongPixel(QuantumState *quantum_state,
+  const size_t depth,const size_t pixel,unsigned char *pixels)
+{
+  register ssize_t
+    i;
+
+  size_t
+    quantum_bits;
+
+  if (quantum_state->bits == 0U)
+    quantum_state->bits=32UL;
+  for (i=(ssize_t) depth; i > 0; )
+  {
+    quantum_bits=(size_t) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    quantum_state->pixel|=(((pixel >> (depth-i)) &
+      quantum_state->mask[quantum_bits]) << (32U-quantum_state->bits));
+    i-=(ssize_t) quantum_bits;
+    quantum_state->bits-=quantum_bits;
+    if (quantum_state->bits == 0U)
+      {
+        pixels=PopLongPixel(quantum_state->endian,quantum_state->pixel,pixels);
+        quantum_state->pixel=0U;
+        quantum_state->bits=32U;
+      }
+  }
+  return(pixels);
+}
+
+MagickExport size_t ExportQuantumPixels(Image *image,CacheView *image_view,
+  const QuantumInfo *quantum_info,const QuantumType quantum_type,
+  unsigned char *pixels,ExceptionInfo *exception)
+{
+  EndianType
+    endian;
+
+  MagickRealType
+    alpha;
+
+  MagickSizeType
+    number_pixels;
+
+  QuantumAny
+    range;
+
+  QuantumState
+    quantum_state;
+
+  register const Quantum
+    *restrict p;
+
+  register ssize_t
+    x;
+
+  register unsigned char
+    *restrict q;
+
+  size_t
+    channels,
+    extent;
+
+  ssize_t
+    bit;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  if (pixels == (unsigned char *) NULL)
+    pixels=GetQuantumPixels(quantum_info);
+  if (image_view == (CacheView *) NULL)
+    {
+      number_pixels=GetImageExtent(image);
+      p=GetVirtualPixelQueue(image);
+      channels=GetPixelChannels(image);
+    }
+  else
+    {
+      number_pixels=GetCacheViewExtent(image_view);
+      p=GetCacheViewVirtualPixelQueue(image_view);
+      channels=GetPixelChannels(image);
+    }
+  if (quantum_info->alpha_type == AssociatedQuantumAlpha)
+    {
+      register Quantum
+        *restrict q;
+
+      /*
+        Associate alpha.
+      */
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        alpha=QuantumScale*GetPixelAlpha(image,q);
+        SetPixelRed(image,ClampToQuantum(alpha*GetPixelRed(image,q)),q);
+        SetPixelGreen(image,ClampToQuantum(alpha*GetPixelGreen(image,q)),q);
+        SetPixelBlue(image,ClampToQuantum(alpha*GetPixelBlue(image,q)),q);
+        q++;
+      }
+    }
+  if ((quantum_type == RGBOQuantum) || (quantum_type == CMYKOQuantum) ||
+      (quantum_type == BGROQuantum))
+    {
+      register Quantum
+        *restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        SetPixelAlpha(image,GetPixelAlpha(image,q),q);
+        q++;
+      }
+    }
+  if ((quantum_type == CbYCrQuantum) || (quantum_type == CbYCrAQuantum))
+    {
+      Quantum
+        quantum;
+
+      register Quantum
+        *restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetAuthenticPixelQueue(image);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        quantum=GetPixelRed(image,q);
+        SetPixelRed(image,GetPixelGreen(image,q),q);
+        SetPixelGreen(image,quantum,q);
+        q+=channels;
+      }
+    }
+  x=0;
+  q=pixels;
+  InitializeQuantumState(quantum_info,image->endian,&quantum_state);
+  extent=GetQuantumExtent(image,quantum_info,quantum_type);
+  endian=quantum_state.endian;
+  switch (quantum_type)
+  {
+    case IndexQuantum:
+    {
+      if (image->storage_class != PseudoClass)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColormappedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=((ssize_t) number_pixels-7); x > 0; x-=8)
+          {
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q=((pixel & 0x01) << 7);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 6);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 5);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 4);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 3);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 2);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 1);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 0);
+            p+=channels;
+            q++;
+          }
+          if ((number_pixels % 8) != 0)
+            {
+              *q='\0';
+              for (bit=7; bit >= (ssize_t) (8-(number_pixels % 8)); bit--)
+              {
+                pixel=(unsigned char) GetPixelIndex(image,p);
+                *q|=((pixel & 0x01) << (unsigned char) bit);
+                p+=channels;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) (number_pixels-1) ; x+=2)
+          {
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q=((pixel & 0xf) << 4);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0xf) << 0);
+            p+=channels;
+            q++;
+          }
+          if ((number_pixels % 2) != 0)
+            {
+              pixel=(unsigned char) GetPixelIndex(image,p);
+              *q=((pixel & 0xf) << 4);
+              p+=channels;
+              q++;
+            }
+          break;
+        }
+        case 8:
+        {
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopCharPixel((unsigned char) GetPixelIndex(image,p),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopShortPixel(endian,SinglePrecisionToHalf(QuantumScale*
+                  GetPixelIndex(image,p)),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopShortPixel(endian,(unsigned short) GetPixelIndex(image,p),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelIndex(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopLongPixel(endian,(unsigned int) GetPixelIndex(image,p),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelIndex(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              GetPixelIndex(image,p),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case IndexAlphaQuantum:
+    {
+      if (image->storage_class != PseudoClass)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColormappedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=((ssize_t) number_pixels-3); x > 0; x-=4)
+          {
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q=((pixel & 0x01) << 7);
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == (Quantum)
+              TransparentAlpha ? 1 : 0);
+            *q|=((pixel & 0x01) << 6);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 5);
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == (Quantum)
+              TransparentAlpha ? 1 : 0);
+            *q|=((pixel & 0x01) << 4);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 3);
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == (Quantum)
+              TransparentAlpha ? 1 : 0);
+            *q|=((pixel & 0x01) << 2);
+            p+=channels;
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q|=((pixel & 0x01) << 1);
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == (Quantum)
+              TransparentAlpha ? 1 : 0);
+            *q|=((pixel & 0x01) << 0);
+            p+=channels;
+            q++;
+          }
+          if ((number_pixels % 4) != 0)
+            {
+              *q='\0';
+              for (bit=3; bit >= (ssize_t) (4-(number_pixels % 4)); bit-=2)
+              {
+                pixel=(unsigned char) GetPixelIndex(image,p);
+                *q|=((pixel & 0x01) << (unsigned char) (bit+4));
+                pixel=(unsigned char) (GetPixelAlpha(image,p) == (Quantum)
+                  TransparentAlpha ? 1 : 0);
+                *q|=((pixel & 0x01) << (unsigned char) (bit+4-1));
+                p+=channels;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels ; x++)
+          {
+            pixel=(unsigned char) GetPixelIndex(image,p);
+            *q=((pixel & 0xf) << 4);
+            pixel=(unsigned char) (16*QuantumScale*GetPixelAlpha(image,p)+0.5);
+            *q|=((pixel & 0xf) << 0);
+            p+=channels;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopCharPixel((unsigned char) GetPixelIndex(image,p),q);
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopShortPixel(endian,(unsigned short)
+                  GetPixelIndex(image,p),q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopShortPixel(endian,(unsigned short) GetPixelIndex(image,p),q);
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelIndex(image,p),q);
+                pixel=(float)  GetPixelAlpha(image,p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopLongPixel(endian,(unsigned int) GetPixelIndex(image,p),q);
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelIndex(image,p),q);
+                pixel=(double) GetPixelAlpha(image,p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              GetPixelIndex(image,p),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BGRQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopCharPixel(ScaleQuantumToChar(GetPixelBlue(image,p)),q);
+            q=PopCharPixel(ScaleQuantumToChar(GetPixelGreen(image,p)),q);
+            q=PopCharPixel(ScaleQuantumToChar(GetPixelRed(image,p)),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          register unsigned int
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) (
+                  ScaleQuantumToAny(GetPixelRed(image,p),range) << 22 |
+                  ScaleQuantumToAny(GetPixelGreen(image,p),range) << 12 |
+                  ScaleQuantumToAny(GetPixelBlue(image,p),range) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 12:
+        {
+          register unsigned int
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) (3*number_pixels-1); x+=2)
+              {
+                switch (x % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelRed(image,p),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelGreen(image,p),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelBlue(image,p),range);
+                    p+=channels;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                switch ((x+1) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelRed(image,p),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelGreen(image,p),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelBlue(image,p),range);
+                    p+=channels;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                q+=quantum_info->pad;
+              }
+              for (bit=0; bit < (ssize_t) (3*number_pixels % 2); bit++)
+              {
+                switch ((x+bit) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelRed(image,p),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelGreen(image,p),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelBlue(image,p),range);
+                    p+=channels;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                q+=quantum_info->pad;
+              }
+              if (bit != 0)
+                p+=channels;
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BGRAQuantum:
+    case BGROQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelBlue(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelGreen(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelRed(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          register unsigned int
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              register ssize_t
+                i;
+
+              size_t
+                quantum;
+
+              ssize_t
+                n;
+
+              n=0;
+              quantum=0;
+              pixel=0;
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (i)
+                  {
+                    case 0: quantum=GetPixelRed(image,p); break;
+                    case 1: quantum=GetPixelGreen(image,p); break;
+                    case 2: quantum=GetPixelBlue(image,p); break;
+                    case 3: quantum=GetPixelAlpha(image,p); break;
+                  }
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      pixel|=(size_t) (ScaleQuantumToAny((Quantum) quantum,
+                        range) << 22);
+                      break;
+                    }
+                    case 1:
+                    {
+                      pixel|=(size_t) (ScaleQuantumToAny((Quantum) quantum,
+                        range) << 12);
+                      break;
+                    }
+                    case 2:
+                    {
+                      pixel|=(size_t) (ScaleQuantumToAny((Quantum) quantum,
+                        range) << 2);
+                      q=PopLongPixel(endian,pixel,q);
+                      pixel=0;
+                      break;
+                    }
+                  }
+                  n++;
+                }
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelAlpha(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelAlpha(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                pixel=(float) GetPixelAlpha(image,p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                pixel=(double) GetPixelAlpha(image,p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GrayQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register Quantum
+            threshold;
+
+          register unsigned char
+            black,
+            white;
+
+          black=0x00;
+          white=0x01;
+          if (quantum_info->min_is_white != MagickFalse)
+            {
+              black=0x01;
+              white=0x00;
+            }
+          threshold=(Quantum) (QuantumRange/2);
+          for (x=((ssize_t) number_pixels-7); x > 0; x-=8)
+          {
+            *q='\0';
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 7;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 6;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 5;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 4;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 3;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 2;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 1;
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) < threshold ? black : white) << 0;
+            p+=channels;
+            q++;
+          }
+          if ((number_pixels % 8) != 0)
+            {
+              *q='\0';
+              for (bit=7; bit >= (ssize_t) (8-(number_pixels % 8)); bit--)
+              {
+                *q|=(GetPixelIntensity(image,p) < threshold ? black : white) <<
+                  bit;
+                p+=channels;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) (number_pixels-1) ; x+=2)
+          {
+            pixel=ScaleQuantumToChar(GetPixelIntensity(image,p));
+            *q=(((pixel >> 4) & 0xf) << 4);
+            p+=channels;
+            pixel=ScaleQuantumToChar(GetPixelIntensity(image,p));
+            *q|=pixel >> 4;
+            p+=channels;
+            q++;
+          }
+          if ((number_pixels % 2) != 0)
+            {
+              pixel=ScaleQuantumToChar(GetPixelIntensity(image,p));
+              *q=(((pixel >> 4) & 0xf) << 4);
+              p+=channels;
+              q++;
+            }
+          break;
+        }
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelIntensity(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              register unsigned int
+                pixel;
+
+              for (x=0; x < (ssize_t) (number_pixels-2); x+=3)
+              {
+                pixel=(unsigned int) (
+                  ScaleQuantumToAny(GetPixelIntensity(image,p+2),range) << 22 |
+                  ScaleQuantumToAny(GetPixelIntensity(image,p+1),range) << 12 |
+                  ScaleQuantumToAny(GetPixelIntensity(image,p+0),range) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p+=3;
+                q+=quantum_info->pad;
+              }
+              pixel=0UL;
+              if (x++ < (ssize_t) (number_pixels-1))
+                pixel|=ScaleQuantumToAny(GetPixelIntensity(image,p+1),
+                  range) << 12;
+              if (x++ < (ssize_t) number_pixels)
+                pixel|=ScaleQuantumToAny(GetPixelIntensity(image,p+0),
+                  range) << 2;
+              q=PopLongPixel(endian,pixel,q);
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelIntensity(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 12:
+        {
+          register unsigned short
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=ScaleQuantumToShort(GetPixelIntensity(image,p));
+                q=PopShortPixel(endian,(unsigned short) (pixel >> 4),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelIntensity(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelIntensity(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelIntensity(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                pixel=(float) GetPixelIntensity(image,p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelIntensity(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                pixel=(double) GetPixelIntensity(image,p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelIntensity(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GrayAlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register Quantum
+            threshold;
+
+          register unsigned char
+            black,
+            pixel,
+            white;
+
+          black=0x00;
+          white=0x01;
+          if (quantum_info->min_is_white == MagickFalse)
+            {
+              black=0x01;
+              white=0x00;
+            }
+          threshold=(Quantum) (QuantumRange/2);
+          for (x=((ssize_t) number_pixels-3); x > 0; x-=4)
+          {
+            *q='\0';
+            *q|=(GetPixelIntensity(image,p) > threshold ? black : white) << 7;
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == OpaqueAlpha ?
+              0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 6);
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) > threshold ? black : white) << 5;
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == OpaqueAlpha ?
+              0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 4);
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) > threshold ? black : white) << 3;
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == OpaqueAlpha ?
+              0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 2);
+            p+=channels;
+            *q|=(GetPixelIntensity(image,p) > threshold ? black : white) << 1;
+            pixel=(unsigned char) (GetPixelAlpha(image,p) == OpaqueAlpha ?
+              0x00 : 0x01);
+            *q|=(((int) pixel != 0 ? 0x00 : 0x01) << 0);
+            p+=channels;
+            q++;
+          }
+          if ((number_pixels % 4) != 0)
+            {
+              *q='\0';
+              for (bit=0; bit <= (ssize_t) (number_pixels % 4); bit+=2)
+              {
+                *q|=(GetPixelIntensity(image,p) > threshold ? black : white) <<
+                  (7-bit);
+                pixel=(unsigned char) (GetPixelAlpha(image,p) == OpaqueAlpha ?
+                  0x00 : 0x01);
+                *q|=(((int) pixel != 0 ? 0x00 : 0x01) << (unsigned char)
+                  (7-bit-1));
+                p+=channels;
+              }
+              q++;
+            }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels ; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelIntensity(image,p));
+            *q=(((pixel >> 4) & 0xf) << 4);
+            pixel=(unsigned char) (16*QuantumScale*GetPixelAlpha(image,p)+0.5);
+            *q|=pixel & 0xf;
+            p+=channels;
+            q++;
+          }
+          break;
+        }
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelIntensity(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelIntensity(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelIntensity(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                pixel=(float) GetPixelIntensity(image,p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                pixel=(float) (GetPixelAlpha(image,p));
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelIntensity(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                pixel=(double) GetPixelIntensity(image,p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                pixel=(double) (GetPixelAlpha(image,p));
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelIntensity(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RedQuantum:
+    case CyanQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelRed(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GreenQuantum:
+    case MagentaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelGreen(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BlueQuantum:
+    case YellowQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelBlue(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case AlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                pixel=(float) GetPixelAlpha(image,p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                double
+                  pixel;
+
+                pixel=(double) (GetPixelAlpha(image,p));
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case OpacityQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelAlpha(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelAlpha(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BlackQuantum:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColorSeparatedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelBlack(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlack(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelBlack(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlack(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelBlack(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlack(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny((Quantum) GetPixelBlack(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBQuantum:
+    case CbYCrQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopCharPixel(ScaleQuantumToChar(GetPixelRed(image,p)),q);
+            q=PopCharPixel(ScaleQuantumToChar(GetPixelGreen(image,p)),q);
+            q=PopCharPixel(ScaleQuantumToChar(GetPixelBlue(image,p)),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          register unsigned int
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) (
+                  ScaleQuantumToAny(GetPixelRed(image,p),range) << 22 |
+                  ScaleQuantumToAny(GetPixelGreen(image,p),range) << 12 |
+                  ScaleQuantumToAny(GetPixelBlue(image,p),range) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 12:
+        {
+          register unsigned int
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) (3*number_pixels-1); x+=2)
+              {
+                switch (x % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelRed(image,p),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelGreen(image,p),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelBlue(image,p),range);
+                    p+=channels;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                switch ((x+1) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelRed(image,p),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelGreen(image,p),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelBlue(image,p),range);
+                    p+=channels;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                q+=quantum_info->pad;
+              }
+              for (bit=0; bit < (ssize_t) (3*number_pixels % 2); bit++)
+              {
+                switch ((x+bit) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelRed(image,p),range);
+                    break;
+                  }
+                  case 1:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelGreen(image,p),range);
+                    break;
+                  }
+                  case 2:
+                  {
+                    pixel=(unsigned int) ScaleQuantumToAny(
+                      GetPixelBlue(image,p),range);
+                    p+=channels;
+                    break;
+                  }
+                }
+                q=PopShortPixel(endian,(unsigned short) (pixel << 4),q);
+                q+=quantum_info->pad;
+              }
+              if (bit != 0)
+                p+=channels;
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+              range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBAQuantum:
+    case RGBOQuantum:
+    case CbYCrAQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelRed(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelGreen(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelBlue(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 10:
+        {
+          register unsigned int
+            pixel;
+
+          range=GetQuantumRange(quantum_info->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              register ssize_t
+                i;
+
+              size_t
+                quantum;
+
+              ssize_t
+                n;
+
+              n=0;
+              quantum=0;
+              pixel=0;
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (i)
+                  {
+                    case 0: quantum=GetPixelRed(image,p); break;
+                    case 1: quantum=GetPixelGreen(image,p); break;
+                    case 2: quantum=GetPixelBlue(image,p); break;
+                    case 3: quantum=GetPixelAlpha(image,p); break;
+                  }
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      pixel|=(size_t) (ScaleQuantumToAny((Quantum) quantum,
+                        range) << 22);
+                      break;
+                    }
+                    case 1:
+                    {
+                      pixel|=(size_t) (ScaleQuantumToAny((Quantum) quantum,
+                        range) << 12);
+                      break;
+                    }
+                    case 2:
+                    {
+                      pixel|=(size_t) (ScaleQuantumToAny((Quantum) quantum,
+                        range) << 2);
+                      q=PopLongPixel(endian,pixel,q);
+                      pixel=0;
+                      break;
+                    }
+                  }
+                  n++;
+                }
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32UL)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelRed(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelGreen(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelBlue(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                pixel=(unsigned int) ScaleQuantumToAny(GetPixelAlpha(image,p),
+                  range);
+                q=PopQuantumLongPixel(&quantum_state,quantum_info->depth,pixel,
+                  q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned int) ScaleQuantumToAny(
+              GetPixelRed(image,p),range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(
+              GetPixelGreen(image,p),range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(
+              GetPixelBlue(image,p),range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            pixel=(unsigned int) ScaleQuantumToAny(
+              GetPixelAlpha(image,p),range);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                pixel=(float) GetPixelAlpha(image,p);
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                pixel=(double) GetPixelAlpha(image,p);
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CMYKQuantum:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColorSeparatedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelRed(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelGreen(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelBlue(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelBlack(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlack(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelBlack(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlack(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelBlack(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlack(image,p),q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlack(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CMYKAQuantum:
+    case CMYKOQuantum:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColorSeparatedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToChar(GetPixelRed(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelGreen(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelBlue(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelBlack(image,p));
+            q=PopCharPixel(pixel,q);
+            pixel=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            q=PopCharPixel(pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 16:
+        {
+          register unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelRed(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelGreen(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlue(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelBlack(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                pixel=SinglePrecisionToHalf(QuantumScale*
+                  GetPixelAlpha(image,p));
+                q=PopShortPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToShort(GetPixelRed(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelGreen(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelBlue(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelBlack(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            pixel=ScaleQuantumToShort(GetPixelAlpha(image,p));
+            q=PopShortPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 32:
+        {
+          register unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                float
+                  pixel;
+
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelRed(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelGreen(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlue(image,p),q);
+                q=PopFloatPixel(&quantum_state,(float)
+                  GetPixelBlack(image,p),q);
+                pixel=(float) (GetPixelAlpha(image,p));
+                q=PopFloatPixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=ScaleQuantumToLong(GetPixelRed(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelGreen(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelBlue(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelBlack(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            pixel=ScaleQuantumToLong(GetPixelAlpha(image,p));
+            q=PopLongPixel(endian,pixel,q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelRed(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelGreen(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlue(image,p),q);
+                q=PopDoublePixel(&quantum_state,(double)
+                  GetPixelBlack(image,p),q);
+                pixel=(double) (GetPixelAlpha(image,p));
+                q=PopDoublePixel(&quantum_state,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(quantum_info->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelRed(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelGreen(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlue(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelBlack(image,p),range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(GetPixelAlpha(image,p),range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CbYCrYQuantum:
+    {
+      Quantum
+        cbcr[4];
+
+      register ssize_t
+        i;
+
+      register unsigned int
+        pixel;
+
+      size_t
+        quantum;
+
+     ssize_t
+        n;
+
+      n=0;
+      quantum=0;
+      range=GetQuantumRange(quantum_info->depth);
+      switch (quantum_info->depth)
+      {
+        case 10:
+        {
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x+=2)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      quantum=GetPixelRed(image,p);
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=GetPixelGreen(image,p);
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=GetPixelBlue(image,p);
+                      break;
+                    }
+                  }
+                  cbcr[i]=(Quantum) quantum;
+                  n++;
+                }
+                pixel=(unsigned int) ((size_t) (cbcr[1]) << 22 | (size_t)
+                  (cbcr[0]) << 12 | (size_t) (cbcr[2]) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p+=channels;
+                pixel=(unsigned int) ((size_t) (cbcr[3]) << 22 | (size_t)
+                  (cbcr[0]) << 12 | (size_t) (cbcr[2]) << 2);
+                q=PopLongPixel(endian,pixel,q);
+                p+=channels;
+                q+=quantum_info->pad;
+              }
+              break;
+            }
+          break;
+        }
+        default:
+        {
+          for (x=0; x < (ssize_t) number_pixels; x+=2)
+          {
+            for (i=0; i < 4; i++)
+            {
+              switch (n % 3)
+              {
+                case 0:
+                {
+                  quantum=GetPixelRed(image,p);
+                  break;
+                }
+                case 1:
+                {
+                  quantum=GetPixelGreen(image,p);
+                  break;
+                }
+                case 2:
+                {
+                  quantum=GetPixelBlue(image,p);
+                  break;
+                }
+              }
+              cbcr[i]=(Quantum) quantum;
+              n++;
+            }
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(cbcr[1],range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(cbcr[0],range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(cbcr[2],range),q);
+            p+=channels;
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(cbcr[3],range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(cbcr[0],range),q);
+            q=PopQuantumPixel(&quantum_state,quantum_info->depth,
+              ScaleQuantumToAny(cbcr[2],range),q);
+            p+=channels;
+            q+=quantum_info->pad;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((quantum_type == CbYCrQuantum) || (quantum_type == CbYCrAQuantum))
+    {
+      Quantum
+        quantum;
+
+      register Quantum
+        *restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        quantum=GetPixelRed(image,q);
+        SetPixelRed(image,GetPixelGreen(image,q),q);
+        SetPixelGreen(image,quantum,q);
+        q+=channels;
+      }
+    }
+  if ((quantum_type == RGBOQuantum) || (quantum_type == CMYKOQuantum) ||
+      (quantum_type == BGROQuantum))
+    {
+      register Quantum
+        *restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        SetPixelAlpha(image,GetPixelAlpha(image,q),q);
+        q+=channels;
+      }
+    }
+  return(extent);
+}
diff --git a/MagickCore/quantum-import.c b/MagickCore/quantum-import.c
new file mode 100644
index 0000000..0da2d48
--- /dev/null
+++ b/MagickCore/quantum-import.c
@@ -0,0 +1,3353 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                QQQ   U   U   AAA   N   N  TTTTT  U   U  M   M               %
+%               Q   Q  U   U  A   A  NN  N    T    U   U  MM MM               %
+%               Q   Q  U   U  AAAAA  N N N    T    U   U  M M M               %
+%               Q  QQ  U   U  A   A  N  NN    T    U   U  M   M               %
+%                QQQQ   UUU   A   A  N   N    T     UUU   M   M               %
+%                                                                             %
+%                   IIIII  M   M  PPPP    OOO   RRRR   TTTTT                  %
+%                     I    MM MM  P   P  O   O  R   R    T                    %
+%                     I    M M M  PPPP   O   O  RRRR     T                    %
+%                     I    M   M  P      O   O  R R      T                    %
+%                   IIIII  M   M  P       OOO   R  R     T                    %
+%                                                                             %
+%                 MagickCore Methods to Import Quantum Pixels                 %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               October 1998                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I m p o r t Q u a n t u m P i x e l s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ImportQuantumPixels() transfers one or more pixel components from a user
+%  supplied buffer into the image pixel cache of an image.  The pixels are
+%  expected in network byte order.  It returns MagickTrue if the pixels are
+%  successfully transferred, otherwise MagickFalse.
+%
+%  The format of the ImportQuantumPixels method is:
+%
+%      size_t ImportQuantumPixels(Image *image,CacheView *image_view,
+%        const QuantumInfo *quantum_info,const QuantumType quantum_type,
+%        const unsigned char *pixels,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o image_view: the image cache view.
+%
+%    o quantum_info: the quantum info.
+%
+%    o quantum_type: Declare which pixel components to transfer (red, green,
+%      blue, opacity, RGB, or RGBA).
+%
+%    o pixels:  The pixel components are transferred from this buffer.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline Quantum PushColormapIndex(Image *image,
+  const size_t index,MagickBooleanType *range_exception)
+{
+  if (index < image->colors)
+    return((Quantum) index);
+  *range_exception=MagickTrue;
+  return((Quantum) 0);
+}
+
+static inline const unsigned char *PushDoublePixel(
+  const QuantumState *quantum_state,const unsigned char *pixels,double *pixel)
+{
+  double
+    *p;
+
+  unsigned char
+    quantum[8];
+
+  if (quantum_state->endian != LSBEndian)
+    {
+      quantum[7]=(*pixels++);
+      quantum[6]=(*pixels++);
+      quantum[5]=(*pixels++);
+      quantum[5]=(*pixels++);
+      quantum[3]=(*pixels++);
+      quantum[2]=(*pixels++);
+      quantum[1]=(*pixels++);
+      quantum[0]=(*pixels++);
+      p=(double *) quantum;
+      *pixel=(*p);
+      *pixel-=quantum_state->minimum;
+      *pixel*=quantum_state->scale;
+      return(pixels);
+    }
+  quantum[0]=(*pixels++);
+  quantum[1]=(*pixels++);
+  quantum[2]=(*pixels++);
+  quantum[3]=(*pixels++);
+  quantum[4]=(*pixels++);
+  quantum[5]=(*pixels++);
+  quantum[6]=(*pixels++);
+  quantum[7]=(*pixels++);
+  p=(double *) quantum;
+  *pixel=(*p);
+  *pixel-=quantum_state->minimum;
+  *pixel*=quantum_state->scale;
+  return(pixels);
+}
+
+static inline const unsigned char *PushFloatPixel(
+  const QuantumState *quantum_state,const unsigned char *pixels,float *pixel)
+{
+  float
+    *p;
+
+  unsigned char
+    quantum[4];
+
+  if (quantum_state->endian != LSBEndian)
+    {
+      quantum[3]=(*pixels++);
+      quantum[2]=(*pixels++);
+      quantum[1]=(*pixels++);
+      quantum[0]=(*pixels++);
+      p=(float *) quantum;
+      *pixel=(*p);
+      *pixel-=quantum_state->minimum;
+      *pixel*=quantum_state->scale;
+      return(pixels);
+    }
+  quantum[0]=(*pixels++);
+  quantum[1]=(*pixels++);
+  quantum[2]=(*pixels++);
+  quantum[3]=(*pixels++);
+  p=(float *) quantum;
+  *pixel=(*p);
+  *pixel-=quantum_state->minimum;
+  *pixel*=quantum_state->scale;
+  return(pixels);
+}
+
+static inline const unsigned char *PushQuantumPixel(
+  QuantumState *quantum_state,const size_t depth,
+  const unsigned char *pixels,unsigned int *quantum)
+{
+  register ssize_t
+    i;
+
+  register size_t
+    quantum_bits;
+
+  *quantum=(QuantumAny) 0;
+  for (i=(ssize_t) depth; i > 0L; )
+  {
+    if (quantum_state->bits == 0UL)
+      {
+        quantum_state->pixel=(*pixels++);
+        quantum_state->bits=8UL;
+      }
+    quantum_bits=(size_t) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    i-=(ssize_t) quantum_bits;
+    quantum_state->bits-=quantum_bits;
+    *quantum=(unsigned int) ((*quantum << quantum_bits) |
+      ((quantum_state->pixel >> quantum_state->bits) &~ ((~0UL) <<
+      quantum_bits)));
+  }
+  return(pixels);
+}
+
+static inline const unsigned char *PushQuantumLongPixel(
+  QuantumState *quantum_state,const size_t depth,
+  const unsigned char *pixels,unsigned int *quantum)
+{
+  register ssize_t
+    i;
+
+  register size_t
+    quantum_bits;
+
+  *quantum=0UL;
+  for (i=(ssize_t) depth; i > 0; )
+  {
+    if (quantum_state->bits == 0)
+      {
+        pixels=PushLongPixel(quantum_state->endian,pixels,
+          &quantum_state->pixel);
+        quantum_state->bits=32U;
+      }
+    quantum_bits=(size_t) i;
+    if (quantum_bits > quantum_state->bits)
+      quantum_bits=quantum_state->bits;
+    *quantum|=(((quantum_state->pixel >> (32U-quantum_state->bits)) &
+      quantum_state->mask[quantum_bits]) << (depth-i));
+    i-=(ssize_t) quantum_bits;
+    quantum_state->bits-=quantum_bits;
+  }
+  return(pixels);
+}
+
+MagickExport size_t ImportQuantumPixels(Image *image,CacheView *image_view,
+  const QuantumInfo *quantum_info,const QuantumType quantum_type,
+  const unsigned char *pixels,ExceptionInfo *exception)
+{
+  EndianType
+    endian;
+
+  MagickSizeType
+    number_pixels;
+
+  QuantumAny
+    range;
+
+  QuantumState
+    quantum_state;
+
+  register const unsigned char
+    *restrict p;
+
+  register ssize_t
+    x;
+
+  register Quantum
+    *restrict q;
+
+  size_t
+    channels,
+    extent;
+
+  ssize_t
+    bit;
+
+  unsigned int
+    pixel;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  if (pixels == (const unsigned char *) NULL)
+    pixels=GetQuantumPixels(quantum_info);
+  x=0;
+  p=pixels;
+  if (image_view == (CacheView *) NULL)
+    {
+      number_pixels=GetImageExtent(image);
+      q=GetAuthenticPixelQueue(image);
+      channels=GetPixelChannels(image);
+    }
+  else
+    {
+      number_pixels=GetCacheViewExtent(image_view);
+      q=GetCacheViewAuthenticPixelQueue(image_view);
+      channels=GetPixelChannels(image);
+    }
+  InitializeQuantumState(quantum_info,image->endian,&quantum_state);
+  extent=GetQuantumExtent(image,quantum_info,quantum_type);
+  endian=quantum_state.endian;
+  switch (quantum_type)
+  {
+    case IndexQuantum:
+    {
+      MagickBooleanType
+        range_exception;
+
+      if (image->storage_class != PseudoClass)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColormappedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      range_exception=MagickFalse;
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < ((ssize_t) number_pixels-7); x+=8)
+          {
+            for (bit=0; bit < 8; bit++)
+            {
+              if (quantum_info->min_is_white == MagickFalse)
+                pixel=(unsigned char) (((*p) & (1 << (7-bit))) == 0 ?
+                  0x00 : 0x01);
+              else
+                pixel=(unsigned char) (((*p) & (1 << (7-bit))) != 0 ?
+                  0x00 : 0x01);
+              SetPixelIndex(image,PushColormapIndex(image,pixel,
+                &range_exception),q);
+              SetPixelPacket(image,image->colormap+(ssize_t)
+                GetPixelIndex(image,q),q);
+              q+=channels;
+            }
+            p++;
+          }
+          for (bit=0; bit < (ssize_t) (number_pixels % 8); bit++)
+          {
+            if (quantum_info->min_is_white == MagickFalse)
+              pixel=(unsigned char) (((*p) & (1 << (7-bit))) == 0 ?
+                0x00 : 0x01);
+            else
+              pixel=(unsigned char) (((*p) & (1 << (7-bit))) != 0 ?
+                0x00 : 0x01);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < ((ssize_t) number_pixels-1); x+=2)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            q+=channels;
+            pixel=(unsigned char) ((*p) & 0xf);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p++;
+            q+=channels;
+          }
+          for (bit=0; bit < (ssize_t) (number_pixels % 2); bit++)
+          {
+            pixel=(unsigned char) ((*p++ >> 4) & 0xf);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelIndex(image,PushColormapIndex(image,ClampToQuantum(
+                  (MagickRealType) QuantumRange*HalfToSinglePrecision(pixel)),
+                  &range_exception),q);
+                SetPixelPacket(image,image->colormap+(ssize_t)
+                  GetPixelIndex(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelIndex(image,PushColormapIndex(image,
+                  ClampToQuantum(pixel),&range_exception),q);
+                SetPixelPacket(image,image->colormap+(ssize_t)
+                  GetPixelIndex(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelIndex(image,PushColormapIndex(image,
+                  ClampToQuantum(pixel),&range_exception),q);
+                SetPixelPacket(image,image->colormap+(ssize_t)
+                  GetPixelIndex(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      if (range_exception != MagickFalse)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+      break;
+    }
+    case IndexAlphaQuantum:
+    {
+      MagickBooleanType
+        range_exception;
+
+      if (image->storage_class != PseudoClass)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ImageError,"ColormappedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      range_exception=MagickFalse;
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < ((ssize_t) number_pixels-3); x+=4)
+          {
+            for (bit=0; bit < 8; bit+=2)
+            {
+              if (quantum_info->min_is_white == MagickFalse)
+                pixel=(unsigned char) (((*p) & (1 << (7-bit))) == 0 ?
+                  0x00 : 0x01);
+              else
+                pixel=(unsigned char) (((*p) & (1 << (7-bit))) != 0 ?
+                  0x00 : 0x01);
+              SetPixelRed(image,(Quantum) (pixel == 0 ? 0 : QuantumRange),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              SetPixelAlpha(image,((*p) & (1UL << (unsigned char)
+                (6-bit))) == 0 ? TransparentAlpha : OpaqueAlpha,q);
+              SetPixelIndex(image,(Quantum) (pixel == 0 ? 0 : 1),q);
+              q+=channels;
+            }
+          }
+          for (bit=0; bit < (ssize_t) (number_pixels % 4); bit+=2)
+          {
+            if (quantum_info->min_is_white == MagickFalse)
+              pixel=(unsigned char) (((*p) & (1 << (7-bit))) == 0 ?
+                0x00 : 0x01);
+            else
+              pixel=(unsigned char) (((*p) & (1 << (7-bit))) != 0 ?
+                0x00 : 0x01);
+            SetPixelIndex(image,(Quantum) (pixel == 0 ? 0 : 1),q);
+            SetPixelRed(image,(Quantum) (pixel == 0 ? 0 : QuantumRange),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            SetPixelAlpha(image,((*p) & (1UL << (unsigned char)
+              (6-bit))) == 0 ? TransparentAlpha : OpaqueAlpha,q);
+            q+=channels;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            pixel=(unsigned char) ((*p) & 0xf);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p++;
+            q+=channels;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelAlpha(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelIndex(image,PushColormapIndex(image,ClampToQuantum(
+                  (MagickRealType) QuantumRange*HalfToSinglePrecision(pixel)),
+                  &range_exception),q);
+                SetPixelPacket(image,image->colormap+(ssize_t)
+                  GetPixelIndex(image,q),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelIndex(image,PushColormapIndex(image,
+                  ClampToQuantum(pixel),&range_exception),q);
+                SetPixelPacket(image,image->colormap+(ssize_t)
+                  GetPixelIndex(image,q),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelIndex(image,PushColormapIndex(image,
+                  ClampToQuantum(pixel),&range_exception),q);
+                SetPixelPacket(image,image->colormap+(ssize_t)
+                  GetPixelIndex(image,q),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelIndex(image,PushColormapIndex(image,pixel,
+              &range_exception),q);
+            SetPixelPacket(image,image->colormap+(ssize_t)
+              GetPixelIndex(image,q),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      if (range_exception != MagickFalse)
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          CorruptImageError,"InvalidColormapIndex","`%s'",image->filename);
+      break;
+    }
+    case BGRQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            SetPixelAlpha(image,OpaqueAlpha,q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushLongPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum((pixel >> 22) & 0x3ff,
+                  range),q);
+                SetPixelGreen(image,ScaleAnyToQuantum((pixel >> 12) & 0x3ff,
+                  range),q);
+                SetPixelBlue(image,ScaleAnyToQuantum((pixel >> 2) & 0x3ff,
+                  range),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32U)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              unsigned short
+                pixel;
+
+              for (x=0; x < (ssize_t) (3*number_pixels-1); x+=2)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                switch (x % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 1:
+                  {
+                    SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 2:
+                  {
+                    SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    q+=channels;
+                    break;
+                  }
+                }
+                p=PushShortPixel(endian,p,&pixel);
+                switch ((x+1) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 1:
+                  {
+                    SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 2:
+                  {
+                    SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    q+=channels;
+                    break;
+                  }
+                }
+                p+=quantum_info->pad;
+              }
+              for (bit=0; bit < (ssize_t) (3*number_pixels % 2); bit++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                switch ((x+bit) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 1:
+                  {
+                    SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 2:
+                  {
+                    SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    q+=channels;
+                    break;
+                  }
+                }
+                p+=quantum_info->pad;
+              }
+              if (bit != 0)
+                p++;
+              break;
+            }
+          if (quantum_info->quantum == 32U)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BGRAQuantum:
+    case BGROQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelAlpha(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 10:
+        {
+          pixel=0;
+          if (quantum_info->pack == MagickFalse)
+            {
+              register ssize_t
+                i;
+
+              size_t
+                quantum;
+
+              ssize_t
+                n;
+
+              n=0;
+              quantum=0;
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      p=PushLongPixel(endian,p,&pixel);
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 22) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 12) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 2) & 0x3ff) << 6)));
+                      break;
+                    }
+                  }
+                  switch (i)
+                  {
+                    case 0: SetPixelRed(image,(Quantum) quantum,q); break;
+                    case 1: SetPixelGreen(image,(Quantum) quantum,q); break;
+                    case 2: SetPixelBlue(image,(Quantum) quantum,q); break;
+                    case 3: SetPixelAlpha(image,(Quantum) quantum,q); break;
+                  }
+                  n++;
+                }
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GrayQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register Quantum
+            black,
+            white;
+
+          black=0;
+          white=(Quantum) QuantumRange;
+          if (quantum_info->min_is_white != MagickFalse)
+            {
+              black=(Quantum) QuantumRange;
+              white=0;
+            }
+          for (x=0; x < ((ssize_t) number_pixels-7); x+=8)
+          {
+            for (bit=0; bit < 8; bit++)
+            {
+              SetPixelRed(image,((*p) & (1 << (7-bit))) == 0 ? black :
+                white,q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              q+=channels;
+            }
+            p++;
+          }
+          for (bit=0; bit < (ssize_t) (number_pixels % 8); bit++)
+          {
+            SetPixelRed(image,((*p) & (0x01 << (7-bit))) == 0 ? black :
+              white,q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            q+=channels;
+          }
+          if (bit != 0)
+            p++;
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < ((ssize_t) number_pixels-1); x+=2)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            q+=channels;
+            pixel=(unsigned char) ((*p) & 0xf);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p++;
+            q+=channels;
+          }
+          for (bit=0; bit < (ssize_t) (number_pixels % 2); bit++)
+          {
+            pixel=(unsigned char) (*p++ >> 4);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          if (quantum_info->min_is_white != MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushCharPixel(p,&pixel);
+                SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                SetPixelAlpha(image,OpaqueAlpha,q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            SetPixelAlpha(image,OpaqueAlpha,q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              if (image->endian != LSBEndian)
+                {
+                  for (x=0; x < (ssize_t) (number_pixels-2); x+=3)
+                  {
+                    p=PushLongPixel(endian,p,&pixel);
+                    SetPixelRed(image,ScaleAnyToQuantum((pixel >> 2) & 0x3ff,
+                      range),q);
+                    SetPixelGreen(image,GetPixelRed(image,q),q);
+                    SetPixelBlue(image,GetPixelRed(image,q),q);
+                    q+=channels;
+                    SetPixelRed(image,ScaleAnyToQuantum((pixel >> 12) & 0x3ff,
+                      range),q);
+                    SetPixelGreen(image,GetPixelRed(image,q),q);
+                    SetPixelBlue(image,GetPixelRed(image,q),q);
+                    q+=channels;
+                    SetPixelRed(image,ScaleAnyToQuantum((pixel >> 22) & 0x3ff,
+                      range),q);
+                    SetPixelGreen(image,GetPixelRed(image,q),q);
+                    SetPixelBlue(image,GetPixelRed(image,q),q);
+                    p+=quantum_info->pad;
+                    q+=channels;
+                  }
+                  p=PushLongPixel(endian,p,&pixel);
+                  if (x++ < (ssize_t) (number_pixels-1))
+                    {
+                      SetPixelRed(image,ScaleAnyToQuantum((pixel >> 2) & 0x3ff,
+                        range),q);
+                      SetPixelGreen(image,GetPixelRed(image,q),q);
+                      SetPixelBlue(image,GetPixelRed(image,q),q);
+                      q+=channels;
+                    }
+                  if (x++ < (ssize_t) number_pixels)
+                    {
+                      SetPixelRed(image,ScaleAnyToQuantum((pixel >> 12) & 0x3ff,
+                        range),q);
+                      SetPixelGreen(image,GetPixelRed(image,q),q);
+                      SetPixelBlue(image,GetPixelRed(image,q),q);
+                      q+=channels;
+                    }
+                  break;
+                }
+              for (x=0; x < (ssize_t) (number_pixels-2); x+=3)
+              {
+                p=PushLongPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum((pixel >> 22) & 0x3ff,
+                  range),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                q+=channels;
+                SetPixelRed(image,ScaleAnyToQuantum((pixel >> 12) & 0x3ff,
+                  range),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                q+=channels;
+                SetPixelRed(image,ScaleAnyToQuantum((pixel >> 2) & 0x3ff,
+                  range),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              p=PushLongPixel(endian,p,&pixel);
+              if (x++ < (ssize_t) (number_pixels-1))
+                {
+                  SetPixelRed(image,ScaleAnyToQuantum((pixel >> 22) & 0x3ff,
+                    range),q);
+                  SetPixelGreen(image,GetPixelRed(image,q),q);
+                  SetPixelBlue(image,GetPixelRed(image,q),q);
+                  q+=channels;
+                }
+              if (x++ < (ssize_t) number_pixels)
+                {
+                  SetPixelRed(image,ScaleAnyToQuantum((pixel >> 12) & 0x3ff,
+                    range),q);
+                  SetPixelGreen(image,GetPixelRed(image,q),q);
+                  SetPixelBlue(image,GetPixelRed(image,q),q);
+                  q+=channels;
+                }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              unsigned short
+                pixel;
+
+              for (x=0; x < (ssize_t) (number_pixels-1); x+=2)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                  (pixel >> 4),range),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                q+=channels;
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum(
+                  (QuantumAny) (pixel >> 4),range),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              for (bit=0; bit < (ssize_t) (number_pixels % 2); bit++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum(
+                  (QuantumAny) (pixel >> 4),range),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              if (bit != 0)
+                p++;
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->min_is_white != MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GrayAlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 1:
+        {
+          register unsigned char
+            pixel;
+
+          for (x=0; x < ((ssize_t) number_pixels-3); x+=4)
+          {
+            for (bit=0; bit < 8; bit+=2)
+            {
+              pixel=(unsigned char)
+                (((*p) & (1 << (7-bit))) != 0 ? 0x00 : 0x01);
+              SetPixelRed(image,(Quantum) (pixel == 0 ? 0 : QuantumRange),q);
+              SetPixelGreen(image,GetPixelRed(image,q),q);
+              SetPixelBlue(image,GetPixelRed(image,q),q);
+              SetPixelAlpha(image,((*p) & (1UL << (unsigned char)
+                (6-bit))) == 0 ? TransparentAlpha : OpaqueAlpha,q);
+              q+=channels;
+            }
+            p++;
+          }
+          for (bit=0; bit <= (ssize_t) (number_pixels % 4); bit+=2)
+          {
+            pixel=(unsigned char) (((*p) & (1 << (7-bit))) != 0 ? 0x00 : 0x01);
+            SetPixelRed(image,(Quantum) (pixel != 0 ? 0 : QuantumRange),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            SetPixelAlpha(image,((*p) & (1UL << (unsigned char)
+              (6-bit))) == 0 ? TransparentAlpha : OpaqueAlpha,q);
+            q+=channels;
+          }
+          if (bit != 0)
+            p++;
+          break;
+        }
+        case 4:
+        {
+          register unsigned char
+            pixel;
+
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            pixel=(unsigned char) ((*p >> 4) & 0xf);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            pixel=(unsigned char) ((*p) & 0xf);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p++;
+            q+=channels;
+          }
+          break;
+        }
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelAlpha(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                SetPixelGreen(image,GetPixelRed(image,q),q);
+                SetPixelBlue(image,GetPixelRed(image,q),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            SetPixelGreen(image,GetPixelRed(image,q),q);
+            SetPixelBlue(image,GetPixelRed(image,q),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RedQuantum:
+    case CyanQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case GreenQuantum:
+    case MagentaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BlueQuantum:
+    case YellowQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case AlphaQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelAlpha(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case BlackQuantum:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColorSeparatedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlack(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlack(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlack(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlack(image,ScaleAnyToQuantum(pixel,range),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBQuantum:
+    case CbYCrQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            SetPixelAlpha(image,OpaqueAlpha,q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 10:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushLongPixel(endian,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum((pixel >> 22) & 0x3ff,
+                  range),q);
+                SetPixelGreen(image,ScaleAnyToQuantum((pixel >> 12) & 0x3ff,
+                  range),q);
+                SetPixelBlue(image,ScaleAnyToQuantum((pixel >> 2) & 0x3ff,
+                  range),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          if (quantum_info->quantum == 32U)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 12:
+        {
+          range=GetQuantumRange(image->depth);
+          if (quantum_info->pack == MagickFalse)
+            {
+              unsigned short
+                pixel;
+
+              for (x=0; x < (ssize_t) (3*number_pixels-1); x+=2)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                switch (x % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 1:
+                  {
+                    SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 2:
+                  {
+                    SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    q+=channels;
+                    break;
+                  }
+                }
+                p=PushShortPixel(endian,p,&pixel);
+                switch ((x+1) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 1:
+                  {
+                    SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 2:
+                  {
+                    SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    q+=channels;
+                    break;
+                  }
+                }
+                p+=quantum_info->pad;
+              }
+              for (bit=0; bit < (ssize_t) (3*number_pixels % 2); bit++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                switch ((x+bit) % 3)
+                {
+                  default:
+                  case 0:
+                  {
+                    SetPixelRed(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 1:
+                  {
+                    SetPixelGreen(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    break;
+                  }
+                  case 2:
+                  {
+                    SetPixelBlue(image,ScaleAnyToQuantum((QuantumAny)
+                      (pixel >> 4),range),q);
+                    q+=channels;
+                    break;
+                  }
+                }
+                p+=quantum_info->pad;
+              }
+              if (bit != 0)
+                p++;
+              break;
+            }
+          if (quantum_info->quantum == 32U)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+                p=PushQuantumLongPixel(&quantum_state,image->depth,p,&pixel);
+                SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case RGBAQuantum:
+    case RGBOQuantum:
+    case CbYCrAQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelAlpha(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 10:
+        {
+          pixel=0;
+          if (quantum_info->pack == MagickFalse)
+            {
+              register ssize_t
+                i;
+
+              size_t
+                quantum;
+
+              ssize_t
+                n;
+
+              n=0;
+              quantum=0;
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      p=PushLongPixel(endian,p,&pixel);
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 22) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 12) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 2) & 0x3ff) << 6)));
+                      break;
+                    }
+                  }
+                  switch (i)
+                  {
+                    case 0: SetPixelRed(image,(Quantum) quantum,q); break;
+                    case 1: SetPixelGreen(image,(Quantum) quantum,q); break;
+                    case 2: SetPixelBlue(image,(Quantum) quantum,q); break;
+                    case 3: SetPixelAlpha(image,(Quantum) quantum,q); break;
+                  }
+                  n++;
+                }
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
+              (pixel << 6)),q);
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CMYKQuantum:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColorSeparatedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlack(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlack(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlack(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlack(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CMYKAQuantum:
+    case CMYKOQuantum:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+            "ColorSeparatedImageRequired","`%s'",image->filename);
+          return(extent);
+        }
+      switch (quantum_info->depth)
+      {
+        case 8:
+        {
+          unsigned char
+            pixel;
+
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushCharPixel(p,&pixel);
+            SetPixelRed(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelGreen(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlue(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelBlack(image,ScaleCharToQuantum(pixel),q);
+            p=PushCharPixel(p,&pixel);
+            SetPixelAlpha(image,ScaleCharToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 16:
+        {
+          unsigned short
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelRed(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p=PushShortPixel(endian,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum((MagickRealType)
+                  QuantumRange*HalfToSinglePrecision(pixel)),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelBlack(image,ScaleShortToQuantum(pixel),q);
+            p=PushShortPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleShortToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 32:
+        {
+          unsigned int
+            pixel;
+
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              float
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum(pixel),q);
+                p=PushFloatPixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelRed(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelBlack(image,ScaleLongToQuantum(pixel),q);
+            p=PushLongPixel(endian,p,&pixel);
+            SetPixelAlpha(image,ScaleLongToQuantum(pixel),q);
+            p+=quantum_info->pad;
+            q+=channels;
+          }
+          break;
+        }
+        case 64:
+        {
+          if (quantum_info->format == FloatingPointQuantumFormat)
+            {
+              double
+                pixel;
+
+              for (x=0; x < (ssize_t) number_pixels; x++)
+              {
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelRed(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelGreen(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlue(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelBlack(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                SetPixelAlpha(image,ClampToQuantum(pixel),q);
+                p=PushDoublePixel(&quantum_state,p,&pixel);
+                p+=quantum_info->pad;
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlue(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelBlack(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelAlpha(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    case CbYCrYQuantum:
+    {
+      switch (quantum_info->depth)
+      {
+        case 10:
+        {
+          Quantum
+            cbcr[4];
+
+          pixel=0;
+          if (quantum_info->pack == MagickFalse)
+            {
+              register ssize_t
+                i;
+
+              size_t
+                quantum;
+
+              ssize_t
+                n;
+
+              n=0;
+              quantum=0;
+              for (x=0; x < (ssize_t) number_pixels; x+=2)
+              {
+                for (i=0; i < 4; i++)
+                {
+                  switch (n % 3)
+                  {
+                    case 0:
+                    {
+                      p=PushLongPixel(endian,p,&pixel);
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 22) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 1:
+                    {
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 12) & 0x3ff) << 6)));
+                      break;
+                    }
+                    case 2:
+                    {
+                      quantum=(size_t) (ScaleShortToQuantum((unsigned short)
+                        (((pixel >> 2) & 0x3ff) << 6)));
+                      break;
+                    }
+                  }
+                  cbcr[i]=(Quantum) (quantum);
+                  n++;
+                }
+                p+=quantum_info->pad;
+                SetPixelRed(image,cbcr[1],q);
+                SetPixelGreen(image,cbcr[0],q);
+                SetPixelBlue(image,cbcr[2],q);
+                q+=channels;
+                SetPixelRed(image,cbcr[3],q);
+                SetPixelGreen(image,cbcr[0],q);
+                SetPixelBlue(image,cbcr[2],q);
+                q+=channels;
+              }
+              break;
+            }
+        }
+        default:
+        {
+          range=GetQuantumRange(image->depth);
+          for (x=0; x < (ssize_t) number_pixels; x++)
+          {
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelRed(image,ScaleAnyToQuantum(pixel,range),q);
+            p=PushQuantumPixel(&quantum_state,image->depth,p,&pixel);
+            SetPixelGreen(image,ScaleAnyToQuantum(pixel,range),q);
+            q+=channels;
+          }
+          break;
+        }
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  if ((quantum_type == CbYCrQuantum) || (quantum_type == CbYCrAQuantum))
+    {
+      Quantum
+        quantum;
+
+      register Quantum
+        *restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        quantum=GetPixelRed(image,q);
+        SetPixelRed(image,GetPixelGreen(image,q),q);
+        SetPixelGreen(image,quantum,q);
+        q+=channels;
+      }
+    }
+  if ((quantum_type == RGBOQuantum) || (quantum_type == CMYKOQuantum))
+    {
+      register Quantum
+        *restrict q;
+
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        SetPixelAlpha(image,GetPixelAlpha(image,q),q);
+        q+=channels;
+      }
+    }
+  if (quantum_info->alpha_type == DisassociatedQuantumAlpha)
+    {
+      MagickRealType
+        alpha;
+
+      register Quantum
+        *restrict q;
+
+      /*
+        Disassociate alpha.
+      */
+      q=GetAuthenticPixelQueue(image);
+      if (image_view != (CacheView *) NULL)
+        q=GetCacheViewAuthenticPixelQueue(image_view);
+      for (x=0; x < (ssize_t) number_pixels; x++)
+      {
+        alpha=QuantumScale*GetPixelAlpha(image,q);
+        alpha=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        SetPixelRed(image,ClampToQuantum(alpha*GetPixelRed(image,q)),q);
+        SetPixelGreen(image,ClampToQuantum(alpha*GetPixelGreen(image,q)),q);
+        SetPixelBlue(image,ClampToQuantum(alpha*GetPixelBlue(image,q)),q);
+        q+=channels;
+      }
+    }
+  return(extent);
+}
diff --git a/MagickCore/quantum-private.h b/MagickCore/quantum-private.h
new file mode 100644
index 0000000..f248caa
--- /dev/null
+++ b/MagickCore/quantum-private.h
@@ -0,0 +1,675 @@
+/*
+  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore quantum inline methods.
+*/
+#ifndef _MAGICKCORE_QUANTUM_PRIVATE_H
+#define _MAGICKCORE_QUANTUM_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/cache.h"
+
+typedef struct _QuantumState
+{
+  EndianType
+    endian;
+
+  double
+    minimum,
+    scale,
+    inverse_scale;
+
+  unsigned int
+    pixel;
+
+  size_t
+    bits;
+
+  const unsigned int
+    *mask;
+} QuantumState;
+
+struct _QuantumInfo
+{
+  size_t
+    depth,
+    quantum;
+
+  QuantumFormatType
+    format;
+
+  double
+    minimum,
+    maximum,
+    scale;
+
+  size_t
+    pad;
+
+  MagickBooleanType
+    min_is_white,
+    pack;
+
+  QuantumAlphaType
+    alpha_type;
+
+  size_t
+    number_threads;
+
+  unsigned char
+    **pixels;
+
+  size_t
+    extent;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+static inline MagickSizeType GetQuantumRange(const size_t depth)
+{
+  MagickSizeType
+    one;
+
+  one=1;
+  return((MagickSizeType) ((one << (depth-1))+((one << (depth-1))-1)));
+}
+
+static inline float HalfToSinglePrecision(const unsigned short half)
+{
+#define ExponentBias  (127-15)
+#define ExponentMask  0x7c00
+#define ExponentShift  23
+#define SignBitShift  31
+#define SignificandShift  13
+#define SignificandMask  0x00000400
+
+  typedef union _SinglePrecision
+  {
+    unsigned int
+      fixed_point;
+
+    float
+      single_precision;
+  } SinglePrecision;
+
+  register unsigned int
+    exponent,
+    significand,
+    sign_bit;
+
+  SinglePrecision
+    map;
+
+  unsigned int
+    value;
+
+  /*
+    The IEEE 754 standard specifies half precision as having:
+
+      Sign bit: 1 bit
+      Exponent width: 5 bits
+      Significand precision: 11 (10 explicitly stored)
+  */
+  sign_bit=(unsigned int) ((half >> 15) & 0x00000001);
+  exponent=(unsigned int) ((half >> 10) & 0x0000001f);
+  significand=(unsigned int) (half & 0x000003ff);
+  if (exponent == 0)
+    {
+      if (significand == 0)
+        value=sign_bit << SignBitShift;
+      else
+        {
+          while ((significand & SignificandMask) == 0)
+          {
+            significand<<=1;
+            exponent--;
+          }
+          exponent++;
+          significand&=(~SignificandMask);
+          exponent+=ExponentBias;
+          value=(sign_bit << SignBitShift) | (exponent << ExponentShift) |
+            (significand << SignificandShift);
+        }
+    }
+  else
+    if (exponent == SignBitShift)
+      {
+        value=(sign_bit << SignBitShift) | 0x7f800000;
+        if (significand != 0)
+          value|=(significand << SignificandShift);
+      }
+    else
+      {
+        exponent+=ExponentBias;
+        significand<<=SignificandShift;
+        value=(sign_bit << SignBitShift) | (exponent << ExponentShift) |
+          significand;
+      }
+  map.fixed_point=value;
+  return(map.single_precision);
+}
+
+static inline void InitializeQuantumState(const QuantumInfo *quantum_info,
+  const EndianType endian,QuantumState *quantum_state)
+{
+  static const unsigned int mask[32] =
+  {
+    0x00000000U, 0x00000001U, 0x00000003U, 0x00000007U, 0x0000000fU,
+    0x0000001fU, 0x0000003fU, 0x0000007fU, 0x000000ffU, 0x000001ffU,
+    0x000003ffU, 0x000007ffU, 0x00000fffU, 0x00001fffU, 0x00003fffU,
+    0x00007fffU, 0x0000ffffU, 0x0001ffffU, 0x0003ffffU, 0x0007ffffU,
+    0x000fffffU, 0x001fffffU, 0x003fffffU, 0x007fffffU, 0x00ffffffU,
+    0x01ffffffU, 0x03ffffffU, 0x07ffffffU, 0x0fffffffU, 0x1fffffffU,
+    0x3fffffffU, 0x7fffffffU
+  };
+
+  quantum_state->endian=endian;
+  quantum_state->minimum=quantum_info->minimum;
+  quantum_state->scale=quantum_info->scale;
+  quantum_state->inverse_scale=1.0;
+  if (quantum_state->scale != 0.0)
+    quantum_state->inverse_scale/=quantum_state->scale;
+  quantum_state->pixel=0U;
+  quantum_state->bits=0U;
+  quantum_state->mask=mask;
+}
+
+static inline unsigned char *PopCharPixel(const unsigned char pixel,
+  unsigned char *pixels)
+{
+  *pixels++=pixel;
+  return(pixels);
+}
+
+static inline unsigned char *PopLongPixel(const EndianType endian,
+  const unsigned int pixel,unsigned char *pixels)
+{
+  register unsigned int
+    quantum;
+
+  quantum=(unsigned int) pixel;
+  if (endian != LSBEndian)
+    {
+      *pixels++=(unsigned char) (quantum >> 24);
+      *pixels++=(unsigned char) (quantum >> 16);
+      *pixels++=(unsigned char) (quantum >> 8);
+      *pixels++=(unsigned char) (quantum);
+      return(pixels);
+    }
+  *pixels++=(unsigned char) (quantum);
+  *pixels++=(unsigned char) (quantum >> 8);
+  *pixels++=(unsigned char) (quantum >> 16);
+  *pixels++=(unsigned char) (quantum >> 24);
+  return(pixels);
+}
+
+static inline unsigned char *PopShortPixel(const EndianType endian,
+  const unsigned short pixel,unsigned char *pixels)
+{
+  register unsigned int
+    quantum;
+
+  quantum=pixel;
+  if (endian != LSBEndian)
+    {
+      *pixels++=(unsigned char) (quantum >> 8);
+      *pixels++=(unsigned char) (quantum);
+      return(pixels);
+    }
+  *pixels++=(unsigned char) (quantum);
+  *pixels++=(unsigned char) (quantum >> 8);
+  return(pixels);
+}
+
+static inline const unsigned char *PushCharPixel(const unsigned char *pixels,
+  unsigned char *pixel)
+{
+  *pixel=(*pixels++);
+  return(pixels);
+}
+
+static inline const unsigned char *PushLongPixel(const EndianType endian,
+  const unsigned char *pixels,unsigned int *pixel)
+{
+  register unsigned int
+    quantum;
+
+  if (endian != LSBEndian)
+    {
+      quantum=(unsigned int) (*pixels++ << 24);
+      quantum|=(unsigned int) (*pixels++ << 16);
+      quantum|=(unsigned int) (*pixels++ << 8);
+      quantum|=(unsigned int) (*pixels++);
+    }
+  else
+    {
+      quantum=(unsigned int) (*pixels++);
+      quantum|=(unsigned int) (*pixels++ << 8);
+      quantum|=(unsigned int) (*pixels++ << 16);
+      quantum|=(unsigned int) (*pixels++ << 24);
+    }
+  *pixel=(unsigned int) (quantum & 0xffffffff);
+  return(pixels);
+}
+
+static inline const unsigned char *PushShortPixel(const EndianType endian,
+  const unsigned char *pixels,unsigned short *pixel)
+{
+  register unsigned int
+    quantum;
+
+  if (endian != LSBEndian)
+    {
+      quantum=(unsigned int) (*pixels++ << 8);
+      quantum|=(unsigned int) *pixels++;
+    }
+  else
+    {
+      quantum=(unsigned int) *pixels++;
+      quantum|=(unsigned int) (*pixels++ << 8);
+    }
+  *pixel=(unsigned short) (quantum & 0xffff);
+  return(pixels);
+}
+
+static inline Quantum ScaleAnyToQuantum(const QuantumAny quantum,
+  const QuantumAny range)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (((MagickRealType) QuantumRange*quantum)/range+0.5));
+#else
+  return((Quantum) (((MagickRealType) QuantumRange*quantum)/range));
+#endif
+}
+
+static inline QuantumAny ScaleQuantumToAny(const Quantum quantum,
+  const QuantumAny range)
+{
+  return((QuantumAny) (((MagickRealType) range*quantum)/QuantumRange+0.5));
+}
+
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+static inline Quantum ScaleCharToQuantum(const unsigned char value)
+{
+  return((Quantum) value);
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned int value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) ((value+8421504UL)/16843009UL));
+#else
+  return((Quantum) (value/16843009.0));
+#endif
+}
+
+static inline Quantum ScaleMapToQuantum(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= MaxMap)
+    return((Quantum) QuantumRange);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (value+0.5));
+#else
+  return((Quantum) value);
+#endif
+}
+
+static inline unsigned int ScaleQuantumToLong(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned int) (16843009UL*quantum));
+#else
+  if (quantum <= 0.0)
+    return(0UL);
+  if ((16843009.0*quantum) >= 4294967295.0)
+    return(4294967295UL);
+  return((unsigned int) (16843009.0*quantum+0.5));
+#endif
+}
+
+static inline unsigned int ScaleQuantumToMap(const Quantum quantum)
+{
+  if (quantum >= (Quantum) MaxMap)
+    return((unsigned int) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned int) quantum);
+#else
+  if (quantum < 0.0)
+    return(0UL);
+  return((unsigned int) (quantum+0.5));
+#endif
+}
+
+static inline unsigned short ScaleQuantumToShort(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned short) (257UL*quantum));
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if ((257.0*quantum) >= 65535.0)
+    return(65535);
+  return((unsigned short) (257.0*quantum+0.5));
+#endif
+}
+
+static inline Quantum ScaleShortToQuantum(const unsigned short value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) ((value+128U)/257U));
+#else
+  return((Quantum) (value/257.0));
+#endif
+}
+#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
+static inline Quantum ScaleCharToQuantum(const unsigned char value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (257U*value));
+#else
+  return((Quantum) (257.0*value));
+#endif
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned int value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) ((value+MagickULLConstant(32768))/
+    MagickULLConstant(65537)));
+#else
+  return((Quantum) (value/65537.0));
+#endif
+}
+
+static inline Quantum ScaleMapToQuantum(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= MaxMap)
+    return((Quantum) QuantumRange);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (value+0.5));
+#else
+  return((Quantum) value);
+#endif
+}
+
+static inline unsigned int ScaleQuantumToLong(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned int) (65537UL*quantum));
+#else
+  if (quantum <= 0.0)
+    return(0UL);
+  if ((65537.0*quantum) >= 4294967295.0)
+    return(4294967295U);
+  return((unsigned int) (65537.0*quantum+0.5));
+#endif
+}
+
+static inline unsigned int ScaleQuantumToMap(const Quantum quantum)
+{
+  if (quantum >= (Quantum) MaxMap)
+    return((unsigned int) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned int) quantum);
+#else
+  if (quantum < 0.0)
+    return(0UL);
+  return((unsigned int) (quantum+0.5));
+#endif
+}
+
+static inline unsigned short ScaleQuantumToShort(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned short) quantum);
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if (quantum >= 65535.0)
+    return(65535);
+  return((unsigned short) (quantum+0.5));
+#endif
+}
+
+static inline Quantum ScaleShortToQuantum(const unsigned short value)
+{
+  return((Quantum) value);
+}
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+static inline Quantum ScaleCharToQuantum(const unsigned char value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (16843009UL*value));
+#else
+  return((Quantum) (16843009.0*value));
+#endif
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned int value)
+{
+  return((Quantum) value);
+}
+
+static inline Quantum ScaleMapToQuantum(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= (Quantum) MaxMap)
+    return(QuantumRange);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (65537.0*value+0.5));
+#else
+  return((Quantum) (65537.0*value));
+#endif
+}
+
+static inline unsigned int ScaleQuantumToLong(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned int) quantum);
+#else
+  return((unsigned int) (quantum+0.5));
+#endif
+}
+
+static inline unsigned int ScaleQuantumToMap(const Quantum quantum)
+{
+  if (quantum < 0.0)
+    return(0UL);
+  if ((quantum/65537) >= (Quantum) MaxMap)
+    return((unsigned int) MaxMap);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned int) ((quantum+MagickULLConstant(32768))/
+    MagickULLConstant(65537)));
+#else
+  return((unsigned int) (quantum/65537.0+0.5));
+#endif
+}
+
+static inline unsigned short ScaleQuantumToShort(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned short) ((quantum+MagickULLConstant(32768))/
+    MagickULLConstant(65537)));
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if ((quantum/65537.0) >= 65535.0)
+    return(65535);
+  return((unsigned short) (quantum/65537.0+0.5));
+#endif
+}
+
+static inline Quantum ScaleShortToQuantum(const unsigned short value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) (65537UL*value));
+#else
+  return((Quantum) (65537.0*value));
+#endif
+}
+#elif (MAGICKCORE_QUANTUM_DEPTH == 64)
+static inline Quantum ScaleCharToQuantum(const unsigned char value)
+{
+  return((Quantum) (72340172838076673.0*value));
+}
+
+static inline Quantum ScaleLongToQuantum(const unsigned int value)
+{
+  return((Quantum) (4294967297.0*value));
+}
+
+static inline Quantum ScaleMapToQuantum(const MagickRealType value)
+{
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= MaxMap)
+    return(QuantumRange);
+  return((Quantum) (281479271743489.0*value));
+}
+
+static inline unsigned int ScaleQuantumToLong(const Quantum quantum)
+{
+  return((unsigned int) (quantum/4294967297.0+0.5));
+}
+
+static inline unsigned int ScaleQuantumToMap(const Quantum quantum)
+{
+  if (quantum <= 0.0)
+    return(0UL);
+  if ((quantum/281479271743489.0) >= MaxMap)
+    return((unsigned int) MaxMap);
+  return((unsigned int) (quantum/281479271743489.0+0.5));
+}
+
+static inline unsigned short ScaleQuantumToShort(const Quantum quantum)
+{
+  if (quantum <= 0.0)
+    return(0);
+  if ((quantum/281479271743489.0) >= 65535.0)
+    return(65535);
+  return((unsigned short) (quantum/281479271743489.0+0.5));
+}
+
+static inline Quantum ScaleShortToQuantum(const unsigned short value)
+{
+  return((Quantum) (281479271743489.0*value));
+}
+#endif
+
+static inline unsigned short SinglePrecisionToHalf(const float value)
+{
+  typedef union _SinglePrecision
+  {
+    unsigned int
+      fixed_point;
+
+    float
+      single_precision;
+  } SinglePrecision;
+
+  register int
+    exponent;
+
+  register unsigned int
+    significand,
+    sign_bit;
+
+  SinglePrecision
+    map;
+
+  unsigned short
+    half;
+
+  /*
+    The IEEE 754 standard specifies half precision as having:
+
+      Sign bit: 1 bit
+      Exponent width: 5 bits
+      Significand precision: 11 (10 explicitly stored)
+  */
+  map.single_precision=value;
+  sign_bit=(map.fixed_point >> 16) & 0x00008000;
+  exponent=(int) ((map.fixed_point >> ExponentShift) & 0x000000ff)-ExponentBias;
+  significand=map.fixed_point & 0x007fffff;
+  if (exponent <= 0)
+    {
+      int
+        shift;
+
+      if (exponent < -10)
+        return((unsigned short) sign_bit);
+      significand=significand | 0x00800000;
+      shift=(int) (14-exponent);
+      significand=(unsigned int) ((significand+((1 << (shift-1))-1)+
+        ((significand >> shift) & 0x01)) >> shift);
+      return((unsigned short) (sign_bit | significand));
+    }
+  else
+    if (exponent == (0xff-ExponentBias))
+      {
+        if (significand == 0)
+          return((unsigned short) (sign_bit | ExponentMask));
+        else
+          {
+            significand>>=SignificandShift;
+            half=(unsigned short) (sign_bit | significand |
+              (significand == 0) | ExponentMask);
+            return(half);
+          }
+      }
+  significand=significand+((significand >> SignificandShift) & 0x01)+0x00000fff;
+  if ((significand & 0x00800000) != 0)
+    {
+      significand=0;
+      exponent++;
+    }
+  if (exponent > 30)
+    {
+      float
+        alpha;
+
+      register int
+        i;
+
+      /*
+        Float overflow.
+      */
+      alpha=1.0e10;
+      for (i=0; i < 10; i++)
+        alpha*=alpha;
+      return((unsigned short) (sign_bit | ExponentMask));
+    }
+  half=(unsigned short) (sign_bit | (exponent << 10) |
+    (significand >> SignificandShift));
+  return(half);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/quantum.c b/MagickCore/quantum.c
new file mode 100644
index 0000000..28ca73c
--- /dev/null
+++ b/MagickCore/quantum.c
@@ -0,0 +1,858 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                QQQ   U   U   AAA   N   N  TTTTT  U   U  M   M               %
+%               Q   Q  U   U  A   A  NN  N    T    U   U  MM MM               %
+%               Q   Q  U   U  AAAAA  N N N    T    U   U  M M M               %
+%               Q  QQ  U   U  A   A  N  NN    T    U   U  M   M               %
+%                QQQQ   UUU   A   A  N   N    T     UUU   M   M               %
+%                                                                             %
+%             MagicCore Methods to Acquire / Destroy Quantum Pixels           %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               October 1998                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/utility.h"
+
+/*
+  Define declarations.
+*/
+#define QuantumSignature  0xab
+
+/*
+  Forward declarations.
+*/
+static void
+  DestroyQuantumPixels(QuantumInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e Q u a n t u m I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireQuantumInfo() allocates the QuantumInfo structure.
+%
+%  The format of the AcquireQuantumInfo method is:
+%
+%      QuantumInfo *AcquireQuantumInfo(const ImageInfo *image_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o image: the image.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,
+  const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+MagickExport QuantumInfo *AcquireQuantumInfo(const ImageInfo *image_info,
+  Image *image)
+{
+  MagickBooleanType
+    status;
+
+  QuantumInfo
+    *quantum_info;
+
+  quantum_info=(QuantumInfo *) AcquireMagickMemory(sizeof(*quantum_info));
+  if (quantum_info == (QuantumInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  quantum_info->signature=MagickSignature;
+  GetQuantumInfo(image_info,quantum_info);
+  if (image == (const Image *) NULL)
+    return(quantum_info);
+  status=SetQuantumDepth(image,quantum_info,image->depth);
+  if (status == MagickFalse)
+    quantum_info=DestroyQuantumInfo(quantum_info);
+  return(quantum_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e Q u a n t u m P i x e l s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireQuantumPixels() allocates the unsigned char structure.
+%
+%  The format of the AcquireQuantumPixels method is:
+%
+%      MagickBooleanType AcquireQuantumPixels(QuantumInfo *quantum_info,
+%        const size_t extent)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+%    o extent: the quantum info.
+%
+*/
+static MagickBooleanType AcquireQuantumPixels(QuantumInfo *quantum_info,
+  const size_t extent)
+{
+  register ssize_t
+    i;
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->number_threads=GetOpenMPMaximumThreads();
+  quantum_info->pixels=(unsigned char **) AcquireQuantumMemory(
+    quantum_info->number_threads,sizeof(*quantum_info->pixels));
+  if (quantum_info->pixels == (unsigned char **) NULL)
+    return(MagickFalse);
+  quantum_info->extent=extent;
+  (void) ResetMagickMemory(quantum_info->pixels,0,
+    quantum_info->number_threads*sizeof(*quantum_info->pixels));
+  for (i=0; i < (ssize_t) quantum_info->number_threads; i++)
+  {
+    quantum_info->pixels[i]=(unsigned char *) AcquireQuantumMemory(extent+1,
+      sizeof(**quantum_info->pixels));
+    if (quantum_info->pixels[i] == (unsigned char *) NULL)
+      return(MagickFalse);
+    (void) ResetMagickMemory(quantum_info->pixels[i],0,(extent+1)*
+      sizeof(**quantum_info->pixels));
+    quantum_info->pixels[i][extent]=QuantumSignature;
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y Q u a n t u m I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyQuantumInfo() deallocates memory associated with the QuantumInfo
+%  structure.
+%
+%  The format of the DestroyQuantumInfo method is:
+%
+%      QuantumInfo *DestroyQuantumInfo(QuantumInfo *quantum_info)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+*/
+MagickExport QuantumInfo *DestroyQuantumInfo(QuantumInfo *quantum_info)
+{
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  if (quantum_info->pixels != (unsigned char **) NULL)
+    DestroyQuantumPixels(quantum_info);
+  if (quantum_info->semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&quantum_info->semaphore);
+  quantum_info->signature=(~MagickSignature);
+  quantum_info=(QuantumInfo *) RelinquishMagickMemory(quantum_info);
+  return(quantum_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y Q u a n t u m P i x e l s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyQuantumPixels() destroys the quantum pixels.
+%
+%  The format of the DestroyQuantumPixels() method is:
+%
+%      void DestroyQuantumPixels(QuantumInfo *quantum_info)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+*/
+static void DestroyQuantumPixels(QuantumInfo *quantum_info)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    extent;
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  assert(quantum_info->pixels != (unsigned char **) NULL);
+  extent=(ssize_t) quantum_info->extent;
+  for (i=0; i < (ssize_t) quantum_info->number_threads; i++)
+    if (quantum_info->pixels[i] != (unsigned char *) NULL)
+      {
+        /*
+          Did we overrun our quantum buffer?
+        */
+        assert(quantum_info->pixels[i][extent] == QuantumSignature);
+        quantum_info->pixels[i]=(unsigned char *) RelinquishMagickMemory(
+          quantum_info->pixels[i]);
+      }
+  quantum_info->pixels=(unsigned char **) RelinquishMagickMemory(
+    quantum_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t Q u a n t u m E x t e n t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetQuantumExtent() returns the quantum pixel buffer extent.
+%
+%  The format of the GetQuantumExtent method is:
+%
+%      size_t GetQuantumExtent(Image *image,const QuantumInfo *quantum_info,
+%        const QuantumType quantum_type)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum_info: the quantum info.
+%
+%    o quantum_type: Declare which pixel components to transfer (red, green,
+%      blue, opacity, RGB, or RGBA).
+%
+*/
+MagickExport size_t GetQuantumExtent(const Image *image,
+  const QuantumInfo *quantum_info,const QuantumType quantum_type)
+{
+  size_t
+    packet_size;
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  packet_size=1;
+  switch (quantum_type)
+  {
+    case GrayAlphaQuantum: packet_size=2; break;
+    case IndexAlphaQuantum: packet_size=2; break;
+    case RGBQuantum: packet_size=3; break;
+    case BGRQuantum: packet_size=3; break;
+    case RGBAQuantum: packet_size=4; break;
+    case RGBOQuantum: packet_size=4; break;
+    case BGRAQuantum: packet_size=4; break;
+    case CMYKQuantum: packet_size=4; break;
+    case CMYKAQuantum: packet_size=5; break;
+    default: break;
+  }
+  if (quantum_info->pack == MagickFalse)
+    return((size_t) (packet_size*image->columns*((quantum_info->depth+7)/8)));
+  return((size_t) ((packet_size*image->columns*quantum_info->depth+7)/8));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t Q u a n t u m I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetQuantumInfo() initializes the QuantumInfo structure to default values.
+%
+%  The format of the GetQuantumInfo method is:
+%
+%      GetQuantumInfo(const ImageInfo *image_info,QuantumInfo *quantum_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o quantum_info: the quantum info.
+%
+*/
+MagickExport void GetQuantumInfo(const ImageInfo *image_info,
+  QuantumInfo *quantum_info)
+{
+  const char
+    *option;
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  (void) ResetMagickMemory(quantum_info,0,sizeof(*quantum_info));
+  quantum_info->quantum=8;
+  quantum_info->maximum=1.0;
+  quantum_info->scale=QuantumRange;
+  quantum_info->pack=MagickTrue;
+  quantum_info->semaphore=AllocateSemaphoreInfo();
+  quantum_info->signature=MagickSignature;
+  if (image_info == (const ImageInfo *) NULL)
+    return;
+  option=GetImageOption(image_info,"quantum:format");
+  if (option != (char *) NULL)
+    quantum_info->format=(QuantumFormatType) ParseCommandOption(
+      MagickQuantumFormatOptions,MagickFalse,option);
+  option=GetImageOption(image_info,"quantum:minimum");
+  if (option != (char *) NULL)
+    quantum_info->minimum=InterpretLocaleValue(option,(char **) NULL);
+  option=GetImageOption(image_info,"quantum:maximum");
+  if (option != (char *) NULL)
+    quantum_info->maximum=InterpretLocaleValue(option,(char **) NULL);
+  if ((quantum_info->minimum == 0.0) && (quantum_info->maximum == 0.0))
+    quantum_info->scale=0.0;
+  else
+    if (quantum_info->minimum == quantum_info->maximum)
+      {
+        quantum_info->scale=(MagickRealType) QuantumRange/quantum_info->minimum;
+        quantum_info->minimum=0.0;
+      }
+    else
+      quantum_info->scale=(MagickRealType) QuantumRange/(quantum_info->maximum-
+        quantum_info->minimum);
+  option=GetImageOption(image_info,"quantum:scale");
+  if (option != (char *) NULL)
+    quantum_info->scale=InterpretLocaleValue(option,(char **) NULL);
+  option=GetImageOption(image_info,"quantum:polarity");
+  if (option != (char *) NULL)
+    quantum_info->min_is_white=LocaleCompare(option,"min-is-white") == 0 ?
+      MagickTrue : MagickFalse;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t Q u a n t u m P i x e l s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetQuantumPixels() returns the quantum pixels.
+%
+%  The format of the GetQuantumPixels method is:
+%
+%      unsigned char *QuantumPixels GetQuantumPixels(
+%        const QuantumInfo *quantum_info)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport unsigned char *GetQuantumPixels(const QuantumInfo *quantum_info)
+{
+  const int
+    id = GetOpenMPThreadId();
+
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  return(quantum_info->pixels[id]);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t Q u a n t u m T y p e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetQuantumType() returns the quantum type of the image.
+%
+%  The format of the GetQuantumType method is:
+%
+%      QuantumType GetQuantumType(Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport QuantumType GetQuantumType(Image *image,ExceptionInfo *exception)
+{
+  QuantumType
+    quantum_type;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  quantum_type=RGBQuantum;
+  if (image->matte != MagickFalse)
+    quantum_type=RGBAQuantum;
+  if (image->colorspace == CMYKColorspace)
+    {
+      quantum_type=CMYKQuantum;
+      if (image->matte != MagickFalse)
+        quantum_type=CMYKAQuantum;
+    }
+  if (IsImageGray(image,exception) != MagickFalse)
+    {
+      quantum_type=GrayQuantum;
+      if (image->matte != MagickFalse)
+        quantum_type=GrayAlphaQuantum;
+    }
+  else
+    if (image->storage_class == PseudoClass)
+      {
+        quantum_type=IndexQuantum;
+        if (image->matte != MagickFalse)
+          quantum_type=IndexAlphaQuantum;
+      }
+  return(quantum_type);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m F o r m a t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumAlphaType() sets the quantum format.
+%
+%  The format of the SetQuantumAlphaType method is:
+%
+%      void SetQuantumAlphaType(QuantumInfo *quantum_info,
+%        const QuantumAlphaType type)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+%    o type: the alpha type (e.g. associate).
+%
+*/
+MagickExport void SetQuantumAlphaType(QuantumInfo *quantum_info,
+  const QuantumAlphaType type)
+{
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->alpha_type=type;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m D e p t h                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumDepth() sets the quantum depth.
+%
+%  The format of the SetQuantumDepth method is:
+%
+%      MagickBooleanType SetQuantumDepth(const Image *image,
+%        QuantumInfo *quantum_info,const size_t depth)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum_info: the quantum info.
+%
+%    o depth: the quantum depth.
+%
+*/
+MagickExport MagickBooleanType SetQuantumDepth(const Image *image,
+  QuantumInfo *quantum_info,const size_t depth)
+{
+  MagickBooleanType
+    status;
+
+  /*
+    Allocate the quantum pixel buffer.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->depth=depth;
+  if (quantum_info->format == FloatingPointQuantumFormat)
+    {
+      if (quantum_info->depth > 32)
+        quantum_info->depth=64;
+      else
+        if (quantum_info->depth > 16)
+          quantum_info->depth=32;
+        else
+          quantum_info->depth=16;
+    }
+  if (quantum_info->pixels != (unsigned char **) NULL)
+    DestroyQuantumPixels(quantum_info);
+  status=AcquireQuantumPixels(quantum_info,(6+quantum_info->pad)*image->columns*
+    ((quantum_info->depth+7)/8));  /* allow for CMYKA + RLE byte + pad */
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m F o r m a t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumFormat() sets the quantum format.
+%
+%  The format of the SetQuantumFormat method is:
+%
+%      MagickBooleanType SetQuantumFormat(const Image *image,
+%        QuantumInfo *quantum_info,const QuantumFormatType format)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum_info: the quantum info.
+%
+%    o format: the quantum format.
+%
+*/
+MagickExport MagickBooleanType SetQuantumFormat(const Image *image,
+  QuantumInfo *quantum_info,const QuantumFormatType format)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->format=format;
+  return(SetQuantumDepth(image,quantum_info,quantum_info->depth));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m I m a g e T y p e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumImageType() sets the image type based on the quantum type.
+%
+%  The format of the SetQuantumImageType method is:
+%
+%      void ImageType SetQuantumImageType(Image *image,
+%        const QuantumType quantum_type)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum_type: Declare which pixel components to transfer (red, green,
+%      blue, opacity, RGB, or RGBA).
+%
+*/
+MagickExport void SetQuantumImageType(Image *image,
+  const QuantumType quantum_type)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  switch (quantum_type)
+  {
+    case IndexQuantum:
+    case IndexAlphaQuantum:
+    {
+      image->type=PaletteType;
+      break;
+    }
+    case GrayQuantum:
+    case GrayAlphaQuantum:
+    {
+      image->type=GrayscaleType;
+      if (image->depth == 1)
+        image->type=BilevelType;
+      break;
+    }
+    case CyanQuantum:
+    case MagentaQuantum:
+    case YellowQuantum:
+    case BlackQuantum:
+    case CMYKQuantum:
+    case CMYKAQuantum:
+    {
+      image->type=ColorSeparationType;
+      break;
+    }
+    default:
+    {
+      image->type=TrueColorType;
+      break;
+    }
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m P a c k                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumPack() sets the quantum pack flag.
+%
+%  The format of the SetQuantumPack method is:
+%
+%      void SetQuantumPack(QuantumInfo *quantum_info,
+%        const MagickBooleanType pack)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+%    o pack: the pack flag.
+%
+*/
+MagickExport void SetQuantumPack(QuantumInfo *quantum_info,
+  const MagickBooleanType pack)
+{
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->pack=pack;
+}
+
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m P a d                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumPad() sets the quantum pad.
+%
+%  The format of the SetQuantumPad method is:
+%
+%      MagickBooleanType SetQuantumPad(const Image *image,
+%        QuantumInfo *quantum_info,const size_t pad)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o quantum_info: the quantum info.
+%
+%    o pad: the quantum pad.
+%
+*/
+MagickExport MagickBooleanType SetQuantumPad(const Image *image,
+  QuantumInfo *quantum_info,const size_t pad)
+{
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->pad=pad;
+  return(SetQuantumDepth(image,quantum_info,quantum_info->depth));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m M i n I s W h i t e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumMinIsWhite() sets the quantum min-is-white flag.
+%
+%  The format of the SetQuantumMinIsWhite method is:
+%
+%      void SetQuantumMinIsWhite(QuantumInfo *quantum_info,
+%        const MagickBooleanType min_is_white)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+%    o min_is_white: the min-is-white flag.
+%
+*/
+MagickExport void SetQuantumMinIsWhite(QuantumInfo *quantum_info,
+  const MagickBooleanType min_is_white)
+{
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->min_is_white=min_is_white;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m Q u a n t u m                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumQuantum() sets the quantum quantum.
+%
+%  The format of the SetQuantumQuantum method is:
+%
+%      void SetQuantumQuantum(QuantumInfo *quantum_info,
+%        const size_t quantum)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+%    o quantum: the quantum quantum.
+%
+*/
+MagickExport void SetQuantumQuantum(QuantumInfo *quantum_info,
+  const size_t quantum)
+{
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->quantum=quantum;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t Q u a n t u m S c a l e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetQuantumScale() sets the quantum scale.
+%
+%  The format of the SetQuantumScale method is:
+%
+%      void SetQuantumScale(QuantumInfo *quantum_info,const double scale)
+%
+%  A description of each parameter follows:
+%
+%    o quantum_info: the quantum info.
+%
+%    o scale: the quantum scale.
+%
+*/
+MagickExport void SetQuantumScale(QuantumInfo *quantum_info,const double scale)
+{
+  assert(quantum_info != (QuantumInfo *) NULL);
+  assert(quantum_info->signature == MagickSignature);
+  quantum_info->scale=scale;
+}
diff --git a/MagickCore/quantum.h b/MagickCore/quantum.h
new file mode 100644
index 0000000..5c6b898
--- /dev/null
+++ b/MagickCore/quantum.h
@@ -0,0 +1,188 @@
+/*
+  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore quantum inline methods.
+*/
+#ifndef _MAGICKCORE_QUANTUM_H
+#define _MAGICKCORE_QUANTUM_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/semaphore.h"
+
+#define RoundToQuantum(quantum)  ClampToQuantum(quantum)
+
+typedef enum
+{
+  UndefinedEndian,
+  LSBEndian,
+  MSBEndian
+} EndianType;
+
+typedef enum
+{
+  UndefinedQuantumAlpha,
+  AssociatedQuantumAlpha,
+  DisassociatedQuantumAlpha
+} QuantumAlphaType;
+
+typedef enum
+{
+  UndefinedQuantumFormat,
+  FloatingPointQuantumFormat,
+  SignedQuantumFormat,
+  UnsignedQuantumFormat
+} QuantumFormatType;
+
+typedef enum
+{
+  UndefinedQuantum,
+  AlphaQuantum,
+  BGRAQuantum,
+  BGROQuantum,
+  BGRQuantum,
+  BlackQuantum,
+  BlueQuantum,
+  CbYCrAQuantum,
+  CbYCrQuantum,
+  CbYCrYQuantum,
+  CMYKAQuantum,
+  CMYKOQuantum,
+  CMYKQuantum,
+  CyanQuantum,
+  GrayAlphaQuantum,
+  GrayQuantum,
+  GreenQuantum,
+  IndexAlphaQuantum,
+  IndexQuantum,
+  MagentaQuantum,
+  OpacityQuantum,
+  RedQuantum,
+  RGBAQuantum,
+  RGBOQuantum,
+  RGBPadQuantum,
+  RGBQuantum,
+  YellowQuantum
+} QuantumType;
+
+typedef struct _QuantumInfo
+  QuantumInfo;
+
+static inline Quantum ClampToQuantum(const MagickRealType value)
+{
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) value);
+#else
+  if (value <= 0.0)
+    return((Quantum) 0);
+  if (value >= (MagickRealType) QuantumRange)
+    return((Quantum) QuantumRange);
+  return((Quantum) (value+0.5));
+#endif
+}
+
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+static inline unsigned char ScaleQuantumToChar(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned char) quantum);
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if (quantum >= 255.0)
+    return(255);
+  return((unsigned char) (quantum+0.5));
+#endif
+}
+#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
+static inline unsigned char ScaleQuantumToChar(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned char) (((quantum+128UL)-((quantum+128UL) >> 8)) >> 8));
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if ((quantum/257.0) >= 255.0)
+    return(255);
+  return((unsigned char) (quantum/257.0+0.5));
+#endif
+}
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+static inline unsigned char ScaleQuantumToChar(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned char) ((quantum+MagickULLConstant(8421504))/
+    MagickULLConstant(16843009)));
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if ((quantum/16843009.0) >= 255.0)
+    return(255);
+  return((unsigned char) (quantum/16843009.0+0.5));
+#endif
+}
+#elif (MAGICKCORE_QUANTUM_DEPTH == 64)
+static inline unsigned char ScaleQuantumToChar(const Quantum quantum)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((unsigned char) (quantum/72340172838076673.0+0.5));
+#else
+  if (quantum <= 0.0)
+    return(0);
+  if ((quantum/72340172838076673.0) >= 255.0)
+    return(255);
+  return((unsigned char) (quantum/72340172838076673.0+0.5));
+#endif
+}
+#endif
+
+extern MagickExport MagickBooleanType
+  SetQuantumDepth(const Image *,QuantumInfo *,const size_t),
+  SetQuantumFormat(const Image *,QuantumInfo *,const QuantumFormatType),
+  SetQuantumPad(const Image *,QuantumInfo *,const size_t);
+
+extern MagickExport QuantumInfo
+  *AcquireQuantumInfo(const ImageInfo *,Image *),
+  *DestroyQuantumInfo(QuantumInfo *);
+
+extern MagickExport QuantumType
+  GetQuantumType(Image *,ExceptionInfo *);
+
+extern MagickExport size_t
+  ExportQuantumPixels(Image *,CacheView *,const QuantumInfo *,const QuantumType,
+    unsigned char *,ExceptionInfo *),
+  GetQuantumExtent(const Image *,const QuantumInfo *,const QuantumType),
+  ImportQuantumPixels(Image *,CacheView *,const QuantumInfo *,const QuantumType,
+    const unsigned char *,ExceptionInfo *);
+
+extern MagickExport unsigned char
+  *GetQuantumPixels(const QuantumInfo *);
+
+extern MagickExport void
+  GetQuantumInfo(const ImageInfo *,QuantumInfo *),
+  SetQuantumAlphaType(QuantumInfo *,const QuantumAlphaType),
+  SetQuantumImageType(Image *,const QuantumType),
+  SetQuantumMinIsWhite(QuantumInfo *,const MagickBooleanType),
+  SetQuantumPack(QuantumInfo *,const MagickBooleanType),
+  SetQuantumQuantum(QuantumInfo *,const size_t),
+  SetQuantumScale(QuantumInfo *,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/random-private.h b/MagickCore/random-private.h
new file mode 100644
index 0000000..fd589c8
--- /dev/null
+++ b/MagickCore/random-private.h
@@ -0,0 +1,70 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore random generation private methods.
+*/
+#ifndef _MAGICKCORE_RANDOM_PRIVATE_H
+#define _MAGICKCORE_RANDOM_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/thread-private.h"
+
+static inline RandomInfo **DestroyRandomInfoThreadSet(
+  RandomInfo **random_info)
+{
+  register ssize_t
+    i;
+
+  assert(random_info != (RandomInfo **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (random_info[i] != (RandomInfo *) NULL)
+      random_info[i]=DestroyRandomInfo(random_info[i]);
+  return((RandomInfo **) RelinquishAlignedMemory(random_info));
+}
+
+static inline RandomInfo **AcquireRandomInfoThreadSet(void)
+{
+  register ssize_t
+    i;
+
+  RandomInfo
+    **random_info;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  random_info=(RandomInfo **) AcquireAlignedMemory(number_threads,
+    sizeof(*random_info));
+  if (random_info == (RandomInfo **) NULL)
+    return((RandomInfo **) NULL);
+  (void) ResetMagickMemory(random_info,0,number_threads*sizeof(*random_info));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    random_info[i]=AcquireRandomInfo();
+    if (random_info[i] == (RandomInfo *) NULL)
+      return(DestroyRandomInfoThreadSet(random_info));
+  }
+  return(random_info);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/random.c b/MagickCore/random.c
new file mode 100644
index 0000000..818e7ca
--- /dev/null
+++ b/MagickCore/random.c
@@ -0,0 +1,892 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                 RRRR    AAA   N   N  DDDD    OOO   M   M                    %
+%                 R   R  A   A  NN  N  D   D  O   O  MM MM                    %
+%                 RRRR   AAAAA  N N N  D   D  O   O  M M M                    %
+%                 R R    A   A  N  NN  D   D  O   O  M   M                    %
+%                 R  R   A   A  N   N  DDDD    OOO   M   M                    %
+%                                                                             %
+%                                                                             %
+%               MagickCore Methods to Generate Random Numbers                 %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                              December 2001                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The generation of random numbers is too important to be left to chance.
+%                               -- Tom Christiansen <tchrist@mox.perl.com>
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#if defined(__VMS)
+#include <time.h>
+#endif
+#if defined(__MINGW32__)
+#include <sys/time.h>
+#endif
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/utility.h"
+/*
+  Define declarations.
+*/
+#define PseudoRandomHash  SHA256Hash
+#define RandomEntropyLevel  9
+#define RandomFilename  "reservoir.xdm"
+#define RandomFiletype  "random"
+#define RandomProtocolMajorVersion  1
+#define RandomProtocolMinorVersion  0
+
+/*
+  Typedef declarations.
+*/
+struct _RandomInfo
+{
+  SignatureInfo
+    *signature_info;
+
+  StringInfo
+    *nonce,
+    *reservoir;
+
+  size_t
+    i;
+
+  unsigned long
+    seed[4];
+
+  double
+    normalize;
+
+  unsigned short
+    protocol_major,
+    protocol_minor;
+
+  SemaphoreInfo
+    *semaphore;
+
+  ssize_t
+    timestamp;
+
+  size_t
+    signature;
+};
+
+/*
+  External declarations.
+*/
+#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+#endif
+
+extern char
+  **environ;
+
+/*
+  Global declarations.
+*/
+static SemaphoreInfo
+  *random_semaphore = (SemaphoreInfo *) NULL;
+
+static unsigned long
+  random_seed = ~0UL;
+
+static MagickBooleanType
+  gather_true_random = MagickFalse;
+
+/*
+  Forward declarations.
+*/
+static StringInfo
+  *GenerateEntropicChaos(RandomInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e R a n d o m I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireRandomInfo() allocates the RandomInfo structure.
+%
+%  The format of the AcquireRandomInfo method is:
+%
+%      RandomInfo *AcquireRandomInfo(void)
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport RandomInfo *AcquireRandomInfo(void)
+{
+  const StringInfo
+    *digest;
+
+  RandomInfo
+    *random_info;
+
+  StringInfo
+    *entropy,
+    *key,
+    *nonce;
+
+  random_info=(RandomInfo *) AcquireMagickMemory(sizeof(*random_info));
+  if (random_info == (RandomInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(random_info,0,sizeof(*random_info));
+  random_info->signature_info=AcquireSignatureInfo();
+  random_info->nonce=AcquireStringInfo(2*GetSignatureDigestsize(
+    random_info->signature_info));
+  ResetStringInfo(random_info->nonce);
+  random_info->reservoir=AcquireStringInfo(GetSignatureDigestsize(
+    random_info->signature_info));
+  ResetStringInfo(random_info->reservoir);
+  random_info->normalize=1.0/(~0UL);
+  random_info->semaphore=AllocateSemaphoreInfo();
+  random_info->protocol_major=RandomProtocolMajorVersion;
+  random_info->protocol_minor=RandomProtocolMinorVersion;
+  random_info->timestamp=(ssize_t) time(0);
+  random_info->signature=MagickSignature;
+  /*
+    Seed random nonce.
+  */
+  nonce=GenerateEntropicChaos(random_info);
+  if (nonce == (StringInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  InitializeSignature(random_info->signature_info);
+  UpdateSignature(random_info->signature_info,nonce);
+  FinalizeSignature(random_info->signature_info);
+  SetStringInfoLength(nonce,(GetSignatureDigestsize(
+    random_info->signature_info)+1)/2);
+  SetStringInfo(nonce,GetSignatureDigest(random_info->signature_info));
+  SetStringInfo(random_info->nonce,nonce);
+  nonce=DestroyStringInfo(nonce);
+  /*
+    Seed random reservoir with entropic data.
+  */
+  entropy=GenerateEntropicChaos(random_info);
+  if (entropy == (StringInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  UpdateSignature(random_info->signature_info,entropy);
+  FinalizeSignature(random_info->signature_info);
+  SetStringInfo(random_info->reservoir,GetSignatureDigest(
+    random_info->signature_info));
+  entropy=DestroyStringInfo(entropy);
+  /*
+    Seed pseudo random number generator.
+  */
+  if (random_seed == ~0UL)
+    {
+      key=GetRandomKey(random_info,sizeof(random_seed));
+      (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(key),
+        GetStringInfoLength(key));
+      key=DestroyStringInfo(key);
+    }
+  else
+    {
+      SignatureInfo
+        *signature_info;
+
+      signature_info=AcquireSignatureInfo();
+      key=AcquireStringInfo(sizeof(random_seed));
+      SetStringInfoDatum(key,(unsigned char *) &random_seed);
+      UpdateSignature(signature_info,key);
+      key=DestroyStringInfo(key);
+      FinalizeSignature(signature_info);
+      digest=GetSignatureDigest(signature_info);
+      (void) CopyMagickMemory(random_info->seed,GetStringInfoDatum(digest),
+        MagickMin(GetSignatureDigestsize(signature_info),
+        sizeof(*random_info->seed)));
+      signature_info=DestroySignatureInfo(signature_info);
+    }
+  random_info->seed[1]=0x50a7f451UL;
+  random_info->seed[2]=0x5365417eUL;
+  random_info->seed[3]=0xc3a4171aUL;
+  return(random_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y R a n d o m I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyRandomInfo() deallocates memory associated with the random
+%  reservoir.
+%
+%  The format of the DestroyRandomInfo method is:
+%
+%      RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
+%
+%  A description of each parameter follows:
+%
+%    o random_info: the random info.
+%
+*/
+MagickExport RandomInfo *DestroyRandomInfo(RandomInfo *random_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(random_info != (RandomInfo *) NULL);
+  assert(random_info->signature == MagickSignature);
+  LockSemaphoreInfo(random_info->semaphore);
+  if (random_info->reservoir != (StringInfo *) NULL)
+    random_info->reservoir=DestroyStringInfo(random_info->reservoir);
+  if (random_info->nonce != (StringInfo *) NULL)
+    random_info->nonce=DestroyStringInfo(random_info->nonce);
+  if (random_info->signature_info != (SignatureInfo *) NULL)
+    random_info->signature_info=DestroySignatureInfo(
+      random_info->signature_info);
+  (void) ResetMagickMemory(random_info->seed,0,sizeof(*random_info->seed));
+  random_info->signature=(~MagickSignature);
+  UnlockSemaphoreInfo(random_info->semaphore);
+  DestroySemaphoreInfo(&random_info->semaphore);
+  random_info=(RandomInfo *) RelinquishMagickMemory(random_info);
+  return(random_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e n e r a t e E n t r o p i c C h a o s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GenerateEntropicChaos() generate entropic chaos used to initialize the
+%  random reservoir.
+%
+%  The format of the GenerateEntropicChaos method is:
+%
+%      StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
+%
+%  A description of each parameter follows:
+%
+%    o random_info: the random info.
+%
+*/
+
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT)
+static ssize_t ReadRandom(int file,unsigned char *source,size_t length)
+{
+  register unsigned char
+    *q;
+
+  ssize_t
+    offset,
+    count;
+
+  offset=0;
+  for (q=source; length != 0; length-=count)
+  {
+    count=(ssize_t) read(file,q,length);
+    if (count <= 0)
+      {
+        count=0;
+        if (errno == EINTR)
+          continue;
+        return(-1);
+      }
+    q+=count;
+    offset+=count;
+  }
+  return(offset);
+}
+#endif
+
+static StringInfo *GenerateEntropicChaos(RandomInfo *random_info)
+{
+#define MaxEntropyExtent  64
+
+  MagickThreadType
+    tid;
+
+  StringInfo
+    *chaos,
+    *entropy;
+
+  size_t
+    nanoseconds,
+    seconds;
+
+  ssize_t
+    pid;
+
+  /*
+    Initialize random reservoir.
+  */
+  entropy=AcquireStringInfo(0);
+  LockSemaphoreInfo(random_info->semaphore);
+  chaos=AcquireStringInfo(sizeof(unsigned char *));
+  SetStringInfoDatum(chaos,(unsigned char *) &entropy);
+  ConcatenateStringInfo(entropy,chaos);
+  SetStringInfoDatum(chaos,(unsigned char *) entropy);
+  ConcatenateStringInfo(entropy,chaos);
+  pid=(ssize_t) getpid();
+  SetStringInfoLength(chaos,sizeof(pid));
+  SetStringInfoDatum(chaos,(unsigned char *) &pid);
+  ConcatenateStringInfo(entropy,chaos);
+  tid=GetMagickThreadId();
+  SetStringInfoLength(chaos,sizeof(tid));
+  SetStringInfoDatum(chaos,(unsigned char *) &tid);
+  ConcatenateStringInfo(entropy,chaos);
+#if defined(MAGICKCORE_HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
+  {
+    struct rusage
+      usage;
+
+    if (getrusage(RUSAGE_SELF,&usage) == 0)
+      {
+        SetStringInfoLength(chaos,sizeof(usage));
+        SetStringInfoDatum(chaos,(unsigned char *) &usage);
+      }
+  }
+#endif
+  seconds=time((time_t *) 0);
+  nanoseconds=0;
+#if defined(MAGICKCORE_HAVE_GETTIMEOFDAY)
+  {
+    struct timeval
+      timer;
+
+    if (gettimeofday(&timer,(struct timezone *) NULL) == 0)
+      {
+        seconds=timer.tv_sec;
+        nanoseconds=1000UL*timer.tv_usec;
+      }
+  }
+#endif
+#if defined(MAGICKCORE_HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME_HR)
+  {
+    struct timespec
+      timer;
+
+    if (clock_gettime(CLOCK_REALTIME_HR,&timer) == 0)
+      {
+        seconds=timer.tv_sec;
+        nanoseconds=timer.tv_nsec;
+      }
+  }
+#endif
+  SetStringInfoLength(chaos,sizeof(seconds));
+  SetStringInfoDatum(chaos,(unsigned char *) &seconds);
+  ConcatenateStringInfo(entropy,chaos);
+  SetStringInfoLength(chaos,sizeof(nanoseconds));
+  SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
+  ConcatenateStringInfo(entropy,chaos);
+  nanoseconds=0;
+#if defined(MAGICKCORE_HAVE_CLOCK)
+  nanoseconds=clock();
+#endif
+#if defined(MAGICKCORE_HAVE_TIMES)
+  {
+    struct tms
+      timer;
+
+    (void) times(&timer);
+    nanoseconds=timer.tms_utime+timer.tms_stime;
+  }
+#endif
+  SetStringInfoLength(chaos,sizeof(nanoseconds));
+  SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
+  ConcatenateStringInfo(entropy,chaos);
+#if defined(MAGICKCORE_HAVE_MKSTEMP)
+  {
+    char
+      *filename;
+
+    int
+      file;
+
+    filename=ConstantString("magickXXXXXX");
+    file=mkstemp(filename);
+#if defined(__OS2__)
+    setmode(file,O_BINARY);
+#endif
+    if (file != -1)
+      (void) close(file);
+    (void) remove(filename);
+    SetStringInfoLength(chaos,strlen(filename));
+    SetStringInfoDatum(chaos,(unsigned char *) filename);
+    ConcatenateStringInfo(entropy,chaos);
+    filename=DestroyString(filename);
+  }
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    double
+      seconds;
+
+    LARGE_INTEGER
+      nanoseconds;
+
+    MagickBooleanType
+      status;
+
+    /*
+      Not crytographically strong but better than nothing.
+    */
+    seconds=NTElapsedTime()+NTUserTime();
+    SetStringInfoLength(chaos,sizeof(seconds));
+    SetStringInfoDatum(chaos,(unsigned char *) &seconds);
+    ConcatenateStringInfo(entropy,chaos);
+    if (QueryPerformanceCounter(&nanoseconds) != 0)
+      {
+        SetStringInfoLength(chaos,sizeof(nanoseconds));
+        SetStringInfoDatum(chaos,(unsigned char *) &nanoseconds);
+        ConcatenateStringInfo(entropy,chaos);
+      }
+    /*
+      Our best hope for true entropy.
+    */
+    SetStringInfoLength(chaos,MaxEntropyExtent);
+    status=NTGatherRandomData(MaxEntropyExtent,GetStringInfoDatum(chaos));
+    ConcatenateStringInfo(entropy,chaos);
+  }
+#else
+  {
+    char
+      *filename;
+
+    int
+      file;
+
+    ssize_t
+      count;
+
+    StringInfo
+      *device;
+
+    /*
+      Not crytographically strong but better than nothing.
+    */
+    if (environ != (char **) NULL)
+      {
+        register ssize_t
+          i;
+
+        /*
+          Squeeze some entropy from the sometimes unpredicatble environment.
+        */
+        for (i=0; environ[i] != (char *) NULL; i++)
+        {
+          SetStringInfoLength(chaos,strlen(environ[i]));
+          SetStringInfoDatum(chaos,(unsigned char *) environ[i]);
+          ConcatenateStringInfo(entropy,chaos);
+        }
+      }
+    filename=AcquireString("/dev/urandom");
+    device=StringToStringInfo(filename);
+    device=DestroyStringInfo(device);
+    file=open(filename,O_RDONLY | O_BINARY);
+    filename=DestroyString(filename);
+    if (file != -1)
+      {
+        SetStringInfoLength(chaos,MaxEntropyExtent);
+        count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
+        (void) close(file);
+        SetStringInfoLength(chaos,(size_t) count);
+        ConcatenateStringInfo(entropy,chaos);
+      }
+    if (gather_true_random != MagickFalse)
+      {
+        /*
+          Our best hope for true entropy.
+        */
+        filename=AcquireString("/dev/random");
+        device=StringToStringInfo(filename);
+        device=DestroyStringInfo(device);
+        file=open(filename,O_RDONLY | O_BINARY);
+        filename=DestroyString(filename);
+        if (file == -1)
+          {
+            filename=AcquireString("/dev/srandom");
+            device=StringToStringInfo(filename);
+            device=DestroyStringInfo(device);
+            file=open(filename,O_RDONLY | O_BINARY);
+          }
+        if (file != -1)
+          {
+            SetStringInfoLength(chaos,MaxEntropyExtent);
+            count=ReadRandom(file,GetStringInfoDatum(chaos),MaxEntropyExtent);
+            (void) close(file);
+            SetStringInfoLength(chaos,(size_t) count);
+            ConcatenateStringInfo(entropy,chaos);
+          }
+      }
+  }
+#endif
+  chaos=DestroyStringInfo(chaos);
+  UnlockSemaphoreInfo(random_info->semaphore);
+  return(entropy);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P s e u d o R a n d o m V a l u e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPseudoRandomValue() return a non-negative double-precision floating-point
+%  value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
+%  128th-1 period.
+%
+%  The format of the GetPseudoRandomValue method is:
+%
+%      double GetPseudoRandomValue(RandomInfo *randon_info)
+%
+%  A description of each parameter follows:
+%
+%    o random_info: the random info.
+%
+*/
+MagickExport double GetPseudoRandomValue(RandomInfo *random_info)
+{
+  register unsigned long
+    *seed;
+
+  unsigned long
+    alpha;
+
+  seed=random_info->seed;
+  do
+  {
+    alpha=(unsigned long) (seed[1] ^ (seed[1] << 11));
+    seed[1]=seed[2];
+    seed[2]=seed[3];
+    seed[3]=seed[0];
+    seed[0]=(seed[0] ^ (seed[0] >> 19)) ^ (alpha ^ (alpha >> 8));
+  } while (seed[0] == ~0UL);
+  return(random_info->normalize*seed[0]);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t R a n d o m K e y                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetRandomKey() gets a random key from the reservoir.
+%
+%  The format of the GetRandomKey method is:
+%
+%      StringInfo *GetRandomKey(RandomInfo *random_info,const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o random_info: the random info.
+%
+%    o length: the key length.
+%
+*/
+MagickExport StringInfo *GetRandomKey(RandomInfo *random_info,
+  const size_t length)
+{
+  StringInfo
+    *key;
+
+  assert(random_info != (RandomInfo *) NULL);
+  key=AcquireStringInfo(length);
+  SetRandomKey(random_info,length,GetStringInfoDatum(key));
+  return(key);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t R a n d o m V a l u e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetRandomValue() return a non-negative double-precision floating-point
+%  value uniformly distributed over the interval [0.0, 1.0) with a 2 to the
+%  128th-1 period (not cryptographically strong).
+%
+%  The format of the GetRandomValue method is:
+%
+%      double GetRandomValue(void)
+%
+*/
+MagickExport double GetRandomValue(RandomInfo *random_info)
+{
+  unsigned long
+    key,
+    range;
+
+  range=(~0UL);
+  do
+  {
+    SetRandomKey(random_info,sizeof(key),(unsigned char *) &key);
+  } while (key == range);
+  return((double) key/range);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R a n d o m C o m p o n e n t G e n e s i s                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RandomComponentGenesis() instantiates the random component.
+%
+%  The format of the RandomComponentGenesis method is:
+%
+%      MagickBooleanType RandomComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType RandomComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&random_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R a n d o m C o m p o n e n t T e r m i n u s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RandomComponentTerminus() destroys the random component.
+%
+%  The format of the RandomComponentTerminus method is:
+%
+%      RandomComponentTerminus(void)
+%
+*/
+MagickExport void RandomComponentTerminus(void)
+{
+  if (random_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&random_semaphore);
+  DestroySemaphoreInfo(&random_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e e d P s e u d o R a n d o m G e n e r a t o r                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SeedPseudoRandomGenerator() initializes the pseudo-random number generator
+%  with a random seed.
+%
+%  The format of the SeedPseudoRandomGenerator method is:
+%
+%      void SeedPseudoRandomGenerator(const unsigned long seed)
+%
+%  A description of each parameter follows:
+%
+%    o seed: the seed.
+%
+*/
+MagickExport void SeedPseudoRandomGenerator(const unsigned long seed)
+{
+  random_seed=seed;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t R a n d o m K e y                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetRandomKey() sets a random key from the reservoir.
+%
+%  The format of the SetRandomKey method is:
+%
+%      void SetRandomKey(RandomInfo *random_info,const size_t length,
+%        unsigned char *key)
+%
+%  A description of each parameter follows:
+%
+%    o random_info: the random info.
+%
+%    o length: the key length.
+%
+%    o key: the key.
+%
+*/
+
+static inline void IncrementRandomNonce(StringInfo *nonce)
+{
+  register ssize_t
+    i;
+
+  unsigned char
+    *datum;
+
+  datum=GetStringInfoDatum(nonce);
+  for (i=(ssize_t) (GetStringInfoLength(nonce)-1); i != 0; i--)
+  {
+    datum[i]++;
+    if (datum[i] != 0)
+      return;
+  }
+  ThrowFatalException(RandomFatalError,"SequenceWrapError");
+}
+
+MagickExport void SetRandomKey(RandomInfo *random_info,const size_t length,
+  unsigned char *key)
+{
+  register size_t
+    i;
+
+  register unsigned char
+    *p;
+
+  SignatureInfo
+    *signature_info;
+
+  unsigned char
+    *datum;
+
+  assert(random_info != (RandomInfo *) NULL);
+  if (length == 0)
+    return;
+  LockSemaphoreInfo(random_info->semaphore);
+  signature_info=random_info->signature_info;
+  datum=GetStringInfoDatum(random_info->reservoir);
+  i=length;
+  for (p=key; (i != 0) && (random_info->i != 0); i--)
+  {
+    *p++=datum[random_info->i];
+    random_info->i++;
+    if (random_info->i == GetSignatureDigestsize(signature_info))
+      random_info->i=0;
+  }
+  while (i >= GetSignatureDigestsize(signature_info))
+  {
+    InitializeSignature(signature_info);
+    UpdateSignature(signature_info,random_info->nonce);
+    FinalizeSignature(signature_info);
+    IncrementRandomNonce(random_info->nonce);
+    (void) CopyMagickMemory(p,GetStringInfoDatum(GetSignatureDigest(
+      signature_info)),GetSignatureDigestsize(signature_info));
+    p+=GetSignatureDigestsize(signature_info);
+    i-=GetSignatureDigestsize(signature_info);
+  }
+  if (i != 0)
+    {
+      InitializeSignature(signature_info);
+      UpdateSignature(signature_info,random_info->nonce);
+      FinalizeSignature(signature_info);
+      IncrementRandomNonce(random_info->nonce);
+      SetStringInfo(random_info->reservoir,GetSignatureDigest(signature_info));
+      random_info->i=i;
+      datum=GetStringInfoDatum(random_info->reservoir);
+      while (i-- != 0)
+        p[i]=datum[i];
+    }
+  UnlockSemaphoreInfo(random_info->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t R a n d o m T r u e R a n d o m                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetRandomTrueRandom() declares your intentions to use true random numbers.
+%  True random numbers are encouraged but may not always be practical because
+%  your application may block while entropy is gathered from your environment.
+%
+%  The format of the SetRandomTrueRandom method is:
+%
+%      void SetRandomTrueRandom(const MagickBooleanType true_random)
+%
+%  A description of each parameter follows:
+%
+%    o true_random: declare your intentions to use true-random number.
+%
+*/
+MagickExport void SetRandomTrueRandom(const MagickBooleanType true_random)
+{
+  gather_true_random=true_random;
+}
diff --git a/MagickCore/random_.h b/MagickCore/random_.h
new file mode 100644
index 0000000..06de7d1
--- /dev/null
+++ b/MagickCore/random_.h
@@ -0,0 +1,60 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore random methods.
+*/
+#ifndef _MAGICKCORE_RANDOM__H
+#define _MAGICKCORE_RANDOM__H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/string_.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _RandomInfo
+  RandomInfo;
+
+/*
+  Method declarations.
+*/
+extern MagickExport double
+  GetRandomValue(RandomInfo *),
+  GetPseudoRandomValue(RandomInfo *);
+
+extern MagickExport MagickBooleanType
+  RandomComponentGenesis(void);
+
+extern MagickExport RandomInfo
+  *AcquireRandomInfo(void),
+  *DestroyRandomInfo(RandomInfo *);
+
+extern MagickExport StringInfo
+  *GetRandomKey(RandomInfo *,const size_t);
+
+extern MagickExport void
+  RandomComponentTerminus(void),
+  SeedPseudoRandomGenerator(const unsigned long),
+  SetRandomKey(RandomInfo *,const size_t,unsigned char *),
+  SetRandomTrueRandom(const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/registry.c b/MagickCore/registry.c
new file mode 100644
index 0000000..e3ba26b
--- /dev/null
+++ b/MagickCore/registry.c
@@ -0,0 +1,541 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           RRRR    EEEEE    GGG   IIIII  SSSSS  TTTTT  RRRR   Y   Y          %
+%           R   R   E       G        I    SS       T    R   R   Y Y           %
+%           RRRR    EEE     G GGG    I     SSS     T    RRRR     Y            %
+%           R R     E       G   G    I       SS    T    R R      Y            %
+%           R  R    EEEEE    GGG   IIIII  SSSSS    T    R  R     Y            %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Registry Methods                           %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 March 2000                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _RegistryInfo
+{
+  RegistryType
+    type;
+
+  void
+    *value;
+
+  size_t
+    signature;
+} RegistryInfo;
+
+/*
+  Static declarations.
+*/
+static SplayTreeInfo
+  *registry = (SplayTreeInfo *) NULL;
+
+static SemaphoreInfo
+  *registry_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_registry = MagickFalse;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e f i n e I m a g e R e g i s t r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineImageRegistry() associates a key/value pair with the image registry.
+%
+%  The format of the DefineImageRegistry method is:
+%
+%      MagickBooleanType DefineImageRegistry(const RegistryType type,
+%        const char *option,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type.
+%
+%    o option: the option.
+%
+%    o exception: the exception.
+%
+*/
+MagickExport MagickBooleanType DefineImageRegistry(const RegistryType type,
+  const char *option,ExceptionInfo *exception)
+{
+  char
+    key[MaxTextExtent],
+    value[MaxTextExtent];
+
+  register char
+    *p;
+
+  assert(option != (const char *) NULL);
+  (void) CopyMagickString(key,option,MaxTextExtent);
+  for (p=key; *p != '\0'; p++)
+    if (*p == '=')
+      break;
+  *value='\0';
+  if (*p == '=')
+    (void) CopyMagickString(value,p+1,MaxTextExtent);
+  *p='\0';
+  return(SetImageRegistry(type,key,value,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e I m a g e R e g i s t r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteImageRegistry() deletes a key from the image registry.
+%
+%  The format of the DeleteImageRegistry method is:
+%
+%      MagickBooleanType DeleteImageRegistry(const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o key: the registry.
+%
+*/
+MagickExport MagickBooleanType DeleteImageRegistry(const char *key)
+{
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",key);
+  if (registry == (void *) NULL)
+    return(MagickFalse);
+  return(DeleteNodeFromSplayTree(registry,key));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e R e g i s t r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageRegistry() returns a value associated with an image registry key.
+%
+%  The format of the GetImageRegistry method is:
+%
+%      void *GetImageRegistry(const RegistryType type,const char *key,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type.
+%
+%    o key: the key.
+%
+%    o exception: the exception.
+%
+*/
+MagickExport void *GetImageRegistry(const RegistryType type,const char *key,
+  ExceptionInfo *exception)
+{
+  void
+    *value;
+
+  RegistryInfo
+    *registry_info;
+
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",key);
+  if (registry == (void *) NULL)
+    return((void *) NULL);
+  registry_info=(RegistryInfo *) GetValueFromSplayTree(registry,key);
+  if (registry_info == (void *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),RegistryError,
+        "UnableToGetRegistryID","`%s'",key);
+      return((void *) NULL);
+    }
+  value=(void *) NULL;
+  switch (type)
+  {
+    case ImageRegistryType:
+    {
+      if (type == registry_info->type)
+        value=(void *) CloneImageList((Image *) registry_info->value,exception);
+      break;
+    }
+    case ImageInfoRegistryType:
+    {
+      if (type == registry_info->type)
+        value=(void *) CloneImageInfo((ImageInfo *) registry_info->value);
+      break;
+    }
+    case StringRegistryType:
+    {
+      switch (registry_info->type)
+      {
+        case ImageRegistryType:
+        {
+          value=(Image *) ConstantString(((Image *)
+            registry_info->value)->filename);
+          break;
+        }
+        case ImageInfoRegistryType:
+        {
+          value=(Image *) ConstantString(((ImageInfo *)
+            registry_info->value)->filename);
+          break;
+        }
+        case StringRegistryType:
+        {
+          value=(void *) ConstantString((char *) registry_info->value);
+          break;
+        }
+        default:
+          break;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t I m a g e R e g i s t r y                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextImageRegistry() gets the next image registry value.
+%
+%  The format of the GetNextImageRegistry method is:
+%
+%      char *GetNextImageRegistry(void)
+%
+*/
+MagickExport char *GetNextImageRegistry(void)
+{
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (registry == (void *) NULL)
+    return((char *) NULL);
+  return((char *) GetNextKeyInSplayTree(registry));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e g i s t r y C o m p o n e n t G e n e s i s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RegistryComponentGenesis() instantiates the registry component.
+%
+%  The format of the RegistryComponentGenesis method is:
+%
+%      MagickBooleanType RegistryComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType RegistryComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&registry_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e g i s t r y C o m p o n e n t T e r m i n u s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RegistryComponentTerminus() destroys the registry component.
+%
+%  The format of the DestroyDefines method is:
+%
+%      void RegistryComponentTerminus(void)
+%
+*/
+MagickExport void RegistryComponentTerminus(void)
+{
+  if (registry_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&registry_semaphore);
+  LockSemaphoreInfo(registry_semaphore);
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (registry != (void *) NULL)
+    registry=DestroySplayTree(registry);
+  instantiate_registry=MagickFalse;
+  UnlockSemaphoreInfo(registry_semaphore);
+  DestroySemaphoreInfo(&registry_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e I m a g e R e g i s t r y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveImageRegistry() removes a key from the image registry and returns its
+%  value.
+%
+%  The format of the RemoveImageRegistry method is:
+%
+%      void *RemoveImageRegistry(const char *key)
+%
+%  A description of each parameter follows:
+%
+%    o key: the registry.
+%
+*/
+MagickExport void *RemoveImageRegistry(const char *key)
+{
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",key);
+  if (registry == (void *) NULL)
+    return((void *) NULL);
+  return(RemoveNodeFromSplayTree(registry,key));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t I m a g e R e g i s t r y I t e r a t o r                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetImageRegistryIterator() resets the registry iterator.  Use it in
+%  conjunction with GetNextImageRegistry() to iterate over all the values
+%  in the image registry.
+%
+%  The format of the ResetImageRegistryIterator method is:
+%
+%      ResetImageRegistryIterator(void)
+%
+*/
+MagickExport void ResetImageRegistryIterator(void)
+{
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (registry == (void *) NULL)
+    return;
+  ResetSplayTreeIterator(registry);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t I m a g e R e g i s t r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageRegistry() associates a value with an image registry key.
+%
+%  The format of the SetImageRegistry method is:
+%
+%      MagickBooleanType SetImageRegistry(const RegistryType type,
+%        const char *key,const void *value,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type.
+%
+%    o key: the key.
+%
+%    o value: the value.
+%
+%    o exception: the exception.
+%
+*/
+
+static void *DestroyRegistryNode(void *registry_info)
+{
+  register RegistryInfo
+    *p;
+
+  p=(RegistryInfo *) registry_info;
+  switch (p->type)
+  {
+    case StringRegistryType:
+    default:
+    {
+      p->value=RelinquishMagickMemory(p->value);
+      break;
+    }
+    case ImageRegistryType:
+    {
+      p->value=(void *) DestroyImageList((Image *) p->value);
+      break;
+    }
+    case ImageInfoRegistryType:
+    {
+      p->value=(void *) DestroyImageInfo((ImageInfo *) p->value);
+      break;
+    }
+  }
+  return(RelinquishMagickMemory(p));
+}
+
+MagickExport MagickBooleanType SetImageRegistry(const RegistryType type,
+  const char *key,const void *value,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  RegistryInfo
+    *registry_info;
+
+  void
+    *clone_value;
+
+  if (IsEventLogging() != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",key);
+  clone_value=(void *) NULL;
+  switch (type)
+  {
+    case StringRegistryType:
+    default:
+    {
+      const char
+        *string;
+
+      string=(const char *) value;
+      clone_value=(void *) ConstantString(string);
+      break;
+    }
+    case ImageRegistryType:
+    {
+      const Image
+        *image;
+
+      image=(const Image *) value;
+      if (image->signature != MagickSignature)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),RegistryError,
+            "UnableToSetRegistry","%s",key);
+          return(MagickFalse);
+        }
+      clone_value=(void *) CloneImageList(image,exception);
+      break;
+    }
+    case ImageInfoRegistryType:
+    {
+      const ImageInfo
+        *image_info;
+
+      image_info=(const ImageInfo *) value;
+      if (image_info->signature != MagickSignature)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),RegistryError,
+            "UnableToSetRegistry","%s",key);
+          return(MagickFalse);
+        }
+      clone_value=(void *) CloneImageInfo(image_info);
+      break;
+    }
+  }
+  if (clone_value == (void *) NULL)
+    return(MagickFalse);
+  registry_info=(RegistryInfo *) AcquireMagickMemory(sizeof(*registry_info));
+  if (registry_info == (RegistryInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(registry_info,0,sizeof(*registry_info));
+  registry_info->type=type;
+  registry_info->value=clone_value;
+  registry_info->signature=MagickSignature;
+  if ((registry == (SplayTreeInfo *) NULL) &&
+      (instantiate_registry == MagickFalse))
+    {
+      if (registry_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&registry_semaphore);
+      LockSemaphoreInfo(registry_semaphore);
+      if ((registry == (SplayTreeInfo *) NULL) &&
+          (instantiate_registry == MagickFalse))
+        {
+          registry=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
+            DestroyRegistryNode);
+          instantiate_registry=MagickTrue;
+        }
+      UnlockSemaphoreInfo(registry_semaphore);
+    }
+  status=AddValueToSplayTree(registry,ConstantString(key),registry_info);
+  return(status);
+}
diff --git a/MagickCore/registry.h b/MagickCore/registry.h
new file mode 100644
index 0000000..76869d9
--- /dev/null
+++ b/MagickCore/registry.h
@@ -0,0 +1,53 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore registry methods.
+*/
+#ifndef _MAGICKCORE_REGISTRY_H
+#define _MAGICKCORE_REGISTRY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedRegistryType,
+  ImageRegistryType,
+  ImageInfoRegistryType,
+  StringRegistryType
+} RegistryType;
+
+extern MagickExport char
+  *GetNextImageRegistry(void);
+
+extern MagickExport MagickBooleanType
+  DefineImageRegistry(const RegistryType,const char *,ExceptionInfo *),
+  DeleteImageRegistry(const char *),
+  RegistryComponentGenesis(void),
+  SetImageRegistry(const RegistryType,const char *,const void *,
+    ExceptionInfo *);
+
+extern MagickExport void
+  *GetImageRegistry(const RegistryType,const char *,ExceptionInfo *),
+  RegistryComponentTerminus(void),
+  *RemoveImageRegistry(const char *),
+  ResetImageRegistryIterator(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/resample-private.h b/MagickCore/resample-private.h
new file mode 100644
index 0000000..2658859
--- /dev/null
+++ b/MagickCore/resample-private.h
@@ -0,0 +1,77 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image resampling private methods.
+*/
+#ifndef _MAGICKCORE_RESAMPLE_PRIVATE_H
+#define _MAGICKCORE_RESAMPLE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "MagickCore/thread-private.h"
+
+static inline ResampleFilter **DestroyResampleFilterThreadSet(
+  ResampleFilter **filter)
+{
+  register ssize_t
+    i;
+
+  assert(filter != (ResampleFilter **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (filter[i] != (ResampleFilter *) NULL)
+      filter[i]=DestroyResampleFilter(filter[i]);
+  filter=(ResampleFilter **) RelinquishAlignedMemory(filter);
+  return(filter);
+}
+
+static inline ResampleFilter **AcquireResampleFilterThreadSet(
+  const Image *image,const VirtualPixelMethod method,
+  const MagickBooleanType interpolate,ExceptionInfo *exception)
+{
+  register ssize_t
+    i;
+
+  ResampleFilter
+    **filter;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  filter=(ResampleFilter **) AcquireAlignedMemory(number_threads,
+    sizeof(*filter));
+  if (filter == (ResampleFilter **) NULL)
+    return((ResampleFilter **) NULL);
+  (void) ResetMagickMemory(filter,0,number_threads*sizeof(*filter));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    filter[i]=AcquireResampleFilter(image,exception);
+    if (filter[i] == (ResampleFilter *) NULL)
+      return(DestroyResampleFilterThreadSet(filter));
+    if (method != UndefinedVirtualPixelMethod)
+      (void) SetResampleFilterVirtualPixelMethod(filter[i],method);
+    if (interpolate != MagickFalse)
+      SetResampleFilter(filter[i],PointFilter,1.0);
+  }
+  return(filter);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/resample.c b/MagickCore/resample.c
new file mode 100644
index 0000000..7da164c
--- /dev/null
+++ b/MagickCore/resample.c
@@ -0,0 +1,1435 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           RRRR    EEEEE   SSSSS   AAA   M   M  PPPP   L      EEEEE          %
+%           R   R   E       SS     A   A  MM MM  P   P  L      E              %
+%           RRRR    EEE      SSS   AAAAA  M M M  PPPP   L      EEE            %
+%           R R     E          SS  A   A  M   M  P      L      E              %
+%           R  R    EEEEE   SSSSS  A   A  M   M  P      LLLLL  EEEEE          %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Pixel Resampling Methods                    %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                              Anthony Thyssen                                %
+%                                August 2007                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resize-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/utility.h"
+/*
+  EWA Resampling Options
+*/
+
+/* select ONE resampling method */
+#define EWA 1                 /* Normal EWA handling - raw or clamped */
+                              /* if 0 then use "High Quality EWA" */
+#define EWA_CLAMP 1           /* EWA Clamping from Nicolas Robidoux */
+
+#define FILTER_LUT 1          /* Use a LUT rather then direct filter calls */
+
+/* output debugging information */
+#define DEBUG_ELLIPSE 0       /* output ellipse info for debug */
+#define DEBUG_HIT_MISS 0      /* output hit/miss pixels (as gnuplot commands) */
+#define DEBUG_NO_PIXEL_HIT 0  /* Make pixels that fail to hit anything - RED */
+
+#if ! FILTER_DIRECT
+#define WLUT_WIDTH 1024       /* size of the filter cache */
+#endif
+
+/*
+  Typedef declarations.
+*/
+struct _ResampleFilter
+{
+  CacheView
+    *view;
+
+  Image
+    *image;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    debug;
+
+  /* Information about image being resampled */
+  ssize_t
+    image_area;
+
+  InterpolatePixelMethod
+    interpolate;
+
+  VirtualPixelMethod
+    virtual_pixel;
+
+  FilterTypes
+    filter;
+
+  /* processing settings needed */
+  MagickBooleanType
+    limit_reached,
+    do_interpolate,
+    average_defined;
+
+  PixelInfo
+    average_pixel;
+
+  /* current ellipitical area being resampled around center point */
+  double
+    A, B, C,
+    Vlimit, Ulimit, Uwidth, slope;
+
+#if FILTER_LUT
+  /* LUT of weights for filtered average in elliptical area */
+  double
+    filter_lut[WLUT_WIDTH];
+#else
+  /* Use a Direct call to the filter functions */
+  ResizeFilter
+    *filter_def;
+
+  double
+    F;
+#endif
+
+  /* the practical working support of the filter */
+  double
+    support;
+
+  size_t
+    signature;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e R e s a m p l e I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireResampleFilter() initializes the information resample needs do to a
+%  scaled lookup of a color from an image, using area sampling.
+%
+%  The algorithm is based on a Elliptical Weighted Average, where the pixels
+%  found in a large elliptical area is averaged together according to a
+%  weighting (filter) function.  For more details see "Fundamentals of Texture
+%  Mapping and Image Warping" a master's thesis by Paul.S.Heckbert, June 17,
+%  1989.  Available for free from, http://www.cs.cmu.edu/~ph/
+%
+%  As EWA resampling (or any sort of resampling) can require a lot of
+%  calculations to produce a distorted scaling of the source image for each
+%  output pixel, the ResampleFilter structure generated holds that information
+%  between individual image resampling.
+%
+%  This function will make the appropriate AcquireCacheView() calls
+%  to view the image, calling functions do not need to open a cache view.
+%
+%  Usage Example...
+%      resample_filter=AcquireResampleFilter(image,exception);
+%      SetResampleFilter(resample_filter, GaussianFilter, 1.0);
+%      for (y=0; y < (ssize_t) image->rows; y++) {
+%        for (x=0; x < (ssize_t) image->columns; x++) {
+%          u= ....;   v= ....;
+%          ScaleResampleFilter(resample_filter, ... scaling vectors ...);
+%          (void) ResamplePixelColor(resample_filter,u,v,&pixel);
+%          ... assign resampled pixel value ...
+%        }
+%      }
+%      DestroyResampleFilter(resample_filter);
+%
+%  The format of the AcquireResampleFilter method is:
+%
+%     ResampleFilter *AcquireResampleFilter(const Image *image,
+%       ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ResampleFilter *AcquireResampleFilter(const Image *image,
+  ExceptionInfo *exception)
+{
+  register ResampleFilter
+    *resample_filter;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+
+  resample_filter=(ResampleFilter *) AcquireMagickMemory(
+    sizeof(*resample_filter));
+  if (resample_filter == (ResampleFilter *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(resample_filter,0,sizeof(*resample_filter));
+
+  resample_filter->exception=exception;
+  resample_filter->image=ReferenceImage((Image *) image);
+  resample_filter->view=AcquireCacheView(resample_filter->image);
+
+  resample_filter->debug=IsEventLogging();
+  resample_filter->signature=MagickSignature;
+
+  resample_filter->image_area=(ssize_t) (image->columns*image->rows);
+  resample_filter->average_defined = MagickFalse;
+
+  /* initialise the resampling filter settings */
+  SetResampleFilter(resample_filter, image->filter, image->blur);
+  (void) SetResampleFilterInterpolateMethod(resample_filter,
+    image->interpolate);
+  (void) SetResampleFilterVirtualPixelMethod(resample_filter,
+    GetImageVirtualPixelMethod(image));
+
+  return(resample_filter);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y R e s a m p l e I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyResampleFilter() finalizes and cleans up the resampling
+%  resample_filter as returned by AcquireResampleFilter(), freeing any memory
+%  or other information as needed.
+%
+%  The format of the DestroyResampleFilter method is:
+%
+%      ResampleFilter *DestroyResampleFilter(ResampleFilter *resample_filter)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: resampling information structure
+%
+*/
+MagickExport ResampleFilter *DestroyResampleFilter(
+  ResampleFilter *resample_filter)
+{
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+  assert(resample_filter->image != (Image *) NULL);
+  if (resample_filter->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      resample_filter->image->filename);
+  resample_filter->view=DestroyCacheView(resample_filter->view);
+  resample_filter->image=DestroyImage(resample_filter->image);
+#if ! FILTER_LUT
+  resample_filter->filter_def=DestroyResizeFilter(resample_filter->filter_def);
+#endif
+  resample_filter->signature=(~MagickSignature);
+  resample_filter=(ResampleFilter *) RelinquishMagickMemory(resample_filter);
+  return(resample_filter);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s a m p l e P i x e l C o l o r                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResamplePixelColor() samples the pixel values surrounding the location
+%  given using an elliptical weighted average, at the scale previously
+%  calculated, and in the most efficent manner possible for the
+%  VirtualPixelMethod setting.
+%
+%  The format of the ResamplePixelColor method is:
+%
+%     MagickBooleanType ResamplePixelColor(ResampleFilter *resample_filter,
+%       const double u0,const double v0,PixelInfo *pixel)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: the resample filter.
+%
+%    o u0,v0: A double representing the center of the area to resample,
+%        The distortion transformed transformed x,y coordinate.
+%
+%    o pixel: the resampled pixel is returned here.
+%
+*/
+MagickExport MagickBooleanType ResamplePixelColor(
+  ResampleFilter *resample_filter,const double u0,const double v0,
+  PixelInfo *pixel)
+{
+  MagickBooleanType
+    status;
+
+  ssize_t u,v, v1, v2, uw, hit;
+  double u1;
+  double U,V,Q,DQ,DDQ;
+  double divisor_c,divisor_m;
+  register double weight;
+  register const Quantum *pixels;
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+
+  status=MagickTrue;
+  /* GetPixelInfo(resample_filter->image,pixel); */
+  if ( resample_filter->do_interpolate ) {
+    status=InterpolatePixelInfo(resample_filter->image,
+      resample_filter->view,resample_filter->interpolate,u0,v0,pixel,
+      resample_filter->exception);
+    return(status);
+  }
+
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "u0=%lf; v0=%lf;\n", u0, v0);
+#endif
+
+  /*
+    Does resample area Miss the image?
+    And is that area a simple solid color - then return that color
+  */
+  hit = 0;
+  switch ( resample_filter->virtual_pixel ) {
+    case BackgroundVirtualPixelMethod:
+    case TransparentVirtualPixelMethod:
+    case BlackVirtualPixelMethod:
+    case GrayVirtualPixelMethod:
+    case WhiteVirtualPixelMethod:
+    case MaskVirtualPixelMethod:
+      if ( resample_filter->limit_reached
+           || u0 + resample_filter->Ulimit < 0.0
+           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
+           || v0 + resample_filter->Vlimit < 0.0
+           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
+           )
+        hit++;
+      break;
+
+    case UndefinedVirtualPixelMethod:
+    case EdgeVirtualPixelMethod:
+      if (    ( u0 + resample_filter->Ulimit < 0.0 && v0 + resample_filter->Vlimit < 0.0 )
+           || ( u0 + resample_filter->Ulimit < 0.0
+                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
+           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
+                && v0 + resample_filter->Vlimit < 0.0 )
+           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
+                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows )
+           )
+        hit++;
+      break;
+    case HorizontalTileVirtualPixelMethod:
+      if (    v0 + resample_filter->Vlimit < 0.0
+           || v0 - resample_filter->Vlimit > (double) resample_filter->image->rows
+           )
+        hit++;  /* outside the horizontally tiled images. */
+      break;
+    case VerticalTileVirtualPixelMethod:
+      if (    u0 + resample_filter->Ulimit < 0.0
+           || u0 - resample_filter->Ulimit > (double) resample_filter->image->columns
+           )
+        hit++;  /* outside the vertically tiled images. */
+      break;
+    case DitherVirtualPixelMethod:
+      if (    ( u0 + resample_filter->Ulimit < -32.0 && v0 + resample_filter->Vlimit < -32.0 )
+           || ( u0 + resample_filter->Ulimit < -32.0
+                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
+           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
+                && v0 + resample_filter->Vlimit < -32.0 )
+           || ( u0 - resample_filter->Ulimit > (double) resample_filter->image->columns+32.0
+                && v0 - resample_filter->Vlimit > (double) resample_filter->image->rows+32.0 )
+           )
+        hit++;
+      break;
+    case TileVirtualPixelMethod:
+    case MirrorVirtualPixelMethod:
+    case RandomVirtualPixelMethod:
+    case HorizontalTileEdgeVirtualPixelMethod:
+    case VerticalTileEdgeVirtualPixelMethod:
+    case CheckerTileVirtualPixelMethod:
+      /* resampling of area is always needed - no VP limits */
+      break;
+  }
+  if ( hit ) {
+    /* whole area is a solid color -- just return that color */
+    status=InterpolatePixelInfo(resample_filter->image,
+      resample_filter->view,IntegerInterpolatePixel,u0,v0,pixel,
+      resample_filter->exception);
+    return(status);
+  }
+
+  /*
+    Scaling limits reached, return an 'averaged' result.
+  */
+  if ( resample_filter->limit_reached ) {
+    switch ( resample_filter->virtual_pixel ) {
+      /*  This is always handled by the above, so no need.
+        case BackgroundVirtualPixelMethod:
+        case ConstantVirtualPixelMethod:
+        case TransparentVirtualPixelMethod:
+        case GrayVirtualPixelMethod,
+        case WhiteVirtualPixelMethod
+        case MaskVirtualPixelMethod:
+      */
+      case UndefinedVirtualPixelMethod:
+      case EdgeVirtualPixelMethod:
+      case DitherVirtualPixelMethod:
+      case HorizontalTileEdgeVirtualPixelMethod:
+      case VerticalTileEdgeVirtualPixelMethod:
+        /* We need an average edge pixel, from the correct edge!
+           How should I calculate an average edge color?
+           Just returning an averaged neighbourhood,
+           works well in general, but falls down for TileEdge methods.
+           This needs to be done properly!!!!!!
+        */
+        status=InterpolatePixelInfo(resample_filter->image,
+          resample_filter->view,AverageInterpolatePixel,u0,v0,pixel,
+          resample_filter->exception);
+        break;
+      case HorizontalTileVirtualPixelMethod:
+      case VerticalTileVirtualPixelMethod:
+        /* just return the background pixel - Is there more direct way? */
+        status=InterpolatePixelInfo(resample_filter->image,
+          resample_filter->view,IntegerInterpolatePixel,-1.0,-1.0,pixel,
+          resample_filter->exception);
+        break;
+      case TileVirtualPixelMethod:
+      case MirrorVirtualPixelMethod:
+      case RandomVirtualPixelMethod:
+      case CheckerTileVirtualPixelMethod:
+      default:
+        /* generate a average color of the WHOLE image */
+        if ( resample_filter->average_defined == MagickFalse ) {
+          Image
+            *average_image;
+
+          CacheView
+            *average_view;
+
+          GetPixelInfo(resample_filter->image,(PixelInfo *)
+            &resample_filter->average_pixel);
+          resample_filter->average_defined=MagickTrue;
+
+          /* Try to get an averaged pixel color of whole image */
+          average_image=ResizeImage(resample_filter->image,1,1,BoxFilter,1.0,
+            resample_filter->exception);
+          if (average_image == (Image *) NULL)
+            {
+              *pixel=resample_filter->average_pixel; /* FAILED */
+              break;
+            }
+          average_view=AcquireCacheView(average_image);
+          pixels=GetCacheViewVirtualPixels(average_view,0,0,1,1,
+            resample_filter->exception);
+          if (pixels == (const Quantum *) NULL) {
+            average_view=DestroyCacheView(average_view);
+            average_image=DestroyImage(average_image);
+            *pixel=resample_filter->average_pixel; /* FAILED */
+            break;
+          }
+          SetPixelInfo(resample_filter->image,pixels,
+            &(resample_filter->average_pixel));
+          average_view=DestroyCacheView(average_view);
+          average_image=DestroyImage(average_image);
+
+          if ( resample_filter->virtual_pixel == CheckerTileVirtualPixelMethod )
+            {
+              /* CheckerTile is avergae of image average half background */
+              /* FUTURE: replace with a 50% blend of both pixels */
+
+              weight = QuantumScale*((MagickRealType)
+                resample_filter->average_pixel.alpha);
+              resample_filter->average_pixel.red *= weight;
+              resample_filter->average_pixel.green *= weight;
+              resample_filter->average_pixel.blue *= weight;
+              divisor_c = weight;
+
+              weight = QuantumScale*((MagickRealType)
+                resample_filter->image->background_color.alpha);
+              resample_filter->average_pixel.red +=
+                      weight*resample_filter->image->background_color.red;
+              resample_filter->average_pixel.green +=
+                      weight*resample_filter->image->background_color.green;
+              resample_filter->average_pixel.blue +=
+                      weight*resample_filter->image->background_color.blue;
+              resample_filter->average_pixel.alpha +=
+                      resample_filter->image->background_color.alpha;
+              divisor_c += weight;
+
+              resample_filter->average_pixel.red /= divisor_c;
+              resample_filter->average_pixel.green /= divisor_c;
+              resample_filter->average_pixel.blue /= divisor_c;
+              resample_filter->average_pixel.alpha /= 2;
+
+            }
+        }
+        *pixel=resample_filter->average_pixel;
+        break;
+    }
+    return(status);
+  }
+
+  /*
+    Initialize weighted average data collection
+  */
+  hit = 0;
+  divisor_c = 0.0;
+  divisor_m = 0.0;
+  pixel->red = pixel->green = pixel->blue = 0.0;
+  if (pixel->colorspace == CMYKColorspace)
+    pixel->black = 0.0;
+  if (pixel->matte != MagickFalse)
+    pixel->alpha = 0.0;
+
+  /*
+    Determine the parellelogram bounding box fitted to the ellipse
+    centered at u0,v0.  This area is bounding by the lines...
+  */
+  v1 = (ssize_t)ceil(v0 - resample_filter->Vlimit);  /* range of scan lines */
+  v2 = (ssize_t)floor(v0 + resample_filter->Vlimit);
+
+  /* scan line start and width accross the parallelogram */
+  u1 = u0 + (v1-v0)*resample_filter->slope - resample_filter->Uwidth;
+  uw = (ssize_t)(2.0*resample_filter->Uwidth)+1;
+
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "v1=%ld; v2=%ld\n", (long)v1, (long)v2);
+  (void) FormatLocaleFile(stderr, "u1=%ld; uw=%ld\n", (long)u1, (long)uw);
+#else
+# define DEBUG_HIT_MISS 0 /* only valid if DEBUG_ELLIPSE is enabled */
+#endif
+
+  /*
+    Do weighted resampling of all pixels,  within the scaled ellipse,
+    bound by a Parellelogram fitted to the ellipse.
+  */
+  DDQ = 2*resample_filter->A;
+  for( v=v1; v<=v2;  v++ ) {
+#if DEBUG_HIT_MISS
+    long uu = ceil(u1);   /* actual pixel location (for debug only) */
+    (void) FormatLocaleFile(stderr, "# scan line from pixel %ld, %ld\n", (long)uu, (long)v);
+#endif
+    u = (ssize_t)ceil(u1);        /* first pixel in scanline */
+    u1 += resample_filter->slope; /* start of next scan line */
+
+
+    /* location of this first pixel, relative to u0,v0 */
+    U = (double)u-u0;
+    V = (double)v-v0;
+
+    /* Q = ellipse quotent ( if Q<F then pixel is inside ellipse) */
+    Q = (resample_filter->A*U + resample_filter->B*V)*U + resample_filter->C*V*V;
+    DQ = resample_filter->A*(2.0*U+1) + resample_filter->B*V;
+
+    /* get the scanline of pixels for this v */
+    pixels=GetCacheViewVirtualPixels(resample_filter->view,u,v,(size_t) uw,
+      1,resample_filter->exception);
+    if (pixels == (const Quantum *) NULL)
+      return(MagickFalse);
+
+    /* count up the weighted pixel colors */
+    for( u=0; u<uw; u++ ) {
+#if FILTER_LUT
+      /* Note that the ellipse has been pre-scaled so F = WLUT_WIDTH */
+      if ( Q < (double)WLUT_WIDTH ) {
+        weight = resample_filter->filter_lut[(int)Q];
+#else
+      /* Note that the ellipse has been pre-scaled so F = support^2 */
+      if ( Q < (double)resample_filter->F ) {
+        weight = GetResizeFilterWeight(resample_filter->filter_def,
+             sqrt(Q));    /* a SquareRoot!  Arrggghhhhh... */
+#endif
+
+        pixel->alpha  += weight*GetPixelAlpha(resample_filter->image,pixels);
+        divisor_m += weight;
+
+        if (pixel->matte != MagickFalse)
+          weight *= QuantumScale*((MagickRealType) GetPixelAlpha(resample_filter->image,pixels));
+        pixel->red   += weight*GetPixelRed(resample_filter->image,pixels);
+        pixel->green += weight*GetPixelGreen(resample_filter->image,pixels);
+        pixel->blue  += weight*GetPixelBlue(resample_filter->image,pixels);
+        if (pixel->colorspace == CMYKColorspace)
+          pixel->black += weight*GetPixelBlack(resample_filter->image,pixels);
+        divisor_c += weight;
+
+        hit++;
+#if DEBUG_HIT_MISS
+        /* mark the pixel according to hit/miss of the ellipse */
+        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
+                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
+        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 3\n",
+                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
+      } else {
+        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
+                     (long)uu-.1,(double)v-.1,(long)uu+.1,(long)v+.1);
+        (void) FormatLocaleFile(stderr, "set arrow from %lf,%lf to %lf,%lf nohead ls 1\n",
+                     (long)uu+.1,(double)v-.1,(long)uu-.1,(long)v+.1);
+      }
+      uu++;
+#else
+      }
+#endif
+      pixels+=GetPixelChannels(resample_filter->image);
+      Q += DQ;
+      DQ += DDQ;
+    }
+  }
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "Hit=%ld;  Total=%ld;\n", (long)hit, (long)uw*(v2-v1) );
+#endif
+
+  /*
+    Result sanity check -- this should NOT happen
+  */
+  if ( hit == 0 ) {
+    /* not enough pixels in resampling, resort to direct interpolation */
+#if DEBUG_NO_PIXEL_HIT
+    pixel->alpha = pixel->red = pixel->green = pixel->blue = 0;
+    pixel->red = QuantumRange; /* show pixels for which EWA fails */
+#else
+    status=InterpolatePixelInfo(resample_filter->image,
+      resample_filter->view,resample_filter->interpolate,u0,v0,pixel,
+      resample_filter->exception);
+#endif
+    return status;
+  }
+
+  /*
+    Finialize results of resampling
+  */
+  divisor_m = 1.0/divisor_m;
+  pixel->alpha = (MagickRealType) ClampToQuantum(divisor_m*pixel->alpha);
+  divisor_c = 1.0/divisor_c;
+  pixel->red   = (MagickRealType) ClampToQuantum(divisor_c*pixel->red);
+  pixel->green = (MagickRealType) ClampToQuantum(divisor_c*pixel->green);
+  pixel->blue  = (MagickRealType) ClampToQuantum(divisor_c*pixel->blue);
+  if (pixel->colorspace == CMYKColorspace)
+    pixel->black = (MagickRealType) ClampToQuantum(divisor_c*pixel->black);
+  return(MagickTrue);
+}
+
+#if EWA && EWA_CLAMP
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+-   C l a m p U p A x e s                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ClampUpAxes() function converts the input vectors into a major and
+% minor axis unit vectors, and their magnitude.  This allows us to
+% ensure that the ellipse generated is never smaller than the unit
+% circle and thus never too small for use in EWA resampling.
+%
+% This purely mathematical 'magic' was provided by Professor Nicolas
+% Robidoux and his Masters student Chantal Racette.
+%
+% Reference: "We Recommend Singular Value Decomposition", David Austin
+%   http://www.ams.org/samplings/feature-column/fcarc-svd
+%
+% By generating major and minor axis vectors, we can actually use the
+% ellipse in its "canonical form", by remapping the dx,dy of the
+% sampled point into distances along the major and minor axis unit
+% vectors.
+%
+% Reference: http://en.wikipedia.org/wiki/Ellipse#Canonical_form
+*/
+static inline void ClampUpAxes(const double dux,
+			       const double dvx,
+			       const double duy,
+			       const double dvy,
+			       double *major_mag,
+			       double *minor_mag,
+			       double *major_unit_x,
+			       double *major_unit_y,
+			       double *minor_unit_x,
+			       double *minor_unit_y)
+{
+  /*
+   * ClampUpAxes takes an input 2x2 matrix
+   *
+   * [ a b ] = [ dux duy ]
+   * [ c d ] = [ dvx dvy ]
+   *
+   * and computes from it the major and minor axis vectors [major_x,
+   * major_y] and [minor_x,minor_y] of the smallest ellipse containing
+   * both the unit disk and the ellipse which is the image of the unit
+   * disk by the linear transformation
+   *
+   * [ dux duy ] [S] = [s]
+   * [ dvx dvy ] [T] = [t]
+   *
+   * (The vector [S,T] is the difference between a position in output
+   * space and [X,Y]; the vector [s,t] is the difference between a
+   * position in input space and [x,y].)
+   */
+  /*
+   * Output:
+   *
+   * major_mag is the half-length of the major axis of the "new"
+   * ellipse.
+   *
+   * minor_mag is the half-length of the minor axis of the "new"
+   * ellipse.
+   *
+   * major_unit_x is the x-coordinate of the major axis direction vector
+   * of both the "old" and "new" ellipses.
+   *
+   * major_unit_y is the y-coordinate of the major axis direction vector.
+   *
+   * minor_unit_x is the x-coordinate of the minor axis direction vector.
+   *
+   * minor_unit_y is the y-coordinate of the minor axis direction vector.
+   *
+   * Unit vectors are useful for computing projections, in particular,
+   * to compute the distance between a point in output space and the
+   * center of a unit disk in output space, using the position of the
+   * corresponding point [s,t] in input space. Following the clamping,
+   * the square of this distance is
+   *
+   * ( ( s * major_unit_x + t * major_unit_y ) / major_mag )^2
+   * +
+   * ( ( s * minor_unit_x + t * minor_unit_y ) / minor_mag )^2
+   *
+   * If such distances will be computed for many [s,t]'s, it makes
+   * sense to actually compute the reciprocal of major_mag and
+   * minor_mag and multiply them by the above unit lengths.
+   *
+   * Now, if you want to modify the input pair of tangent vectors so
+   * that it defines the modified ellipse, all you have to do is set
+   *
+   * newdux = major_mag * major_unit_x
+   * newdvx = major_mag * major_unit_y
+   * newduy = minor_mag * minor_unit_x = minor_mag * -major_unit_y
+   * newdvy = minor_mag * minor_unit_y = minor_mag *  major_unit_x
+   *
+   * and use these tangent vectors as if they were the original ones.
+   * Usually, this is a drastic change in the tangent vectors even if
+   * the singular values are not clamped; for example, the minor axis
+   * vector always points in a direction which is 90 degrees
+   * counterclockwise from the direction of the major axis vector.
+   */
+  /*
+   * Discussion:
+   *
+   * GOAL: Fix things so that the pullback, in input space, of a disk
+   * of radius r in output space is an ellipse which contains, at
+   * least, a disc of radius r. (Make this hold for any r>0.)
+   *
+   * ESSENCE OF THE METHOD: Compute the product of the first two
+   * factors of an SVD of the linear transformation defining the
+   * ellipse and make sure that both its columns have norm at least 1.
+   * Because rotations and reflexions map disks to themselves, it is
+   * not necessary to compute the third (rightmost) factor of the SVD.
+   *
+   * DETAILS: Find the singular values and (unit) left singular
+   * vectors of Jinv, clampling up the singular values to 1, and
+   * multiply the unit left singular vectors by the new singular
+   * values in order to get the minor and major ellipse axis vectors.
+   *
+   * Image resampling context:
+   *
+   * The Jacobian matrix of the transformation at the output point
+   * under consideration is defined as follows:
+   *
+   * Consider the transformation (x,y) -> (X,Y) from input locations
+   * to output locations. (Anthony Thyssen, elsewhere in resample.c,
+   * uses the notation (u,v) -> (x,y).)
+   *
+   * The Jacobian matrix of the transformation at (x,y) is equal to
+   *
+   *   J = [ A, B ] = [ dX/dx, dX/dy ]
+   *       [ C, D ]   [ dY/dx, dY/dy ]
+   *
+   * that is, the vector [A,C] is the tangent vector corresponding to
+   * input changes in the horizontal direction, and the vector [B,D]
+   * is the tangent vector corresponding to input changes in the
+   * vertical direction.
+   *
+   * In the context of resampling, it is natural to use the inverse
+   * Jacobian matrix Jinv because resampling is generally performed by
+   * pulling pixel locations in the output image back to locations in
+   * the input image. Jinv is
+   *
+   *   Jinv = [ a, b ] = [ dx/dX, dx/dY ]
+   *          [ c, d ]   [ dy/dX, dy/dY ]
+   *
+   * Note: Jinv can be computed from J with the following matrix
+   * formula:
+   *
+   *   Jinv = 1/(A*D-B*C) [  D, -B ]
+   *                      [ -C,  A ]
+   *
+   * What we do is modify Jinv so that it generates an ellipse which
+   * is as close as possible to the original but which contains the
+   * unit disk. This can be accomplished as follows:
+   *
+   * Let
+   *
+   *   Jinv = U Sigma V^T
+   *
+   * be an SVD decomposition of Jinv. (The SVD is not unique, but the
+   * final ellipse does not depend on the particular SVD.)
+   *
+   * We could clamp up the entries of the diagonal matrix Sigma so
+   * that they are at least 1, and then set
+   *
+   *   Jinv = U newSigma V^T.
+   *
+   * However, we do not need to compute V for the following reason:
+   * V^T is an orthogonal matrix (that is, it represents a combination
+   * of rotations and reflexions) so that it maps the unit circle to
+   * itself. For this reason, the exact value of V does not affect the
+   * final ellipse, and we can choose V to be the identity
+   * matrix. This gives
+   *
+   *   Jinv = U newSigma.
+   *
+   * In the end, we return the two diagonal entries of newSigma
+   * together with the two columns of U.
+   */
+  /*
+   * ClampUpAxes was written by Nicolas Robidoux and Chantal Racette
+   * of Laurentian University with insightful suggestions from Anthony
+   * Thyssen and funding from the National Science and Engineering
+   * Research Council of Canada. It is distinguished from its
+   * predecessors by its efficient handling of degenerate cases.
+   *
+   * The idea of clamping up the EWA ellipse's major and minor axes so
+   * that the result contains the reconstruction kernel filter support
+   * is taken from Andreas Gustaffson's Masters thesis "Interactive
+   * Image Warping", Helsinki University of Technology, Faculty of
+   * Information Technology, 59 pages, 1993 (see Section 3.6).
+   *
+   * The use of the SVD to clamp up the singular values of the
+   * Jacobian matrix of the pullback transformation for EWA resampling
+   * is taken from the astrophysicist Craig DeForest.  It is
+   * implemented in his PDL::Transform code (PDL = Perl Data
+   * Language).
+   */
+  const double a = dux;
+  const double b = duy;
+  const double c = dvx;
+  const double d = dvy;
+  /*
+   * n is the matrix Jinv * transpose(Jinv). Eigenvalues of n are the
+   * squares of the singular values of Jinv.
+   */
+  const double aa = a*a;
+  const double bb = b*b;
+  const double cc = c*c;
+  const double dd = d*d;
+  /*
+   * Eigenvectors of n are left singular vectors of Jinv.
+   */
+  const double n11 = aa+bb;
+  const double n12 = a*c+b*d;
+  const double n21 = n12;
+  const double n22 = cc+dd;
+  const double det = a*d-b*c;
+  const double twice_det = det+det;
+  const double frobenius_squared = n11+n22;
+  const double discriminant =
+    (frobenius_squared+twice_det)*(frobenius_squared-twice_det);
+  const double sqrt_discriminant = sqrt(discriminant);
+  /*
+   * s1 is the largest singular value of the inverse Jacobian
+   * matrix. In other words, its reciprocal is the smallest singular
+   * value of the Jacobian matrix itself.
+   * If s1 = 0, both singular values are 0, and any orthogonal pair of
+   * left and right factors produces a singular decomposition of Jinv.
+   */
+  /*
+   * Initially, we only compute the squares of the singular values.
+   */
+  const double s1s1 = 0.5*(frobenius_squared+sqrt_discriminant);
+  /*
+   * s2 the smallest singular value of the inverse Jacobian
+   * matrix. Its reciprocal is the largest singular value of the
+   * Jacobian matrix itself.
+   */
+  const double s2s2 = 0.5*(frobenius_squared-sqrt_discriminant);
+  const double s1s1minusn11 = s1s1-n11;
+  const double s1s1minusn22 = s1s1-n22;
+  /*
+   * u1, the first column of the U factor of a singular decomposition
+   * of Jinv, is a (non-normalized) left singular vector corresponding
+   * to s1. It has entries u11 and u21. We compute u1 from the fact
+   * that it is an eigenvector of n corresponding to the eigenvalue
+   * s1^2.
+   */
+  const double s1s1minusn11_squared = s1s1minusn11*s1s1minusn11;
+  const double s1s1minusn22_squared = s1s1minusn22*s1s1minusn22;
+  /*
+   * The following selects the largest row of n-s1^2 I as the one
+   * which is used to find the eigenvector. If both s1^2-n11 and
+   * s1^2-n22 are zero, n-s1^2 I is the zero matrix.  In that case,
+   * any vector is an eigenvector; in addition, norm below is equal to
+   * zero, and, in exact arithmetic, this is the only case in which
+   * norm = 0. So, setting u1 to the simple but arbitrary vector [1,0]
+   * if norm = 0 safely takes care of all cases.
+   */
+  const double temp_u11 =
+    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? n12 : s1s1minusn22 );
+  const double temp_u21 =
+    ( (s1s1minusn11_squared>=s1s1minusn22_squared) ? s1s1minusn11 : n21 );
+  const double norm = sqrt(temp_u11*temp_u11+temp_u21*temp_u21);
+  /*
+   * Finalize the entries of first left singular vector (associated
+   * with the largest singular value).
+   */
+  const double u11 = ( (norm>0.0) ? temp_u11/norm : 1.0 );
+  const double u21 = ( (norm>0.0) ? temp_u21/norm : 0.0 );
+  /*
+   * Clamp the singular values up to 1.
+   */
+  *major_mag = ( (s1s1<=1.0) ? 1.0 : sqrt(s1s1) );
+  *minor_mag = ( (s2s2<=1.0) ? 1.0 : sqrt(s2s2) );
+  /*
+   * Return the unit major and minor axis direction vectors.
+   */
+  *major_unit_x = u11;
+  *major_unit_y = u21;
+  *minor_unit_x = -u21;
+  *minor_unit_y = u11;
+}
+
+#endif
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S c a l e R e s a m p l e F i l t e r                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ScaleResampleFilter() does all the calculations needed to resample an image
+%  at a specific scale, defined by two scaling vectors.  This not using
+%  a orthogonal scaling, but two distorted scaling vectors, to allow the
+%  generation of a angled ellipse.
+%
+%  As only two deritive scaling vectors are used the center of the ellipse
+%  must be the center of the lookup.  That is any curvature that the
+%  distortion may produce is discounted.
+%
+%  The input vectors are produced by either finding the derivitives of the
+%  distortion function, or the partial derivitives from a distortion mapping.
+%  They do not need to be the orthogonal dx,dy scaling vectors, but can be
+%  calculated from other derivatives.  For example you could use  dr,da/r
+%  polar coordinate vector scaling vectors
+%
+%  If   u,v =  DistortEquation(x,y)   OR   u = Fu(x,y); v = Fv(x,y)
+%  Then the scaling vectors are determined from the deritives...
+%      du/dx, dv/dx     and    du/dy, dv/dy
+%  If the resulting scaling vectors is othogonally aligned then...
+%      dv/dx = 0   and   du/dy  =  0
+%  Producing an othogonally alligned ellipse in source space for the area to
+%  be resampled.
+%
+%  Note that scaling vectors are different to argument order.  Argument order
+%  is the general order the deritives are extracted from the distortion
+%  equations, and not the scaling vectors. As such the middle two vaules
+%  may be swapped from what you expect.  Caution is advised.
+%
+%  WARNING: It is assumed that any SetResampleFilter() method call will
+%  always be performed before the ScaleResampleFilter() method, so that the
+%  size of the ellipse will match the support for the resampling filter being
+%  used.
+%
+%  The format of the ScaleResampleFilter method is:
+%
+%     void ScaleResampleFilter(const ResampleFilter *resample_filter,
+%       const double dux,const double duy,const double dvx,const double dvy)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: the resampling resample_filterrmation defining the
+%      image being resampled
+%
+%    o dux,duy,dvx,dvy:
+%         The deritives or scaling vectors defining the EWA ellipse.
+%         NOTE: watch the order, which is based on the order deritives
+%         are usally determined from distortion equations (see above).
+%         The middle two values may need to be swapped if you are thinking
+%         in terms of scaling vectors.
+%
+*/
+MagickExport void ScaleResampleFilter(ResampleFilter *resample_filter,
+  const double dux,const double duy,const double dvx,const double dvy)
+{
+  double A,B,C,F;
+
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+
+  resample_filter->limit_reached = MagickFalse;
+
+  /* A 'point' filter forces use of interpolation instead of area sampling */
+  if ( resample_filter->filter == PointFilter )
+    return; /* EWA turned off - nothing to do */
+
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "# -----\n" );
+  (void) FormatLocaleFile(stderr, "dux=%lf; dvx=%lf;   duy=%lf; dvy=%lf;\n",
+       dux, dvx, duy, dvy);
+#endif
+
+  /* Find Ellipse Coefficents such that
+        A*u^2 + B*u*v + C*v^2 = F
+     With u,v relative to point around which we are resampling.
+     And the given scaling dx,dy vectors in u,v space
+         du/dx,dv/dx   and  du/dy,dv/dy
+  */
+#if EWA
+  /* Direct conversion of derivatives into elliptical coefficients
+     However when magnifying images, the scaling vectors will be small
+     resulting in a ellipse that is too small to sample properly.
+     As such we need to clamp the major/minor axis to a minumum of 1.0
+     to prevent it getting too small.
+  */
+#if EWA_CLAMP
+  { double major_mag,
+           minor_mag,
+           major_x,
+           major_y,
+           minor_x,
+           minor_y;
+
+  ClampUpAxes(dux,dvx,duy,dvy, &major_mag, &minor_mag,
+                &major_x, &major_y, &minor_x, &minor_y);
+  major_x *= major_mag;  major_y *= major_mag;
+  minor_x *= minor_mag;  minor_y *= minor_mag;
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "major_x=%lf; major_y=%lf;  minor_x=%lf; minor_y=%lf;\n",
+        major_x, major_y, minor_x, minor_y);
+#endif
+  A = major_y*major_y+minor_y*minor_y;
+  B = -2.0*(major_x*major_y+minor_x*minor_y);
+  C = major_x*major_x+minor_x*minor_x;
+  F = major_mag*minor_mag;
+  F *= F; /* square it */
+  }
+#else /* raw unclamped EWA */
+  A = dvx*dvx+dvy*dvy;
+  B = -2.0*(dux*dvx+duy*dvy);
+  C = dux*dux+duy*duy;
+  F = dux*dvy-duy*dvx;
+  F *= F; /* square it */
+#endif /* EWA_CLAMP */
+
+#else /* HQ_EWA */
+  /*
+    This Paul Heckbert's "Higher Quality EWA" formula, from page 60 in his
+    thesis, which adds a unit circle to the elliptical area so as to do both
+    Reconstruction and Prefiltering of the pixels in the resampling.  It also
+    means it is always likely to have at least 4 pixels within the area of the
+    ellipse, for weighted averaging.  No scaling will result with F == 4.0 and
+    a circle of radius 2.0, and F smaller than this means magnification is
+    being used.
+
+    NOTE: This method produces a very blury result at near unity scale while
+    producing perfect results for strong minitification and magnifications.
+
+    However filter support is fixed to 2.0 (no good for Windowed Sinc filters)
+  */
+  A = dvx*dvx+dvy*dvy+1;
+  B = -2.0*(dux*dvx+duy*dvy);
+  C = dux*dux+duy*duy+1;
+  F = A*C - B*B/4;
+#endif
+
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "A=%lf; B=%lf; C=%lf; F=%lf\n", A,B,C,F);
+
+  /* Figure out the various information directly about the ellipse.
+     This information currently not needed at this time, but may be
+     needed later for better limit determination.
+
+     It is also good to have as a record for future debugging
+  */
+  { double alpha, beta, gamma, Major, Minor;
+    double Eccentricity, Ellipse_Area, Ellipse_Angle;
+
+    alpha = A+C;
+    beta  = A-C;
+    gamma = sqrt(beta*beta + B*B );
+
+    if ( alpha - gamma <= MagickEpsilon )
+      Major = MagickHuge;
+    else
+      Major = sqrt(2*F/(alpha - gamma));
+    Minor = sqrt(2*F/(alpha + gamma));
+
+    (void) FormatLocaleFile(stderr, "# Major=%lf; Minor=%lf\n", Major, Minor );
+
+    /* other information about ellipse include... */
+    Eccentricity = Major/Minor;
+    Ellipse_Area = MagickPI*Major*Minor;
+    Ellipse_Angle = atan2(B, A-C);
+
+    (void) FormatLocaleFile(stderr, "# Angle=%lf   Area=%lf\n",
+         RadiansToDegrees(Ellipse_Angle), Ellipse_Area);
+  }
+#endif
+
+  /* If one or both of the scaling vectors is impossibly large
+     (producing a very large raw F value), we may as well not bother
+     doing any form of resampling since resampled area is very large.
+     In this case some alternative means of pixel sampling, such as
+     the average of the whole image is needed to get a reasonable
+     result. Calculate only as needed.
+  */
+  if ( (4*A*C - B*B) > MagickHuge ) {
+    resample_filter->limit_reached = MagickTrue;
+    return;
+  }
+
+  /* Scale ellipse to match the filters support
+     (that is, multiply F by the square of the support).
+  */
+  F *= resample_filter->support;
+  F *= resample_filter->support;
+
+  /* Orthogonal bounds of the ellipse */
+  resample_filter->Ulimit = sqrt(C*F/(A*C-0.25*B*B));
+  resample_filter->Vlimit = sqrt(A*F/(A*C-0.25*B*B));
+
+  /* Horizontally aligned parallelogram fitted to Ellipse */
+  resample_filter->Uwidth = sqrt(F/A); /* Half of the parallelogram width */
+  resample_filter->slope = -B/(2.0*A); /* Reciprocal slope of the parallelogram */
+
+#if DEBUG_ELLIPSE
+  (void) FormatLocaleFile(stderr, "Ulimit=%lf; Vlimit=%lf; UWidth=%lf; Slope=%lf;\n",
+           resample_filter->Ulimit, resample_filter->Vlimit,
+           resample_filter->Uwidth, resample_filter->slope );
+#endif
+
+  /* Check the absolute area of the parallelogram involved.
+   * This limit needs more work, as it is too slow for larger images
+   * with tiled views of the horizon.
+  */
+  if ( (resample_filter->Uwidth * resample_filter->Vlimit)
+         > (4.0*resample_filter->image_area)) {
+    resample_filter->limit_reached = MagickTrue;
+    return;
+  }
+
+  /* Scale ellipse formula to directly index the Filter Lookup Table */
+  { register double scale;
+#if FILTER_LUT
+    /* scale so that F = WLUT_WIDTH; -- hardcoded */
+    scale = (double)WLUT_WIDTH/F;
+#else
+    /* scale so that F = resample_filter->F (support^2) */
+    scale = resample_filter->F/F;
+#endif
+    resample_filter->A = A*scale;
+    resample_filter->B = B*scale;
+    resample_filter->C = C*scale;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t R e s a m p l e F i l t e r                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetResampleFilter() set the resampling filter lookup table based on a
+%  specific filter.  Note that the filter is used as a radial filter not as a
+%  two pass othogonally aligned resampling filter.
+%
+%  The default Filter, is Gaussian, which is the standard filter used by the
+%  original paper on the Elliptical Weighted Everage Algorithm. However other
+%  filters can also be used.
+%
+%  The format of the SetResampleFilter method is:
+%
+%    void SetResampleFilter(ResampleFilter *resample_filter,
+%      const FilterTypes filter,const double blur)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: resampling resample_filterrmation structure
+%
+%    o filter: the resize filter for elliptical weighting LUT
+%
+%    o blur: filter blur factor (radial scaling) for elliptical weighting LUT
+%
+*/
+MagickExport void SetResampleFilter(ResampleFilter *resample_filter,
+  const FilterTypes filter,const double blur)
+{
+  ResizeFilter
+     *resize_filter;
+
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+
+  resample_filter->do_interpolate = MagickFalse;
+  resample_filter->filter = filter;
+
+  if ( filter == PointFilter )
+    {
+      resample_filter->do_interpolate = MagickTrue;
+      return;  /* EWA turned off - nothing more to do */
+    }
+
+  /* Set a default cylindrical filter of a 'low blur' Jinc windowed Jinc */
+  if ( filter == UndefinedFilter )
+    resample_filter->filter = RobidouxFilter;
+
+  resize_filter = AcquireResizeFilter(resample_filter->image,
+       resample_filter->filter,blur,MagickTrue,resample_filter->exception);
+  if (resize_filter == (ResizeFilter *) NULL)
+    {
+      (void) ThrowMagickException(resample_filter->exception,GetMagickModule(),
+           ModuleError, "UnableToSetFilteringValue",
+           "Fall back to default EWA gaussian filter");
+      resample_filter->filter = PointFilter;
+    }
+
+  /* Get the practical working support for the filter,
+   * after any API call blur factors have been accoded for.
+   */
+#if EWA
+  resample_filter->support = GetResizeFilterSupport(resize_filter);
+#else
+  resample_filter->support = 2.0;  /* fixed support size for HQ-EWA */
+#endif
+
+#if FILTER_LUT
+  /* Fill the LUT with the weights from the selected filter function */
+  { register int
+       Q;
+    double
+       r_scale;
+    /* Scale radius so the filter LUT covers the full support range */
+    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
+    for(Q=0; Q<WLUT_WIDTH; Q++)
+      resample_filter->filter_lut[Q] = (double)
+           GetResizeFilterWeight(resize_filter,sqrt((double)Q)*r_scale);
+
+    /* finished with the resize filter */
+    resize_filter = DestroyResizeFilter(resize_filter);
+  }
+#else
+  /* save the filter and the scaled ellipse bounds needed for filter */
+  resample_filter->filter_def = resize_filter;
+  resample_filter->F = resample_filter->support*resample_filter->support;
+#endif
+
+  /*
+    Adjust the scaling of the default unit circle
+    This assumes that any real scaling changes will always
+    take place AFTER the filter method has been initialized.
+  */
+  ScaleResampleFilter(resample_filter, 1.0, 0.0, 0.0, 1.0);
+
+#if 0
+  /* This is old code kept as a reference only.  It is very wrong,
+     and I don't understand exactly what it was attempting to do.
+  */
+  /*
+    Create Normal Gaussian 2D Filter Weighted Lookup Table.
+    A normal EWA guassual lookup would use   exp(Q*ALPHA)
+    where  Q = distance squared from 0.0 (center) to 1.0 (edge)
+    and    ALPHA = -4.0*ln(2.0)  ==>  -2.77258872223978123767
+    The table is of length 1024, and equates to support radius of 2.0
+    thus needs to be scaled by  ALPHA*4/1024 and any blur factor squared
+
+    The above came from some reference code provided by Fred Weinhaus
+    and seems to have been a guess that was appropriate for its use
+    in a 3d perspective landscape mapping program.
+  */
+  r_scale = -2.77258872223978123767/(WLUT_WIDTH*blur*blur);
+  for(Q=0; Q<WLUT_WIDTH; Q++)
+    resample_filter->filter_lut[Q] = exp((double)Q*r_scale);
+  resample_filter->support = WLUT_WIDTH;
+  break;
+#endif
+
+#if FILTER_LUT
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp single
+#endif
+  { register int
+       Q;
+    double
+       r_scale;
+
+    /* Scale radius so the filter LUT covers the full support range */
+    r_scale = resample_filter->support*sqrt(1.0/(double)WLUT_WIDTH);
+    if (IsMagickTrue(GetImageArtifact(resample_filter->image,"resample:verbose")) )
+      {
+        /* Debug output of the filter weighting LUT
+          Gnuplot the LUT with hoizontal adjusted to 'r' using...
+            plot [0:2][-.2:1] "lut.dat" using (sqrt($0/1024)*2):1 with lines
+          The filter values is normalized for comparision
+        */
+        printf("#\n");
+        printf("# Resampling Filter LUT (%d values)\n", WLUT_WIDTH);
+        printf("#\n");
+        printf("# Note: values in table are using a squared radius lookup.\n");
+        printf("# And the whole table represents the filters support.\n");
+        printf("\n"); /* generates a 'break' in gnuplot if multiple outputs */
+        for(Q=0; Q<WLUT_WIDTH; Q++)
+          printf("%8.*g %.*g\n",
+               GetMagickPrecision(),sqrt((double)Q)*r_scale,
+               GetMagickPrecision(),resample_filter->filter_lut[Q] );
+      }
+    /* output the above once only for each image, and each setting */
+    (void) DeleteImageArtifact(resample_filter->image,"resample:verbose");
+  }
+#endif /* FILTER_LUT */
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t R e s a m p l e F i l t e r I n t e r p o l a t e M e t h o d       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetResampleFilterInterpolateMethod() sets the resample filter interpolation
+%  method.
+%
+%  The format of the SetResampleFilterInterpolateMethod method is:
+%
+%      MagickBooleanType SetResampleFilterInterpolateMethod(
+%        ResampleFilter *resample_filter,const InterpolateMethod method)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: the resample filter.
+%
+%    o method: the interpolation method.
+%
+*/
+MagickExport MagickBooleanType SetResampleFilterInterpolateMethod(
+  ResampleFilter *resample_filter,const InterpolatePixelMethod method)
+{
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+  assert(resample_filter->image != (Image *) NULL);
+  if (resample_filter->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      resample_filter->image->filename);
+  resample_filter->interpolate=method;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t R e s a m p l e F i l t e r V i r t u a l P i x e l M e t h o d     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetResampleFilterVirtualPixelMethod() changes the virtual pixel method
+%  associated with the specified resample filter.
+%
+%  The format of the SetResampleFilterVirtualPixelMethod method is:
+%
+%      MagickBooleanType SetResampleFilterVirtualPixelMethod(
+%        ResampleFilter *resample_filter,const VirtualPixelMethod method)
+%
+%  A description of each parameter follows:
+%
+%    o resample_filter: the resample filter.
+%
+%    o method: the virtual pixel method.
+%
+*/
+MagickExport MagickBooleanType SetResampleFilterVirtualPixelMethod(
+  ResampleFilter *resample_filter,const VirtualPixelMethod method)
+{
+  assert(resample_filter != (ResampleFilter *) NULL);
+  assert(resample_filter->signature == MagickSignature);
+  assert(resample_filter->image != (Image *) NULL);
+  if (resample_filter->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      resample_filter->image->filename);
+  resample_filter->virtual_pixel=method;
+  if (method != UndefinedVirtualPixelMethod)
+    (void) SetCacheViewVirtualPixelMethod(resample_filter->view,method);
+  return(MagickTrue);
+}
diff --git a/MagickCore/resample.h b/MagickCore/resample.h
new file mode 100644
index 0000000..72d529f
--- /dev/null
+++ b/MagickCore/resample.h
@@ -0,0 +1,95 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore graphic resample methods.
+*/
+#ifndef _MAGICKCORE_RESAMPLE_H
+#define _MAGICKCORE_RESAMPLE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/cache-view.h>
+
+/*
+  WARNING:  The order of this table must also match the order of a table
+  located in AcquireResizeFilter() or "resize.c" otherwise the users filter
+  will not match the actual filter that is setup.
+*/
+typedef enum
+{
+  UndefinedFilter,
+  PointFilter,
+  BoxFilter,
+  TriangleFilter,
+  HermiteFilter,
+  HanningFilter,
+  HammingFilter,
+  BlackmanFilter,
+  GaussianFilter,
+  QuadraticFilter,
+  CubicFilter,
+  CatromFilter,
+  MitchellFilter,
+  JincFilter,
+  SincFilter,
+  SincFastFilter,
+  KaiserFilter,
+  WelshFilter,
+  ParzenFilter,
+  BohmanFilter,
+  BartlettFilter,
+  LagrangeFilter,
+  LanczosFilter,
+  LanczosSharpFilter,
+  Lanczos2Filter,
+  Lanczos2SharpFilter,
+  RobidouxFilter,
+  SentinelFilter  /* a count of all the filters, not a real filter */
+} FilterTypes;
+
+/*
+  Backward compatibility for the more correctly named Jinc Filter.  Original
+  source of this filter is from "zoom" but it refers to a reference by Pratt,
+  who does not actualy name the filter.
+*/
+#define BesselFilter JincFilter
+
+typedef struct _ResampleFilter
+  ResampleFilter;
+
+extern MagickExport MagickBooleanType
+  ResamplePixelColor(ResampleFilter *,const double,const double,
+    PixelInfo *),
+  SetResampleFilterInterpolateMethod(ResampleFilter *,
+    const InterpolatePixelMethod),
+  SetResampleFilterVirtualPixelMethod(ResampleFilter *,
+    const VirtualPixelMethod);
+
+extern MagickExport ResampleFilter
+  *AcquireResampleFilter(const Image *,ExceptionInfo *),
+  *DestroyResampleFilter(ResampleFilter *);
+
+extern MagickExport void
+  ScaleResampleFilter(ResampleFilter *,const double,const double,const double,
+    const double),
+  SetResampleFilter(ResampleFilter *,const FilterTypes,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/resize-private.h b/MagickCore/resize-private.h
new file mode 100644
index 0000000..5c63ca6
--- /dev/null
+++ b/MagickCore/resize-private.h
@@ -0,0 +1,44 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image resize private methods.
+*/
+#ifndef _MAGICKCORE_RESIZE_PRIVATE_H
+#define _MAGICKCORE_RESIZE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _ResizeFilter
+  ResizeFilter;
+
+extern MagickExport MagickRealType
+  GetResizeFilterSupport(const ResizeFilter *),
+  GetResizeFilterWeight(const ResizeFilter *,const MagickRealType);
+
+extern MagickExport ResizeFilter
+  *AcquireResizeFilter(const Image *,const FilterTypes,const MagickRealType,
+     const MagickBooleanType,ExceptionInfo *),
+  *DestroyResizeFilter(ResizeFilter *);
+
+extern MagickExport void
+  SetResizeFilterSupport(ResizeFilter *,const MagickRealType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/resize.c b/MagickCore/resize.c
new file mode 100644
index 0000000..116bcfd
--- /dev/null
+++ b/MagickCore/resize.c
@@ -0,0 +1,3305 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                 RRRR   EEEEE  SSSSS  IIIII  ZZZZZ  EEEEE                    %
+%                 R   R  E      SS       I       ZZ  E                        %
+%                 RRRR   EEE     SSS     I     ZZZ   EEE                      %
+%                 R R    E         SS    I    ZZ     E                        %
+%                 R  R   EEEEE  SSSSS  IIIII  ZZZZZ  EEEEE                    %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Resize Methods                        %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/option.h"
+#include "MagickCore/resample.h"
+#include "MagickCore/resample-private.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resize-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+#if defined(MAGICKCORE_LQR_DELEGATE)
+#include <lqr.h>
+#endif
+
+/*
+  Typedef declarations.
+*/
+struct _ResizeFilter
+{
+  MagickRealType
+    (*filter)(const MagickRealType,const ResizeFilter *),
+    (*window)(const MagickRealType,const ResizeFilter *),
+    support,        /* filter region of support - the filter support limit */
+    window_support, /* window support, usally equal to support (expert only) */
+    scale,          /* dimension scaling to fit window support (usally 1.0) */
+    blur,           /* x-scale (blur-sharpen) */
+    coefficient[7]; /* cubic coefficents for BC-cubic spline filters */
+
+  size_t
+    signature;
+};
+
+/*
+  Forward declaractions.
+*/
+static MagickRealType
+  I0(MagickRealType x),
+  BesselOrderOne(MagickRealType),
+  Sinc(const MagickRealType, const ResizeFilter *),
+  SincFast(const MagickRealType, const ResizeFilter *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   F i l t e r F u n c t i o n s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  These are the various filter and windowing functions that are provided.
+%
+%  They are internal to this module only.  See AcquireResizeFilterInfo() for
+%  details of the access to these functions, via the GetResizeFilterSupport()
+%  and GetResizeFilterWeight() API interface.
+%
+%  The individual filter functions have this format...
+%
+%     static MagickRealtype *FilterName(const MagickRealType x,
+%        const MagickRealType support)
+%
+%  A description of each parameter follows:
+%
+%    o x: the distance from the sampling point generally in the range of 0 to
+%      support.  The GetResizeFilterWeight() ensures this a positive value.
+%
+%    o resize_filter: current filter information.  This allows function to
+%      access support, and possibly other pre-calculated information defining
+%      the functions.
+%
+*/
+
+#define MagickPIL ((MagickRealType) 3.14159265358979323846264338327950288420L)
+
+static MagickRealType Jinc(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    See Pratt "Digital Image Processing" p.97 for Jinc/Bessel functions.
+    http://mathworld.wolfram.com/JincFunction.html and page 11 of
+    http://www.ph.ed.ac.uk/%7ewjh/teaching/mo/slides/lens/lens.pdf
+
+    The original "zoom" program by Paul Heckbert called this "Bessel".
+    But really it is more accurately named "Jinc".
+  */
+  if (x == 0.0)
+    return(0.5*MagickPIL);
+  return(BesselOrderOne(MagickPIL*x)/x);
+}
+
+static MagickRealType Blackman(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Blackman: 2nd order cosine windowing function:
+      0.42 + 0.5 cos(pi x) + 0.08 cos(2pi x)
+    Refactored by Chantal Racette and Nicolas Robidoux to one trig
+    call and five flops.
+  */
+  const MagickRealType cospix = cos((double) (MagickPIL*x));
+  return(0.34+cospix*(0.5+cospix*0.16));
+}
+
+static MagickRealType Bohman(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Bohman: 2rd Order cosine windowing function:
+      (1-x) cos(pi x) + sin(pi x) / pi.
+    Refactored by Nicolas Robidoux to one trig call, one sqrt call,
+    and 7 flops, taking advantage of the fact that the support of
+    Bohman is 1 (so that we know that sin(pi x) >= 0).
+  */
+  const double cospix = cos((double) (MagickPIL*x));
+  const double sinpix = sqrt(1.0-cospix*cospix);
+  return((1.0-x)*cospix+(1.0/MagickPIL)*sinpix);
+}
+
+static MagickRealType Box(const MagickRealType magick_unused(x),
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    A Box filter is a equal weighting function (all weights equal).
+    DO NOT LIMIT results by support or resize point sampling will work
+    as it requests points beyond its normal 0.0 support size.
+  */
+  return(1.0);
+}
+
+static MagickRealType CubicBC(const MagickRealType x,
+  const ResizeFilter *resize_filter)
+{
+  /*
+    Cubic Filters using B,C determined values:
+       Mitchell-Netravali  B= 1/3 C= 1/3  "Balanced" cubic spline filter
+       Catmull-Rom         B= 0   C= 1/2  Interpolatory and exact on linears
+       Cubic B-Spline      B= 1   C= 0    Spline approximation of Gaussian
+       Hermite             B= 0   C= 0    Spline with small support (= 1)
+
+    See paper by Mitchell and Netravali, Reconstruction Filters in Computer
+    Graphics Computer Graphics, Volume 22, Number 4, August 1988
+    http://www.cs.utexas.edu/users/fussell/courses/cs384g/lectures/mitchell/
+    Mitchell.pdf.
+
+    Coefficents are determined from B,C values:
+       P0 = (  6 - 2*B       )/6 = coeff[0]
+       P1 =         0
+       P2 = (-18 +12*B + 6*C )/6 = coeff[1]
+       P3 = ( 12 - 9*B - 6*C )/6 = coeff[2]
+       Q0 = (      8*B +24*C )/6 = coeff[3]
+       Q1 = (    -12*B -48*C )/6 = coeff[4]
+       Q2 = (      6*B +30*C )/6 = coeff[5]
+       Q3 = (    - 1*B - 6*C )/6 = coeff[6]
+
+    which are used to define the filter:
+
+       P0 + P1*x + P2*x^2 + P3*x^3      0 <= x < 1
+       Q0 + Q1*x + Q2*x^2 + Q3*x^3      1 <= x < 2
+
+    which ensures function is continuous in value and derivative
+    (slope).
+  */
+  if (x < 1.0)
+    return(resize_filter->coefficient[0]+x*(x*
+      (resize_filter->coefficient[1]+x*resize_filter->coefficient[2])));
+  if (x < 2.0)
+    return(resize_filter->coefficient[3]+x*(resize_filter->coefficient[4]+x*
+      (resize_filter->coefficient[5]+x*resize_filter->coefficient[6])));
+  return(0.0);
+}
+
+static MagickRealType Gaussian(const MagickRealType x,
+  const ResizeFilter *resize_filter)
+{
+  /*
+    Gaussian with a fixed sigma = 1/2
+
+    Gaussian Formula (1D) ...
+        exp( -(x^2)/((2.0*sigma^2) ) / sqrt(2*PI)sigma^2))
+    The constants are pre-calculated...
+        exp( -coeff[0]*(x^2)) ) * coeff[1]
+    However the multiplier coefficent (1) is not needed and not used.
+
+    Gaussian Formula (2D) ...
+        exp( -(x^2)/((2.0*sigma^2) ) / (PI*sigma^2) )
+    Note that it is only a change in the normalization multiplier
+    which is not needed or used when gausian is used as a filter.
+
+    This separates the gaussian 'sigma' value from the 'blur/support'
+    settings allowing for its use in special 'small sigma' gaussians,
+    without the filter 'missing' pixels because the support becomes too
+    small.
+  */
+  return(exp((double)(-resize_filter->coefficient[0]*x*x)));
+}
+
+static MagickRealType Hanning(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Cosine window function:
+      .5+.5cos(pi x).
+  */
+  const MagickRealType cospix = cos((double) (MagickPIL*x));
+  return(0.5+0.5*cospix);
+}
+
+static MagickRealType Hamming(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Offset cosine window function:
+     .54 + .46 cos(pi x).
+  */
+  const MagickRealType cospix = cos((double) (MagickPIL*x));
+  return(0.54+0.46*cospix);
+}
+
+static MagickRealType Kaiser(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+#define Alpha  6.5
+#define I0A  (1.0/I0(Alpha))
+
+  /*
+    Kaiser Windowing Function (bessel windowing): Alpha is a free
+    value from 5 to 8 (currently hardcoded to 6.5).
+    Future: make alpha the IOA pre-calculation, an 'expert' setting.
+  */
+  return(I0A*I0(Alpha*sqrt((double) (1.0-x*x))));
+}
+
+static MagickRealType Lagrange(const MagickRealType x,
+  const ResizeFilter *resize_filter)
+{
+  MagickRealType
+    value;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    n,
+    order;
+
+  /*
+    Lagrange piecewise polynomial fit of sinc: N is the 'order' of the
+    lagrange function and depends on the overall support window size
+    of the filter. That is: for a support of 2, it gives a lagrange-4
+    (piecewise cubic function).
+
+    "n" identifies the piece of the piecewise polynomial.
+
+    See Survey: Interpolation Methods, IEEE Transactions on Medical
+    Imaging, Vol 18, No 11, November 1999, p1049-1075, -- Equation 27
+    on p1064.
+  */
+  if (x > resize_filter->support)
+    return(0.0);
+  order=(ssize_t) (2.0*resize_filter->window_support);  /* number of pieces */
+  /*n=(ssize_t)((1.0*order)/2.0+x);   --  which piece does x belong to */
+  n = (ssize_t)(resize_filter->window_support + x);
+  value=1.0f;
+  for (i=0; i < order; i++)
+    if (i != n)
+      value*=(n-i-x)/(n-i);
+  return(value);
+}
+
+static MagickRealType Quadratic(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    2rd order (quadratic) B-Spline approximation of Gaussian.
+  */
+  if (x < 0.5)
+    return(0.75-x*x);
+  if (x < 1.5)
+    return(0.5*(x-1.5)*(x-1.5));
+  return(0.0);
+}
+
+static MagickRealType Sinc(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Scaled sinc(x) function using a trig call:
+      sinc(x) == sin(pi x)/(pi x).
+  */
+  if (x != 0.0)
+  {
+    const MagickRealType pix = (MagickRealType) (MagickPIL*x);
+    return(sin((double) pix)/pix);
+  }
+  return((MagickRealType) 1.0);
+}
+
+static MagickRealType SincFast(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Approximations of the sinc function sin(pi x)/(pi x) over the
+    interval [-4,4] constructed by Nicolas Robidoux and Chantal
+    Racette with funding from the Natural Sciences and Engineering
+    Research Council of Canada.
+
+    Although the approximations are polynomials (for low order of
+    approximation) and quotients of polynomials (for higher order of
+    approximation) and consequently are similar in form to Taylor
+    polynomials/Pade approximants, the approximations are computed
+    with a completely different technique.
+
+    Summary: These approximations are "the best" in terms of bang
+    (accuracy) for the buck (flops). More specifically: Among the
+    polynomial quotients that can be computed using a fixed number of
+    flops (with a given "+ - * / budget"), the chosen polynomial
+    quotient is the one closest to the approximated function with
+    respect to maximum absolute relative error over the given
+    interval.
+
+    The Remez algorithm, as implemented in the boost library's minimax
+    package, is the key to the construction:
+    http://www.boost.org/doc/libs/1_36_0/libs/math/doc/...
+    ...sf_and_dist/html/math_toolkit/backgrounders/remez.html
+  */
+  /*
+    If outside of the interval of approximation, use the standard trig
+    formula.
+  */
+  if (x > 4.0)
+    {
+      const MagickRealType pix = (MagickRealType) (MagickPIL*x);
+      return(sin((double) pix)/pix);
+    }
+  {
+    /*
+      The approximations only depend on x^2 (sinc is an even
+      function).
+    */
+    const MagickRealType xx = x*x;
+#if MAGICKCORE_QUANTUM_DEPTH <= 8
+    /*
+      Maximum absolute relative error 6.3e-6 < 1/2^17.
+    */
+    const MagickRealType c0 = 0.173610016489197553621906385078711564924e-2L;
+    const MagickRealType c1 = -0.384186115075660162081071290162149315834e-3L;
+    const MagickRealType c2 = 0.393684603287860108352720146121813443561e-4L;
+    const MagickRealType c3 = -0.248947210682259168029030370205389323899e-5L;
+    const MagickRealType c4 = 0.107791837839662283066379987646635416692e-6L;
+    const MagickRealType c5 = -0.324874073895735800961260474028013982211e-8L;
+    const MagickRealType c6 = 0.628155216606695311524920882748052490116e-10L;
+    const MagickRealType c7 = -0.586110644039348333520104379959307242711e-12L;
+    const MagickRealType p =
+      c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
+    return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
+#elif MAGICKCORE_QUANTUM_DEPTH <= 16
+    /*
+      Max. abs. rel. error 2.2e-8 < 1/2^25.
+    */
+    const MagickRealType c0 = 0.173611107357320220183368594093166520811e-2L;
+    const MagickRealType c1 = -0.384240921114946632192116762889211361285e-3L;
+    const MagickRealType c2 = 0.394201182359318128221229891724947048771e-4L;
+    const MagickRealType c3 = -0.250963301609117217660068889165550534856e-5L;
+    const MagickRealType c4 = 0.111902032818095784414237782071368805120e-6L;
+    const MagickRealType c5 = -0.372895101408779549368465614321137048875e-8L;
+    const MagickRealType c6 = 0.957694196677572570319816780188718518330e-10L;
+    const MagickRealType c7 = -0.187208577776590710853865174371617338991e-11L;
+    const MagickRealType c8 = 0.253524321426864752676094495396308636823e-13L;
+    const MagickRealType c9 = -0.177084805010701112639035485248501049364e-15L;
+    const MagickRealType p =
+      c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*(c7+xx*(c8+xx*c9))))))));
+    return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)*p);
+#else
+    /*
+      Max. abs. rel. error 1.2e-12 < 1/2^39.
+    */
+    const MagickRealType c0 = 0.173611111110910715186413700076827593074e-2L;
+    const MagickRealType c1 = -0.289105544717893415815859968653611245425e-3L;
+    const MagickRealType c2 = 0.206952161241815727624413291940849294025e-4L;
+    const MagickRealType c3 = -0.834446180169727178193268528095341741698e-6L;
+    const MagickRealType c4 = 0.207010104171026718629622453275917944941e-7L;
+    const MagickRealType c5 = -0.319724784938507108101517564300855542655e-9L;
+    const MagickRealType c6 = 0.288101675249103266147006509214934493930e-11L;
+    const MagickRealType c7 = -0.118218971804934245819960233886876537953e-13L;
+    const MagickRealType p =
+      c0+xx*(c1+xx*(c2+xx*(c3+xx*(c4+xx*(c5+xx*(c6+xx*c7))))));
+    const MagickRealType d0 = 1.0L;
+    const MagickRealType d1 = 0.547981619622284827495856984100563583948e-1L;
+    const MagickRealType d2 = 0.134226268835357312626304688047086921806e-2L;
+    const MagickRealType d3 = 0.178994697503371051002463656833597608689e-4L;
+    const MagickRealType d4 = 0.114633394140438168641246022557689759090e-6L;
+    const MagickRealType q = d0+xx*(d1+xx*(d2+xx*(d3+xx*d4)));
+    return((xx-1.0)*(xx-4.0)*(xx-9.0)*(xx-16.0)/q*p);
+#endif
+  }
+}
+
+static MagickRealType Triangle(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    1st order (linear) B-Spline, bilinear interpolation, Tent 1D
+    filter, or a Bartlett 2D Cone filter.  Also used as a
+    Bartlett Windowing function for Sinc().
+  */
+  if (x < 1.0)
+    return(1.0-x);
+  return(0.0);
+}
+
+static MagickRealType Welsh(const MagickRealType x,
+  const ResizeFilter *magick_unused(resize_filter))
+{
+  /*
+    Welsh parabolic windowing filter.
+  */
+  if (x < 1.0)
+    return(1.0-x*x);
+  return(0.0);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e R e s i z e F i l t e r                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireResizeFilter() allocates the ResizeFilter structure.  Choose from
+%  these filters:
+%
+%  FIR (Finite impulse Response) Filters
+%      Box         Triangle   Quadratic
+%      Cubic       Hermite    Catrom
+%      Mitchell
+%
+%  IIR (Infinite impulse Response) Filters
+%      Gaussian     Sinc        Jinc (Bessel)
+%
+%  Windowed Sinc/Jinc Filters
+%      Blackman     Hanning     Hamming
+%      Kaiser       Lanczos
+%
+%  Special purpose Filters
+%      SincFast  LanczosSharp  Lanczos2D Lanczos2DSharp  Robidoux
+%
+%  The users "-filter" selection is used to lookup the default 'expert'
+%  settings for that filter from a internal table.  However any provided
+%  'expert' settings (see below) may override this selection.
+%
+%  FIR filters are used as is, and are limited to that filters support window
+%  (unless over-ridden).  'Gaussian' while classed as an IIR filter, is also
+%  simply clipped by its support size (currently 1.5 or approximatally 3*sigma
+%  as recommended by many references)
+%
+%  The special a 'cylindrical' filter flag will promote the default 4-lobed
+%  Windowed Sinc filter to a 3-lobed Windowed Jinc equivalent, which is better
+%  suited to this style of image resampling. This typically happens when using
+%  such a filter for images distortions.
+%
+%  Directly requesting 'Sinc', 'Jinc' function as a filter will force the use
+%  of function without any windowing, or promotion for cylindrical usage.  This
+%  is not recommended, except by image processing experts, especially as part
+%  of expert option filter function selection.
+%
+%  Two forms of the 'Sinc' function are available: Sinc and SincFast.  Sinc is
+%  computed using the traditional sin(pi*x)/(pi*x); it is selected if the user
+%  specifically specifies the use of a Sinc filter. SincFast uses highly
+%  accurate (and fast) polynomial (low Q) and rational (high Q) approximations,
+%  and will be used by default in most cases.
+%
+%  The Lanczos filter is a special 3-lobed Sinc-windowed Sinc filter (promoted
+%  to Jinc-windowed Jinc for cylindrical (Elliptical Weighted Average) use).
+%  The Sinc version is the most popular windowed filter.
+%
+%  LanczosSharp is a slightly sharpened (blur=0.9812505644269356 < 1) form of
+%  the Lanczos filter, specifically designed for EWA distortion (as a
+%  Jinc-Jinc); it can also be used as a slightly sharper orthogonal Lanczos
+%  (Sinc-Sinc) filter. The chosen blur value comes as close as possible to
+%  satisfying the following condition without changing the character of the
+%  corresponding EWA filter:
+%
+%    'No-Op' Vertical and Horizontal Line Preservation Condition: Images with
+%    only vertical or horizontal features are preserved when performing 'no-op"
+%    with EWA distortion.
+%
+%  The Lanczos2 and Lanczos2Sharp filters are 2-lobe versions of the Lanczos
+%  filters.  The 'sharp' version uses a blur factor of 0.9549963639785485,
+%  again chosen because the resulting EWA filter comes as close as possible to
+%  satisfying the above condition.
+%
+%  Robidoux is another filter tuned for EWA. It is the Keys cubic filter
+%  defined by B=(228 - 108 sqrt(2))/199. Robidoux satisfies the "'No-Op'
+%  Vertical and Horizontal Line Preservation Condition" exactly, and it
+%  moderately blurs high frequency 'pixel-hash' patterns under no-op.  It turns
+%  out to be close to both Mitchell and Lanczos2Sharp.  For example, its first
+%  crossing is at (36 sqrt(2) + 123)/(72 sqrt(2) + 47), almost the same as the
+%  first crossing of Mitchell and Lanczos2Sharp.
+%
+%  'EXPERT' OPTIONS:
+%
+%  These artifact "defines" are not recommended for production use without
+%  expert knowledge of resampling, filtering, and the effects they have on the
+%  resulting resampled (resize ro distorted) image.
+%
+%  They can be used to override any and all filter default, and it is
+%  recommended you make good use of "filter:verbose" to make sure that the
+%  overall effect of your selection (before and after) is as expected.
+%
+%    "filter:verbose"  controls whether to output the exact results of the
+%       filter selections made, as well as plotting data for graphing the
+%       resulting filter over the filters support range.
+%
+%    "filter:filter"  select the main function associated with this filter
+%       name, as the weighting function of the filter.  This can be used to
+%       set a windowing function as a weighting function, for special
+%       purposes, such as graphing.
+%
+%       If a "filter:window" operation has not been provided, a 'Box'
+%       windowing function will be set to denote that no windowing function is
+%       being used.
+%
+%    "filter:window"  Select this windowing function for the filter. While any
+%       filter could be used as a windowing function, using the 'first lobe' of
+%       that filter over the whole support window, using a non-windowing
+%       function is not advisible. If no weighting filter function is specifed
+%       a 'SincFast' filter is used.
+%
+%    "filter:lobes"  Number of lobes to use for the Sinc/Jinc filter.  This a
+%       simpler method of setting filter support size that will correctly
+%       handle the Sinc/Jinc switch for an operators filtering requirements.
+%       Only integers should be given.
+%
+%    "filter:support" Set the support size for filtering to the size given.
+%       This not recommended for Sinc/Jinc windowed filters (lobes should be
+%       used instead).  This will override any 'filter:lobes' option.
+%
+%    "filter:win-support" Scale windowing function to this size instead.  This
+%       causes the windowing (or self-windowing Lagrange filter) to act is if
+%       the support window it much much larger than what is actually supplied
+%       to the calling operator.  The filter however is still clipped to the
+%       real support size given, by the support range suppiled to the caller.
+%       If unset this will equal the normal filter support size.
+%
+%    "filter:blur" Scale the filter and support window by this amount.  A value
+%       > 1 will generally result in a more burred image with more ringing
+%       effects, while a value <1 will sharpen the resulting image with more
+%       aliasing effects.
+%
+%    "filter:sigma" The sigma value to use for the Gaussian filter only.
+%       Defaults to '1/2'.  Using a different sigma effectively provides a
+%       method of using the filter as a 'blur' convolution.  Particularly when
+%       using it for Distort.
+%
+%    "filter:b"
+%    "filter:c" Override the preset B,C values for a Cubic type of filter.
+%       If only one of these are given it is assumes to be a 'Keys' type of
+%       filter such that B+2C=1, where Keys 'alpha' value = C.
+%
+%  Examples:
+%
+%  Set a true un-windowed Sinc filter with 10 lobes (very slow):
+%     -define filter:filter=Sinc
+%     -define filter:lobes=8
+%
+%  Set an 8 lobe Lanczos (Sinc or Jinc) filter:
+%     -filter Lanczos
+%     -define filter:lobes=8
+%
+%  The format of the AcquireResizeFilter method is:
+%
+%      ResizeFilter *AcquireResizeFilter(const Image *image,
+%        const FilterTypes filter_type, const MagickBooleanType radial,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o filter: the filter type, defining a preset filter, window and support.
+%      The artifact settings listed above will override those selections.
+%
+%    o blur: blur the filter by this amount, use 1.0 if unknown.  Image
+%      artifact "filter:blur" will override this API call usage, including any
+%      internal change (such as for cylindrical usage).
+%
+%    o radial: use a 1D orthogonal filter (Sinc) or 2D cylindrical (radial)
+%      filter (Jinc).
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ResizeFilter *AcquireResizeFilter(const Image *image,
+  const FilterTypes filter,const MagickRealType blur,
+  const MagickBooleanType cylindrical,ExceptionInfo *exception)
+{
+  const char
+    *artifact;
+
+  FilterTypes
+    filter_type,
+    window_type;
+
+  MagickRealType
+    B,
+    C,
+    sigma;
+
+  register ResizeFilter
+    *resize_filter;
+
+  /*
+    Table Mapping given Filter, into Weighting and Windowing functions.  A
+    'Box' windowing function means its a simble non-windowed filter.  An
+    'SincFast' filter function could be upgraded to a 'Jinc' filter if a
+    "cylindrical", unless a 'Sinc' or 'SincFast' filter was specifically
+    requested.
+
+    WARNING: The order of this tabel must match the order of the FilterTypes
+    enumeration specified in "resample.h", or the filter names will not match
+    the filter being setup.
+
+    You can check filter setups with the "filter:verbose" setting.
+  */
+  static struct
+  {
+    FilterTypes
+      filter,
+      window;
+  } const mapping[SentinelFilter] =
+  {
+    { UndefinedFilter,    BoxFilter      }, /* Undefined (default to Box)   */
+    { PointFilter,        BoxFilter      }, /* SPECIAL: Nearest neighbour   */
+    { BoxFilter,          BoxFilter      }, /* Box averaging filter         */
+    { TriangleFilter,     BoxFilter      }, /* Linear interpolation filter  */
+    { HermiteFilter,      BoxFilter      }, /* Hermite interpolation filter */
+    { SincFastFilter,     HanningFilter  }, /* Hanning -- cosine-sinc       */
+    { SincFastFilter,     HammingFilter  }, /* Hamming --      '' variation */
+    { SincFastFilter,     BlackmanFilter }, /* Blackman -- 2*cosine-sinc    */
+    { GaussianFilter,     BoxFilter      }, /* Gaussian blur filter         */
+    { QuadraticFilter,    BoxFilter      }, /* Quadratic Gaussian approx    */
+    { CubicFilter,        BoxFilter      }, /* Cubic B-Spline               */
+    { CatromFilter,       BoxFilter      }, /* Cubic-Keys interpolator      */
+    { MitchellFilter,     BoxFilter      }, /* 'Ideal' Cubic-Keys filter    */
+    { JincFilter,         BoxFilter      }, /* Raw 3-lobed Jinc function    */
+    { SincFilter,         BoxFilter      }, /* Raw 4-lobed Sinc function    */
+    { SincFastFilter,     BoxFilter      }, /* Raw fast sinc ("Pade"-type)  */
+    { SincFastFilter,     KaiserFilter   }, /* Kaiser -- square root-sinc   */
+    { SincFastFilter,     WelshFilter    }, /* Welsh -- parabolic-sinc      */
+    { SincFastFilter,     CubicFilter    }, /* Parzen -- cubic-sinc         */
+    { SincFastFilter,     BohmanFilter   }, /* Bohman -- 2*cosine-sinc      */
+    { SincFastFilter,     TriangleFilter }, /* Bartlett -- triangle-sinc    */
+    { LagrangeFilter,     BoxFilter      }, /* Lagrange self-windowing      */
+    { LanczosFilter,      LanczosFilter  }, /* Lanczos Sinc-Sinc filters    */
+    { LanczosSharpFilter, LanczosSharpFilter }, /* | these require */
+    { Lanczos2Filter,     Lanczos2Filter },     /* | special handling */
+    { Lanczos2SharpFilter,Lanczos2SharpFilter },
+    { RobidouxFilter,     BoxFilter      }, /* Cubic Keys tuned for EWA     */
+  };
+  /*
+    Table mapping the filter/window from the above table to an actual function.
+    The default support size for that filter as a weighting function, the range
+    to scale with to use that function as a sinc windowing function, (typ 1.0).
+
+    Note that the filter_type -> function is 1 to 1 except for Sinc(),
+    SincFast(), and CubicBC() functions, which may have multiple filter to
+    function associations.
+
+    See "filter:verbose" handling below for the function -> filter mapping.
+  */
+  static struct
+  {
+    MagickRealType
+      (*function)(const MagickRealType, const ResizeFilter*),
+      lobes, /* Default lobes/support size of the weighting filter. */
+      scale, /* Support when function used as a windowing function
+                Typically equal to the location of the first zero crossing. */
+      B,C;   /* BC-spline coefficients, ignored if not a CubicBC filter. */
+  } const filters[SentinelFilter] =
+  {
+    { Box,       0.5, 0.5,     0.0, 0.0 }, /* Undefined (default to Box)  */
+    { Box,       0.0, 0.5,     0.0, 0.0 }, /* Point (special handling)    */
+    { Box,       0.5, 0.5,     0.0, 0.0 }, /* Box                         */
+    { Triangle,  1.0, 1.0,     0.0, 0.0 }, /* Triangle                    */
+    { CubicBC,   1.0, 1.0,     0.0, 0.0 }, /* Hermite (cubic  B=C=0)      */
+    { Hanning,   1.0, 1.0,     0.0, 0.0 }, /* Hanning, cosine window      */
+    { Hamming,   1.0, 1.0,     0.0, 0.0 }, /* Hamming, '' variation       */
+    { Blackman,  1.0, 1.0,     0.0, 0.0 }, /* Blackman, 2*cosine window   */
+    { Gaussian,  2.0, 1.5,     0.0, 0.0 }, /* Gaussian                    */
+    { Quadratic, 1.5, 1.5,     0.0, 0.0 }, /* Quadratic gaussian          */
+    { CubicBC,   2.0, 2.0,     1.0, 0.0 }, /* Cubic B-Spline (B=1,C=0)    */
+    { CubicBC,   2.0, 1.0,     0.0, 0.5 }, /* Catmull-Rom    (B=0,C=1/2)  */
+    { CubicBC,   2.0, 8.0/7.0, 1./3., 1./3. }, /* Mitchell   (B=C=1/3)    */
+    { Jinc,      3.0, 1.2196698912665045, 0.0, 0.0 }, /* Raw 3-lobed Jinc */
+    { Sinc,      4.0, 1.0,     0.0, 0.0 }, /* Raw 4-lobed Sinc            */
+    { SincFast,  4.0, 1.0,     0.0, 0.0 }, /* Raw fast sinc ("Pade"-type) */
+    { Kaiser,    1.0, 1.0,     0.0, 0.0 }, /* Kaiser (square root window) */
+    { Welsh,     1.0, 1.0,     0.0, 0.0 }, /* Welsh (parabolic window)    */
+    { CubicBC,   2.0, 2.0,     1.0, 0.0 }, /* Parzen (B-Spline window)    */
+    { Bohman,    1.0, 1.0,     0.0, 0.0 }, /* Bohman, 2*Cosine window     */
+    { Triangle,  1.0, 1.0,     0.0, 0.0 }, /* Bartlett (triangle window)  */
+    { Lagrange,  2.0, 1.0,     0.0, 0.0 }, /* Lagrange sinc approximation */
+    { SincFast,  3.0, 1.0,     0.0, 0.0 }, /* Lanczos, 3-lobed Sinc-Sinc  */
+    { SincFast,  3.0, 1.0,     0.0, 0.0 }, /* lanczos, Sharpened          */
+    { SincFast,  2.0, 1.0,     0.0, 0.0 }, /* Lanczos, 2-lobed            */
+    { SincFast,  2.0, 1.0,     0.0, 0.0 }, /* Lanczos2, sharpened         */
+    { CubicBC,   2.0, 1.1685777620836932,
+                              0.37821575509399867, 0.31089212245300067 }
+                     /* Robidoux: Keys cubic close to Lanczos2D sharpened */
+  };
+  /*
+    The known zero crossings of the Jinc() or more accurately the Jinc(x*PI)
+    function being used as a filter. It is used by the "filter:lobes" expert
+    setting and for 'lobes' for Jinc functions in the previous table. This way
+    users do not have to deal with the highly irrational lobe sizes of the Jinc
+    filter.
+
+    Values taken from
+    http://cose.math.bas.bg/webMathematica/webComputing/BesselZeros.jsp using
+    Jv-function with v=1, then dividing by PI.
+  */
+  static MagickRealType
+    jinc_zeros[16] =
+    {
+      1.2196698912665045,
+      2.2331305943815286,
+      3.2383154841662362,
+      4.2410628637960699,
+      5.2427643768701817,
+      6.2439216898644877,
+      7.244759868719957,
+      8.2453949139520427,
+      9.2458926849494673,
+      10.246293348754916,
+      11.246622794877883,
+      12.246898461138105,
+      13.247132522181061,
+      14.247333735806849,
+      15.2475085630373,
+      16.247661874700962
+   };
+
+  /*
+    Allocate resize filter.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(UndefinedFilter < filter && filter < SentinelFilter);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  resize_filter=(ResizeFilter *) AcquireMagickMemory(sizeof(*resize_filter));
+  if (resize_filter == (ResizeFilter *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  /*
+    Defaults for the requested filter.
+  */
+  filter_type=mapping[filter].filter;
+  window_type=mapping[filter].window;
+  resize_filter->blur = blur;   /* function argument blur factor */
+  sigma = 0.5;    /* guassian sigma of half a pixel by default */
+  /* Promote 1D Windowed Sinc Filters to a 2D Windowed Jinc filters */
+  if (cylindrical != MagickFalse && filter_type == SincFastFilter
+       && filter != SincFastFilter )
+    filter_type=JincFilter;
+
+  /* Expert filter setting override */
+  artifact=GetImageArtifact(image,"filter:filter");
+  if (artifact != (const char *) NULL)
+    {
+      ssize_t
+        option;
+
+      option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
+      if ((UndefinedFilter < option) && (option < SentinelFilter))
+        { /* Raw filter request - no window function. */
+          filter_type=(FilterTypes) option;
+          window_type=BoxFilter;
+        }
+      /* Filter override with a specific window function. */
+      artifact=GetImageArtifact(image,"filter:window");
+      if (artifact != (const char *) NULL)
+        {
+          option=ParseCommandOption(MagickFilterOptions,MagickFalse,artifact);
+          if ((UndefinedFilter < option) && (option < SentinelFilter))
+            window_type=(FilterTypes) option;
+        }
+    }
+  else
+    {
+      /* Window specified, but no filter function?  Assume Sinc/Jinc. */
+      artifact=GetImageArtifact(image,"filter:window");
+      if (artifact != (const char *) NULL)
+        {
+          ssize_t
+            option;
+
+          option=ParseCommandOption(MagickFilterOptions,MagickFalse,
+            artifact);
+          if ((UndefinedFilter < option) && (option < SentinelFilter))
+            {
+              filter_type=cylindrical != MagickFalse ?
+                         JincFilter : SincFastFilter;
+              window_type=(FilterTypes) option;
+            }
+        }
+    }
+
+  /* Assign the real functions to use for the filters selected. */
+  resize_filter->filter=filters[filter_type].function;
+  resize_filter->support=filters[filter_type].lobes;
+  resize_filter->window=filters[window_type].function;
+  resize_filter->scale=filters[window_type].scale;
+  resize_filter->signature=MagickSignature;
+
+  /* Filter Modifications for orthogonal/cylindrical usage */
+  if (cylindrical != MagickFalse)
+    switch (filter_type)
+    {
+      case BoxFilter:
+        /* Support for Cylindrical Box should be sqrt(2)/2 */
+        resize_filter->support=(MagickRealType) MagickSQ1_2;
+        break;
+      case LanczosFilter:
+      case LanczosSharpFilter:
+      case Lanczos2Filter:
+      case Lanczos2SharpFilter:
+        resize_filter->filter=filters[JincFilter].function;
+        resize_filter->window=filters[JincFilter].function;
+        resize_filter->scale=filters[JincFilter].scale;
+        /* number of lobes (support window size) remain unchanged */
+        break;
+      default:
+        break;
+    }
+  /* Global Sharpening (regardless of orthoginal/cylindrical) */
+  switch (filter_type)
+  {
+    case LanczosSharpFilter:
+      resize_filter->blur *= 0.9812505644269356;
+      break;
+    case Lanczos2SharpFilter:
+      resize_filter->blur *= 0.9549963639785485;
+      break;
+    default:
+      break;
+  }
+
+  /*
+  ** Other Expert Option Modifications
+  */
+
+  /* User Sigma Override - no support change */
+  artifact=GetImageArtifact(image,"filter:sigma");
+  if (artifact != (const char *) NULL)
+    sigma=InterpretLocaleValue(artifact,(char **) NULL);
+  /* Define coefficents for Gaussian */
+  if ( GaussianFilter ) {
+    resize_filter->coefficient[0]=1.0/(2.0*sigma*sigma);
+    resize_filter->coefficient[1]=(MagickRealType) (1.0/(Magick2PI*sigma*
+      sigma)); /* Normalization Multiplier - unneeded for filters */
+  }
+
+  /* Blur Override */
+  artifact=GetImageArtifact(image,"filter:blur");
+  if (artifact != (const char *) NULL)
+    resize_filter->blur *= InterpretLocaleValue(artifact,(char **) NULL);
+  if (resize_filter->blur < MagickEpsilon)
+    resize_filter->blur=(MagickRealType) MagickEpsilon;
+
+  /* Support Overrides */
+  artifact=GetImageArtifact(image,"filter:lobes");
+  if (artifact != (const char *) NULL)
+    {
+      ssize_t
+        lobes;
+
+      lobes=(ssize_t) StringToLong(artifact);
+      if (lobes < 1)
+        lobes=1;
+      resize_filter->support=(MagickRealType) lobes;
+    }
+  /* Convert a Jinc function lobes value to a real support value */
+  if (resize_filter->filter == Jinc)
+    {
+      if (resize_filter->support > 16)
+        resize_filter->support=jinc_zeros[15];  /* largest entry in table */
+      else
+        resize_filter->support = jinc_zeros[((long)resize_filter->support)-1];
+    }
+  /* expert override of the support setting */
+  artifact=GetImageArtifact(image,"filter:support");
+  if (artifact != (const char *) NULL)
+    resize_filter->support=fabs(InterpretLocaleValue(artifact,(char **) NULL));
+  /*
+    Scale windowing function separately to the support 'clipping'
+    window that calling operator is planning to actually use. (Expert
+    override)
+  */
+  resize_filter->window_support=resize_filter->support; /* default */
+  artifact=GetImageArtifact(image,"filter:win-support");
+  if (artifact != (const char *) NULL)
+    resize_filter->window_support=fabs(InterpretLocaleValue(artifact,(char **) NULL));
+  /*
+    Adjust window function scaling to match windowing support for
+    weighting function.  This avoids a division on every filter call.
+  */
+  resize_filter->scale /= resize_filter->window_support;
+
+  /*
+   * Set Cubic Spline B,C values, calculate Cubic coefficients.
+  */
+  B=0.0;
+  C=0.0;
+  if ((filters[filter_type].function == CubicBC) ||
+      (filters[window_type].function == CubicBC))
+    {
+      B=filters[filter_type].B;
+      C=filters[filter_type].C;
+      if (filters[window_type].function == CubicBC)
+        {
+          B=filters[window_type].B;
+          C=filters[window_type].C;
+        }
+      artifact=GetImageArtifact(image,"filter:b");
+      if (artifact != (const char *) NULL)
+        {
+          B=InterpretLocaleValue(artifact,(char **) NULL);
+          C=(1.0-B)/2.0; /* Calculate C to get a Keys cubic filter. */
+          artifact=GetImageArtifact(image,"filter:c"); /* user C override */
+          if (artifact != (const char *) NULL)
+            C=InterpretLocaleValue(artifact,(char **) NULL);
+        }
+      else
+        {
+          artifact=GetImageArtifact(image,"filter:c");
+          if (artifact != (const char *) NULL)
+            {
+              C=InterpretLocaleValue(artifact,(char **) NULL);
+              B=1.0-2.0*C; /* Calculate B to get a Keys cubic filter. */
+            }
+        }
+      /* Convert B,C values into Cubic Coefficents. See CubicBC(). */
+      {
+        const double twoB = B+B;
+        resize_filter->coefficient[0]=1.0-(1.0/3.0)*B;
+        resize_filter->coefficient[1]=-3.0+twoB+C;
+        resize_filter->coefficient[2]=2.0-1.5*B-C;
+        resize_filter->coefficient[3]=(4.0/3.0)*B+4.0*C;
+        resize_filter->coefficient[4]=-8.0*C-twoB;
+        resize_filter->coefficient[5]=B+5.0*C;
+        resize_filter->coefficient[6]=(-1.0/6.0)*B-C;
+      }
+    }
+
+  /*
+    Expert Option Request for verbose details of the resulting filter.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp master
+  {
+#endif
+    artifact=GetImageArtifact(image,"filter:verbose");
+    if (IsMagickTrue(artifact))
+      {
+        double
+          support,
+          x;
+
+        /*
+          Set the weighting function properly when the weighting
+          function may not exactly match the filter of the same name.
+          EG: a Point filter is really uses a Box weighting function
+          with a different support than is typically used.
+        */
+        if (resize_filter->filter == Box)       filter_type=BoxFilter;
+        if (resize_filter->filter == Sinc)      filter_type=SincFilter;
+        if (resize_filter->filter == SincFast)  filter_type=SincFastFilter;
+        if (resize_filter->filter == Jinc)      filter_type=JincFilter;
+        if (resize_filter->filter == CubicBC)   filter_type=CubicFilter;
+        if (resize_filter->window == Box)       window_type=BoxFilter;
+        if (resize_filter->window == Sinc)      window_type=SincFilter;
+        if (resize_filter->window == SincFast)  window_type=SincFastFilter;
+        if (resize_filter->window == Jinc)      window_type=JincFilter;
+        if (resize_filter->window == CubicBC)   window_type=CubicFilter;
+        /*
+          Report Filter Details.
+        */
+        support=GetResizeFilterSupport(resize_filter); /* practical_support */
+        (void) FormatLocaleFile(stdout,"# Resize Filter (for graphing)\n#\n");
+        (void) FormatLocaleFile(stdout,"# filter = %s\n",
+             CommandOptionToMnemonic(MagickFilterOptions,filter_type));
+        (void) FormatLocaleFile(stdout,"# window = %s\n",
+             CommandOptionToMnemonic(MagickFilterOptions, window_type));
+        (void) FormatLocaleFile(stdout,"# support = %.*g\n",
+             GetMagickPrecision(),(double) resize_filter->support);
+        (void) FormatLocaleFile(stdout,"# win-support = %.*g\n",
+             GetMagickPrecision(),(double) resize_filter->window_support);
+        (void) FormatLocaleFile(stdout,"# scale_blur = %.*g\n",
+             GetMagickPrecision(), (double)resize_filter->blur);
+        if ( filter_type == GaussianFilter )
+          (void) FormatLocaleFile(stdout,"# gaussian_sigma = %.*g\n",
+               GetMagickPrecision(), (double)sigma);
+        (void) FormatLocaleFile(stdout,"# practical_support = %.*g\n",
+             GetMagickPrecision(), (double)support);
+        if ( filter_type == CubicFilter || window_type == CubicFilter )
+          (void) FormatLocaleFile(stdout,"# B,C = %.*g,%.*g\n",
+               GetMagickPrecision(),(double)B, GetMagickPrecision(),(double)C);
+        (void) FormatLocaleFile(stdout,"\n");
+        /*
+          Output values of resulting filter graph -- for graphing
+          filter result.
+        */
+        for (x=0.0; x <= support; x+=0.01f)
+          (void) FormatLocaleFile(stdout,"%5.2lf\t%.*g\n",x,GetMagickPrecision(),
+            (double) GetResizeFilterWeight(resize_filter,x));
+        /* A final value so gnuplot can graph the 'stop' properly. */
+        (void) FormatLocaleFile(stdout,"%5.2lf\t%.*g\n",support,
+          GetMagickPrecision(),0.0);
+      }
+      /* Output the above once only for each image - remove setting */
+    (void) DeleteImageArtifact((Image *) image,"filter:verbose");
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  }
+#endif
+  return(resize_filter);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A d a p t i v e R e s i z e I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AdaptiveResizeImage() adaptively resize image with pixel resampling.
+%
+%  The format of the AdaptiveResizeImage method is:
+%
+%      Image *AdaptiveResizeImage(const Image *image,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the resized image.
+%
+%    o rows: the number of rows in the resized image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *AdaptiveResizeImage(const Image *image,
+  const size_t columns,const size_t rows,ExceptionInfo *exception)
+{
+#define AdaptiveResizeImageTag  "Resize/Image"
+
+  CacheView
+    *image_view,
+    *resize_view;
+
+  Image
+    *resize_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  /*
+    Adaptively resize image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((columns == 0) || (rows == 0))
+    return((Image *) NULL);
+  if ((columns == image->columns) && (rows == image->rows))
+    return(CloneImage(image,0,0,MagickTrue,exception));
+  resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
+  if (resize_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(resize_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&resize_image->exception);
+      resize_image=DestroyImage(resize_image);
+      return((Image *) NULL);
+    }
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  resize_view=AcquireCacheView(resize_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) resize_image->rows; y++)
+  {
+    PixelInfo
+      pixel;
+
+    PointInfo
+      offset;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      continue;
+    offset.y=((MagickRealType) (y+0.5)*image->rows/resize_image->rows);
+    GetPixelInfo(image,&pixel);
+    for (x=0; x < (ssize_t) resize_image->columns; x++)
+    {
+      offset.x=((MagickRealType) (x+0.5)*image->columns/resize_image->columns);
+      (void) InterpolatePixelInfo(image,image_view,
+        MeshInterpolatePixel,offset.x-0.5,offset.y-0.5,&pixel,exception);
+      SetPixelPixelInfo(resize_image,&pixel,q);
+      q+=GetPixelChannels(resize_image);
+    }
+    if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
+      continue;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp critical (MagickCore_AdaptiveResizeImage)
+#endif
+        proceed=SetImageProgress(image,AdaptiveResizeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  resize_view=DestroyCacheView(resize_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    resize_image=DestroyImage(resize_image);
+  return(resize_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   B e s s e l O r d e r O n e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BesselOrderOne() computes the Bessel function of x of the first kind of
+%  order 0.  This is used to create the Jinc() filter function below.
+%
+%    Reduce x to |x| since j1(x)= -j1(-x), and for x in (0,8]
+%
+%       j1(x) = x*j1(x);
+%
+%    For x in (8,inf)
+%
+%       j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+%
+%    where x1 = x-3*pi/4. Compute sin(x1) and cos(x1) as follow:
+%
+%       cos(x1) =  cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+%               =  1/sqrt(2) * (sin(x) - cos(x))
+%       sin(x1) =  sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+%               = -1/sqrt(2) * (sin(x) + cos(x))
+%
+%  The format of the BesselOrderOne method is:
+%
+%      MagickRealType BesselOrderOne(MagickRealType x)
+%
+%  A description of each parameter follows:
+%
+%    o x: MagickRealType value.
+%
+*/
+
+#undef I0
+static MagickRealType I0(MagickRealType x)
+{
+  MagickRealType
+    sum,
+    t,
+    y;
+
+  register ssize_t
+    i;
+
+  /*
+    Zeroth order Bessel function of the first kind.
+  */
+  sum=1.0;
+  y=x*x/4.0;
+  t=y;
+  for (i=2; t > MagickEpsilon; i++)
+  {
+    sum+=t;
+    t*=y/((MagickRealType) i*i);
+  }
+  return(sum);
+}
+
+#undef J1
+static MagickRealType J1(MagickRealType x)
+{
+  MagickRealType
+    p,
+    q;
+
+  register ssize_t
+    i;
+
+  static const double
+    Pone[] =
+    {
+       0.581199354001606143928050809e+21,
+      -0.6672106568924916298020941484e+20,
+       0.2316433580634002297931815435e+19,
+      -0.3588817569910106050743641413e+17,
+       0.2908795263834775409737601689e+15,
+      -0.1322983480332126453125473247e+13,
+       0.3413234182301700539091292655e+10,
+      -0.4695753530642995859767162166e+7,
+       0.270112271089232341485679099e+4
+    },
+    Qone[] =
+    {
+      0.11623987080032122878585294e+22,
+      0.1185770712190320999837113348e+20,
+      0.6092061398917521746105196863e+17,
+      0.2081661221307607351240184229e+15,
+      0.5243710262167649715406728642e+12,
+      0.1013863514358673989967045588e+10,
+      0.1501793594998585505921097578e+7,
+      0.1606931573481487801970916749e+4,
+      0.1e+1
+    };
+
+  p=Pone[8];
+  q=Qone[8];
+  for (i=7; i >= 0; i--)
+  {
+    p=p*x*x+Pone[i];
+    q=q*x*x+Qone[i];
+  }
+  return(p/q);
+}
+
+#undef P1
+static MagickRealType P1(MagickRealType x)
+{
+  MagickRealType
+    p,
+    q;
+
+  register ssize_t
+    i;
+
+  static const double
+    Pone[] =
+    {
+      0.352246649133679798341724373e+5,
+      0.62758845247161281269005675e+5,
+      0.313539631109159574238669888e+5,
+      0.49854832060594338434500455e+4,
+      0.2111529182853962382105718e+3,
+      0.12571716929145341558495e+1
+    },
+    Qone[] =
+    {
+      0.352246649133679798068390431e+5,
+      0.626943469593560511888833731e+5,
+      0.312404063819041039923015703e+5,
+      0.4930396490181088979386097e+4,
+      0.2030775189134759322293574e+3,
+      0.1e+1
+    };
+
+  p=Pone[5];
+  q=Qone[5];
+  for (i=4; i >= 0; i--)
+  {
+    p=p*(8.0/x)*(8.0/x)+Pone[i];
+    q=q*(8.0/x)*(8.0/x)+Qone[i];
+  }
+  return(p/q);
+}
+
+#undef Q1
+static MagickRealType Q1(MagickRealType x)
+{
+  MagickRealType
+    p,
+    q;
+
+  register ssize_t
+    i;
+
+  static const double
+    Pone[] =
+    {
+      0.3511751914303552822533318e+3,
+      0.7210391804904475039280863e+3,
+      0.4259873011654442389886993e+3,
+      0.831898957673850827325226e+2,
+      0.45681716295512267064405e+1,
+      0.3532840052740123642735e-1
+    },
+    Qone[] =
+    {
+      0.74917374171809127714519505e+4,
+      0.154141773392650970499848051e+5,
+      0.91522317015169922705904727e+4,
+      0.18111867005523513506724158e+4,
+      0.1038187585462133728776636e+3,
+      0.1e+1
+    };
+
+  p=Pone[5];
+  q=Qone[5];
+  for (i=4; i >= 0; i--)
+  {
+    p=p*(8.0/x)*(8.0/x)+Pone[i];
+    q=q*(8.0/x)*(8.0/x)+Qone[i];
+  }
+  return(p/q);
+}
+
+static MagickRealType BesselOrderOne(MagickRealType x)
+{
+  MagickRealType
+    p,
+    q;
+
+  if (x == 0.0)
+    return(0.0);
+  p=x;
+  if (x < 0.0)
+    x=(-x);
+  if (x < 8.0)
+    return(p*J1(x));
+  q=sqrt((double) (2.0/(MagickPI*x)))*(P1(x)*(1.0/sqrt(2.0)*(sin((double) x)-
+    cos((double) x)))-8.0/x*Q1(x)*(-1.0/sqrt(2.0)*(sin((double) x)+
+    cos((double) x))));
+  if (p < 0.0)
+    q=(-q);
+  return(q);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y R e s i z e F i l t e r                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyResizeFilter() destroy the resize filter.
+%
+%  The format of the DestroyResizeFilter method is:
+%
+%      ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
+%
+%  A description of each parameter follows:
+%
+%    o resize_filter: the resize filter.
+%
+*/
+MagickExport ResizeFilter *DestroyResizeFilter(ResizeFilter *resize_filter)
+{
+  assert(resize_filter != (ResizeFilter *) NULL);
+  assert(resize_filter->signature == MagickSignature);
+  resize_filter->signature=(~MagickSignature);
+  resize_filter=(ResizeFilter *) RelinquishMagickMemory(resize_filter);
+  return(resize_filter);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t R e s i z e F i l t e r S u p p o r t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetResizeFilterSupport() return the current support window size for this
+%  filter.  Note that this may have been enlarged by filter:blur factor.
+%
+%  The format of the GetResizeFilterSupport method is:
+%
+%      MagickRealType GetResizeFilterSupport(const ResizeFilter *resize_filter)
+%
+%  A description of each parameter follows:
+%
+%    o filter: Image filter to use.
+%
+*/
+MagickExport MagickRealType GetResizeFilterSupport(
+  const ResizeFilter *resize_filter)
+{
+  assert(resize_filter != (ResizeFilter *) NULL);
+  assert(resize_filter->signature == MagickSignature);
+  return(resize_filter->support*resize_filter->blur);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t R e s i z e F i l t e r W e i g h t                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetResizeFilterWeight evaluates the specified resize filter at the point x
+%  which usally lies between zero and the filters current 'support' and
+%  returns the weight of the filter function at that point.
+%
+%  The format of the GetResizeFilterWeight method is:
+%
+%      MagickRealType GetResizeFilterWeight(const ResizeFilter *resize_filter,
+%        const MagickRealType x)
+%
+%  A description of each parameter follows:
+%
+%    o filter: the filter type.
+%
+%    o x: the point.
+%
+*/
+MagickExport MagickRealType GetResizeFilterWeight(
+  const ResizeFilter *resize_filter,const MagickRealType x)
+{
+  MagickRealType
+    scale,
+    weight,
+    x_blur;
+
+  /*
+    Windowing function - scale the weighting filter by this amount.
+  */
+  assert(resize_filter != (ResizeFilter *) NULL);
+  assert(resize_filter->signature == MagickSignature);
+  x_blur=fabs((double) x)/resize_filter->blur;  /* X offset with blur scaling */
+  if ((resize_filter->window_support < MagickEpsilon) ||
+      (resize_filter->window == Box))
+    scale=1.0;  /* Point or Box Filter -- avoid division by zero */
+  else
+    {
+      scale=resize_filter->scale;
+      scale=resize_filter->window(x_blur*scale,resize_filter);
+    }
+  weight=scale*resize_filter->filter(x_blur,resize_filter);
+  return(weight);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g n i f y I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagnifyImage() is a convenience method that scales an image proportionally
+%  to twice its size.
+%
+%  The format of the MagnifyImage method is:
+%
+%      Image *MagnifyImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *MagnifyImage(const Image *image,ExceptionInfo *exception)
+{
+  Image
+    *magnify_image;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  magnify_image=ResizeImage(image,2*image->columns,2*image->rows,CubicFilter,
+    1.0,exception);
+  return(magnify_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M i n i f y I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MinifyImage() is a convenience method that scales an image proportionally
+%  to half its size.
+%
+%  The format of the MinifyImage method is:
+%
+%      Image *MinifyImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *MinifyImage(const Image *image,ExceptionInfo *exception)
+{
+  Image
+    *minify_image;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  minify_image=ResizeImage(image,image->columns/2,image->rows/2,CubicFilter,1.0,
+    exception);
+  return(minify_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s a m p l e I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResampleImage() resize image in terms of its pixel size, so that when
+%  displayed at the given resolution it will be the same size in terms of
+%  real world units as the original image at the original resolution.
+%
+%  The format of the ResampleImage method is:
+%
+%      Image *ResampleImage(Image *image,const double x_resolution,
+%        const double y_resolution,const FilterTypes filter,const double blur,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image to be resized to fit the given resolution.
+%
+%    o x_resolution: the new image x resolution.
+%
+%    o y_resolution: the new image y resolution.
+%
+%    o filter: Image filter to use.
+%
+%    o blur: the blur factor where > 1 is blurry, < 1 is sharp.
+%
+*/
+MagickExport Image *ResampleImage(const Image *image,const double x_resolution,
+  const double y_resolution,const FilterTypes filter,const double blur,
+  ExceptionInfo *exception)
+{
+#define ResampleImageTag  "Resample/Image"
+
+  Image
+    *resample_image;
+
+  size_t
+    height,
+    width;
+
+  /*
+    Initialize sampled image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  width=(size_t) (x_resolution*image->columns/(image->x_resolution == 0.0 ?
+    72.0 : image->x_resolution)+0.5);
+  height=(size_t) (y_resolution*image->rows/(image->y_resolution == 0.0 ?
+    72.0 : image->y_resolution)+0.5);
+  resample_image=ResizeImage(image,width,height,filter,blur,exception);
+  if (resample_image != (Image *) NULL)
+    {
+      resample_image->x_resolution=x_resolution;
+      resample_image->y_resolution=y_resolution;
+    }
+  return(resample_image);
+}
+#if defined(MAGICKCORE_LQR_DELEGATE)
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L i q u i d R e s c a l e I m a g e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LiquidRescaleImage() rescales image with seam carving.
+%
+%  The format of the LiquidRescaleImage method is:
+%
+%      Image *LiquidRescaleImage(const Image *image,
+%        const size_t columns,const size_t rows,
+%        const double delta_x,const double rigidity,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the rescaled image.
+%
+%    o rows: the number of rows in the rescaled image.
+%
+%    o delta_x: maximum seam transversal step (0 means straight seams).
+%
+%    o rigidity: introduce a bias for non-straight seams (typically 0).
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *LiquidRescaleImage(const Image *image,const size_t columns,
+  const size_t rows,const double delta_x,const double rigidity,
+  ExceptionInfo *exception)
+{
+#define LiquidRescaleImageTag  "Rescale/Image"
+
+  CacheView
+    *rescale_view;
+
+  const char
+    *map;
+
+  guchar
+    *packet;
+
+  Image
+    *rescale_image;
+
+  int
+    x,
+    y;
+
+  LqrCarver
+    *carver;
+
+  LqrRetVal
+    lqr_status;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    pixel;
+
+  unsigned char
+    *pixels;
+
+  /*
+    Liquid rescale image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((columns == 0) || (rows == 0))
+    return((Image *) NULL);
+  if ((columns == image->columns) && (rows == image->rows))
+    return(CloneImage(image,0,0,MagickTrue,exception));
+  if ((columns <= 2) || (rows <= 2))
+    return(ResizeImage(image,columns,rows,image->filter,image->blur,exception));
+  if ((columns >= (2*image->columns)) || (rows >= (2*image->rows)))
+    {
+      Image
+        *resize_image;
+
+      size_t
+        height,
+        width;
+
+      /*
+        Honor liquid resize size limitations.
+      */
+      for (width=image->columns; columns >= (2*width-1); width*=2);
+      for (height=image->rows; rows >= (2*height-1); height*=2);
+      resize_image=ResizeImage(image,width,height,image->filter,image->blur,
+        exception);
+      if (resize_image == (Image *) NULL)
+        return((Image *) NULL);
+      rescale_image=LiquidRescaleImage(resize_image,columns,rows,delta_x,
+        rigidity,exception);
+      resize_image=DestroyImage(resize_image);
+      return(rescale_image);
+    }
+  map="RGB";
+  if (image->matte == MagickFalse)
+    map="RGBA";
+  if (image->colorspace == CMYKColorspace)
+    {
+      map="CMYK";
+      if (image->matte == MagickFalse)
+        map="CMYKA";
+    }
+  pixels=(unsigned char *) AcquireQuantumMemory(image->columns,image->rows*
+    strlen(map)*sizeof(*pixels));
+  if (pixels == (unsigned char *) NULL)
+    return((Image *) NULL);
+  status=ExportImagePixels(image,0,0,image->columns,image->rows,map,CharPixel,
+    pixels,exception);
+  if (status == MagickFalse)
+    {
+      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  carver=lqr_carver_new(pixels,image->columns,image->rows,strlen(map));
+  if (carver == (LqrCarver *) NULL)
+    {
+      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  lqr_status=lqr_carver_init(carver,(int) delta_x,rigidity);
+  lqr_status=lqr_carver_resize(carver,columns,rows);
+  (void) lqr_status;
+  rescale_image=CloneImage(image,lqr_carver_get_width(carver),
+    lqr_carver_get_height(carver),MagickTrue,exception);
+  if (rescale_image == (Image *) NULL)
+    {
+      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
+      return((Image *) NULL);
+    }
+  if (SetImageStorageClass(rescale_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&rescale_image->exception);
+      rescale_image=DestroyImage(rescale_image);
+      return((Image *) NULL);
+    }
+  GetPixelInfo(rescale_image,&pixel);
+  (void) lqr_carver_scan_reset(carver);
+  rescale_view=AcquireCacheView(rescale_image);
+  while (lqr_carver_scan(carver,&x,&y,&packet) != 0)
+  {
+    register Quantum
+      *restrict q;
+
+    q=QueueCacheViewAuthenticPixels(rescale_view,x,y,1,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    pixel.red=QuantumRange*(packet[0]/255.0);
+    pixel.green=QuantumRange*(packet[1]/255.0);
+    pixel.blue=QuantumRange*(packet[2]/255.0);
+    if (image->colorspace != CMYKColorspace)
+      {
+        if (image->matte == MagickFalse)
+          pixel.alpha=QuantumRange*(packet[3]/255.0);
+      }
+    else
+      {
+        pixel.black=QuantumRange*(packet[3]/255.0);
+        if (image->matte == MagickFalse)
+          pixel.alpha=QuantumRange*(packet[4]/255.0);
+      }
+    SetPixelPixelInfo(rescale_image,&pixel,q);
+    if (SyncCacheViewAuthenticPixels(rescale_view,exception) == MagickFalse)
+      break;
+  }
+  rescale_view=DestroyCacheView(rescale_view);
+  /*
+    Relinquish resources.
+  */
+  lqr_carver_destroy(carver);
+  return(rescale_image);
+}
+#else
+MagickExport Image *LiquidRescaleImage(const Image *image,
+  const size_t magick_unused(columns),const size_t magick_unused(rows),
+  const double magick_unused(delta_x),const double magick_unused(rigidity),
+  ExceptionInfo *exception)
+{
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
+    "DelegateLibrarySupportNotBuiltIn","`%s' (LQR)",image->filename);
+  return((Image *) NULL);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s i z e I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResizeImage() scales an image to the desired dimensions, using the given
+%  filter (see AcquireFilterInfo()).
+%
+%  If an undefined filter is given the filter defaults to Mitchell for a
+%  colormapped image, a image with a matte channel, or if the image is
+%  enlarged.  Otherwise the filter defaults to a Lanczos.
+%
+%  ResizeImage() was inspired by Paul Heckbert's "zoom" program.
+%
+%  The format of the ResizeImage method is:
+%
+%      Image *ResizeImage(Image *image,const size_t columns,
+%        const size_t rows,const FilterTypes filter,const double blur,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the scaled image.
+%
+%    o rows: the number of rows in the scaled image.
+%
+%    o filter: Image filter to use.
+%
+%    o blur: the blur factor where > 1 is blurry, < 1 is sharp.  Typically set
+%      this to 1.0.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+typedef struct _ContributionInfo
+{
+  MagickRealType
+    weight;
+
+  ssize_t
+    pixel;
+} ContributionInfo;
+
+static ContributionInfo **DestroyContributionThreadSet(
+  ContributionInfo **contribution)
+{
+  register ssize_t
+    i;
+
+  assert(contribution != (ContributionInfo **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (contribution[i] != (ContributionInfo *) NULL)
+      contribution[i]=(ContributionInfo *) RelinquishMagickMemory(
+        contribution[i]);
+  contribution=(ContributionInfo **) RelinquishMagickMemory(contribution);
+  return(contribution);
+}
+
+static ContributionInfo **AcquireContributionThreadSet(const size_t count)
+{
+  register ssize_t
+    i;
+
+  ContributionInfo
+    **contribution;
+
+  size_t
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  contribution=(ContributionInfo **) AcquireQuantumMemory(number_threads,
+    sizeof(*contribution));
+  if (contribution == (ContributionInfo **) NULL)
+    return((ContributionInfo **) NULL);
+  (void) ResetMagickMemory(contribution,0,number_threads*sizeof(*contribution));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    contribution[i]=(ContributionInfo *) AcquireQuantumMemory(count,
+      sizeof(**contribution));
+    if (contribution[i] == (ContributionInfo *) NULL)
+      return(DestroyContributionThreadSet(contribution));
+  }
+  return(contribution);
+}
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickBooleanType HorizontalFilter(const ResizeFilter *resize_filter,
+  const Image *image,Image *resize_image,const MagickRealType x_factor,
+  const MagickSizeType span,MagickOffsetType *offset,ExceptionInfo *exception)
+{
+#define ResizeImageTag  "Resize/Image"
+
+  CacheView
+    *image_view,
+    *resize_view;
+
+  ClassType
+    storage_class;
+
+  ContributionInfo
+    **restrict contributions;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    scale,
+    support;
+
+  ssize_t
+    x;
+
+  /*
+    Apply filter to resize horizontally from image to resize image.
+  */
+  scale=MagickMax(1.0/x_factor+MagickEpsilon,1.0);
+  support=scale*GetResizeFilterSupport(resize_filter);
+  storage_class=support > 0.5 ? DirectClass : image->storage_class;
+  if (SetImageStorageClass(resize_image,storage_class) == MagickFalse)
+    {
+      InheritException(exception,&resize_image->exception);
+      return(MagickFalse);
+    }
+  if (support < 0.5)
+    {
+      /*
+        Support too small even for nearest neighbour: Reduce to point
+        sampling.
+      */
+      support=(MagickRealType) 0.5;
+      scale=1.0;
+    }
+  contributions=AcquireContributionThreadSet((size_t) (2.0*support+3.0));
+  if (contributions == (ContributionInfo **) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  status=MagickTrue;
+  scale=1.0/scale;
+  (void) ResetMagickMemory(&zero,0,sizeof(zero));
+  image_view=AcquireCacheView(image);
+  resize_view=AcquireCacheView(resize_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for shared(status)
+#endif
+  for (x=0; x < (ssize_t) resize_image->columns; x++)
+  {
+    MagickRealType
+      center,
+      density;
+
+
+    register const Quantum
+      *restrict p;
+
+    register ContributionInfo
+      *restrict contribution;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      y;
+
+    ssize_t
+      n,
+      start,
+      stop;
+
+    if (status == MagickFalse)
+      continue;
+    center=(MagickRealType) (x+0.5)/x_factor;
+    start=(ssize_t) MagickMax(center-support+0.5,0.0);
+    stop=(ssize_t) MagickMin(center+support+0.5,(double) image->columns);
+    density=0.0;
+    contribution=contributions[GetOpenMPThreadId()];
+    for (n=0; n < (stop-start); n++)
+    {
+      contribution[n].pixel=start+n;
+      contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
+        ((MagickRealType) (start+n)-center+0.5));
+      density+=contribution[n].weight;
+    }
+    if ((density != 0.0) && (density != 1.0))
+      {
+        register ssize_t
+          i;
+
+        /*
+          Normalize.
+        */
+        density=1.0/density;
+        for (i=0; i < n; i++)
+          contribution[i].weight*=density;
+      }
+    p=GetCacheViewVirtualPixels(image_view,contribution[0].pixel,0,(size_t)
+      (contribution[n-1].pixel-contribution[0].pixel+1),image->rows,exception);
+    q=QueueCacheViewAuthenticPixels(resize_view,x,0,1,resize_image->rows,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (y=0; y < (ssize_t) resize_image->rows; y++)
+    {
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        alpha;
+
+      register ssize_t
+        i;
+
+      ssize_t
+        j;
+
+      pixel=zero;
+      if (image->matte == MagickFalse)
+        {
+          for (i=0; i < n; i++)
+          {
+            j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
+              (contribution[i].pixel-contribution[0].pixel);
+            alpha=contribution[i].weight;
+            pixel.red+=alpha*GetPixelRed(image,p+j*
+              GetPixelChannels(image));
+            pixel.green+=alpha*GetPixelGreen(image,p+j*
+              GetPixelChannels(image));
+            pixel.blue+=alpha*GetPixelBlue(image,p+j*
+              GetPixelChannels(image));
+            if ((image->colorspace == CMYKColorspace) &&
+                (resize_image->colorspace == CMYKColorspace))
+              pixel.black+=alpha*GetPixelBlue(image,p+j*
+                GetPixelChannels(image));
+            pixel.alpha+=alpha*GetPixelAlpha(image,p+j*
+              GetPixelChannels(image));
+          }
+          SetPixelRed(resize_image,ClampToQuantum(pixel.red),q);
+          SetPixelGreen(resize_image,ClampToQuantum(pixel.green),q);
+          SetPixelBlue(resize_image,ClampToQuantum(pixel.blue),q);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            SetPixelBlack(resize_image,ClampToQuantum(pixel.black),q);
+          SetPixelAlpha(resize_image,ClampToQuantum(pixel.alpha),q);
+        }
+      else
+        {
+          MagickRealType
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < n; i++)
+          {
+            j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
+              (contribution[i].pixel-contribution[0].pixel);
+            alpha=contribution[i].weight*QuantumScale*
+              GetPixelAlpha(image,p+j*GetPixelChannels(image));
+            pixel.red+=alpha*GetPixelRed(image,p+j*
+              GetPixelChannels(image));
+            pixel.green+=alpha*GetPixelGreen(image,p+j*
+              GetPixelChannels(image));
+            pixel.blue+=alpha*GetPixelBlue(image,p+j*
+              GetPixelChannels(image));
+            if ((image->colorspace == CMYKColorspace) &&
+                (resize_image->colorspace == CMYKColorspace))
+              pixel.black+=alpha*GetPixelBlack(image,p+j*
+                GetPixelChannels(image));
+            pixel.alpha+=contribution[i].weight*
+              GetPixelAlpha(image,p+j*GetPixelChannels(image));
+            gamma+=alpha;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          SetPixelRed(resize_image,ClampToQuantum(gamma*pixel.red),q);
+          SetPixelGreen(resize_image,ClampToQuantum(gamma*pixel.green),q);
+          SetPixelBlue(resize_image,ClampToQuantum(gamma*pixel.blue),q);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            SetPixelBlack(resize_image,ClampToQuantum(gamma*pixel.black),q);
+          SetPixelAlpha(resize_image,ClampToQuantum(pixel.alpha),q);
+        }
+      if ((resize_image->storage_class == PseudoClass) &&
+          (image->storage_class == PseudoClass))
+        {
+          i=(ssize_t) (MagickMin(MagickMax(center,(double) start),(double) stop-
+            1.0)+0.5);
+          j=y*(contribution[n-1].pixel-contribution[0].pixel+1)+
+            (contribution[i-start].pixel-contribution[0].pixel);
+          SetPixelIndex(resize_image,GetPixelIndex(image,p+j*
+            GetPixelChannels(image)),q);
+        }
+      q+=GetPixelChannels(resize_image);
+    }
+    if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_HorizontalFilter)
+#endif
+        proceed=SetImageProgress(image,ResizeImageTag,(*offset)++,span);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  resize_view=DestroyCacheView(resize_view);
+  image_view=DestroyCacheView(image_view);
+  contributions=DestroyContributionThreadSet(contributions);
+  return(status);
+}
+
+static MagickBooleanType VerticalFilter(const ResizeFilter *resize_filter,
+  const Image *image,Image *resize_image,const MagickRealType y_factor,
+  const MagickSizeType span,MagickOffsetType *offset,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view,
+    *resize_view;
+
+  ClassType
+    storage_class;
+
+  ContributionInfo
+    **restrict contributions;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    scale,
+    support;
+
+  ssize_t
+    y;
+
+  /*
+    Apply filter to resize vertically from image to resize image.
+  */
+  scale=MagickMax(1.0/y_factor+MagickEpsilon,1.0);
+  support=scale*GetResizeFilterSupport(resize_filter);
+  storage_class=support > 0.5 ? DirectClass : image->storage_class;
+  if (SetImageStorageClass(resize_image,storage_class) == MagickFalse)
+    {
+      InheritException(exception,&resize_image->exception);
+      return(MagickFalse);
+    }
+  if (support < 0.5)
+    {
+      /*
+        Support too small even for nearest neighbour: Reduce to point
+        sampling.
+      */
+      support=(MagickRealType) 0.5;
+      scale=1.0;
+    }
+  contributions=AcquireContributionThreadSet((size_t) (2.0*support+3.0));
+  if (contributions == (ContributionInfo **) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  status=MagickTrue;
+  scale=1.0/scale;
+  (void) ResetMagickMemory(&zero,0,sizeof(zero));
+  image_view=AcquireCacheView(image);
+  resize_view=AcquireCacheView(resize_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for shared(status)
+#endif
+  for (y=0; y < (ssize_t) resize_image->rows; y++)
+  {
+    MagickRealType
+      center,
+      density;
+
+    register const Quantum
+      *restrict p;
+
+    register ContributionInfo
+      *restrict contribution;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    ssize_t
+      n,
+      start,
+      stop;
+
+    if (status == MagickFalse)
+      continue;
+    center=(MagickRealType) (y+0.5)/y_factor;
+    start=(ssize_t) MagickMax(center-support+0.5,0.0);
+    stop=(ssize_t) MagickMin(center+support+0.5,(double) image->rows);
+    density=0.0;
+    contribution=contributions[GetOpenMPThreadId()];
+    for (n=0; n < (stop-start); n++)
+    {
+      contribution[n].pixel=start+n;
+      contribution[n].weight=GetResizeFilterWeight(resize_filter,scale*
+        ((MagickRealType) (start+n)-center+0.5));
+      density+=contribution[n].weight;
+    }
+    if ((density != 0.0) && (density != 1.0))
+      {
+        register ssize_t
+          i;
+
+        /*
+          Normalize.
+        */
+        density=1.0/density;
+        for (i=0; i < n; i++)
+          contribution[i].weight*=density;
+      }
+    p=GetCacheViewVirtualPixels(image_view,0,contribution[0].pixel,
+      image->columns,(size_t) (contribution[n-1].pixel-contribution[0].pixel+1),
+      exception);
+    q=QueueCacheViewAuthenticPixels(resize_view,0,y,resize_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) resize_image->columns; x++)
+    {
+      PixelInfo
+        pixel;
+
+      MagickRealType
+        alpha;
+
+      register ssize_t
+        i;
+
+      ssize_t
+        j;
+
+      pixel=zero;
+      if (image->matte == MagickFalse)
+        {
+          for (i=0; i < n; i++)
+          {
+            j=(ssize_t) ((contribution[i].pixel-contribution[0].pixel)*
+              image->columns+x);
+            alpha=contribution[i].weight;
+            pixel.red+=alpha*GetPixelRed(image,p+j*
+              GetPixelChannels(image));
+            pixel.green+=alpha*GetPixelGreen(image,p+j*
+              GetPixelChannels(image));
+            pixel.blue+=alpha*GetPixelBlue(image,p+j*
+              GetPixelChannels(image));
+            if ((image->colorspace == CMYKColorspace) &&
+                (resize_image->colorspace == CMYKColorspace))
+              pixel.black+=alpha*GetPixelBlack(image,p+j*
+                GetPixelChannels(image));
+            pixel.alpha+=alpha*GetPixelAlpha(image,p+j*
+              GetPixelChannels(image));
+          }
+          SetPixelRed(resize_image,ClampToQuantum(pixel.red),q);
+          SetPixelGreen(resize_image,ClampToQuantum(pixel.green),q);
+          SetPixelBlue(resize_image,ClampToQuantum(pixel.blue),q);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            SetPixelBlack(resize_image,ClampToQuantum(pixel.black),q);
+          SetPixelAlpha(resize_image,ClampToQuantum(pixel.alpha),q);
+        }
+      else
+        {
+          MagickRealType
+            gamma;
+
+          gamma=0.0;
+          for (i=0; i < n; i++)
+          {
+            j=(ssize_t) ((contribution[i].pixel-contribution[0].pixel)*
+              image->columns+x);
+            alpha=contribution[i].weight*QuantumScale*
+              GetPixelAlpha(image,p+j*GetPixelChannels(image));
+            pixel.red+=alpha*GetPixelRed(image,p+j*
+              GetPixelChannels(image));
+            pixel.green+=alpha*GetPixelGreen(image,p+j*
+              GetPixelChannels(image));
+            pixel.blue+=alpha*GetPixelBlue(image,p+j*
+              GetPixelChannels(image));
+            if ((image->colorspace == CMYKColorspace) &&
+                (resize_image->colorspace == CMYKColorspace))
+              pixel.black+=alpha*GetPixelBlack(image,p+j*
+                GetPixelChannels(image));
+            pixel.alpha+=contribution[i].weight*GetPixelAlpha(image,p+j*
+             GetPixelChannels(image));
+            gamma+=alpha;
+          }
+          gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+          SetPixelRed(resize_image,ClampToQuantum(gamma*pixel.red),q);
+          SetPixelGreen(resize_image,ClampToQuantum(gamma*pixel.green),q);
+          SetPixelBlue(resize_image,ClampToQuantum(gamma*pixel.blue),q);
+          if ((image->colorspace == CMYKColorspace) &&
+              (resize_image->colorspace == CMYKColorspace))
+            SetPixelBlack(resize_image,ClampToQuantum(gamma*pixel.black),q);
+          SetPixelAlpha(resize_image,ClampToQuantum(pixel.alpha),q);
+        }
+      if ((resize_image->storage_class == PseudoClass) &&
+          (image->storage_class == PseudoClass))
+        {
+          i=(ssize_t) (MagickMin(MagickMax(center,(double) start),(double) stop-
+            1.0)+0.5);
+          j=(ssize_t) ((contribution[i-start].pixel-contribution[0].pixel)*
+            image->columns+x);
+          SetPixelIndex(resize_image,GetPixelIndex(image,p+j*
+            GetPixelChannels(image)),q);
+        }
+      q+=GetPixelChannels(resize_image);
+    }
+    if (SyncCacheViewAuthenticPixels(resize_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_VerticalFilter)
+#endif
+        proceed=SetImageProgress(image,ResizeImageTag,(*offset)++,span);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  resize_view=DestroyCacheView(resize_view);
+  image_view=DestroyCacheView(image_view);
+  contributions=DestroyContributionThreadSet(contributions);
+  return(status);
+}
+
+MagickExport Image *ResizeImage(const Image *image,const size_t columns,
+  const size_t rows,const FilterTypes filter,const double blur,
+  ExceptionInfo *exception)
+{
+#define WorkLoadFactor  0.265
+
+  FilterTypes
+    filter_type;
+
+  Image
+    *filter_image,
+    *resize_image;
+
+  MagickOffsetType
+    offset;
+
+  MagickRealType
+    x_factor,
+    y_factor;
+
+  MagickSizeType
+    span;
+
+  MagickStatusType
+    status;
+
+  ResizeFilter
+    *resize_filter;
+
+  /*
+    Acquire resize image.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((columns == 0) || (rows == 0))
+    ThrowImageException(ImageError,"NegativeOrZeroImageSize");
+  if ((columns == image->columns) && (rows == image->rows) &&
+      (filter == UndefinedFilter) && (blur == 1.0))
+    return(CloneImage(image,0,0,MagickTrue,exception));
+  resize_image=CloneImage(image,columns,rows,MagickTrue,exception);
+  if (resize_image == (Image *) NULL)
+    return(resize_image);
+  /*
+    Acquire resize filter.
+  */
+  x_factor=(MagickRealType) columns/(MagickRealType) image->columns;
+  y_factor=(MagickRealType) rows/(MagickRealType) image->rows;
+  if ((x_factor*y_factor) > WorkLoadFactor)
+    filter_image=CloneImage(image,columns,image->rows,MagickTrue,exception);
+  else
+    filter_image=CloneImage(image,image->columns,rows,MagickTrue,exception);
+  if (filter_image == (Image *) NULL)
+    return(DestroyImage(resize_image));
+  filter_type=LanczosFilter;
+  if (filter != UndefinedFilter)
+    filter_type=filter;
+  else
+    if ((x_factor == 1.0) && (y_factor == 1.0))
+      filter_type=PointFilter;
+    else
+      if ((image->storage_class == PseudoClass) ||
+          (image->matte != MagickFalse) || ((x_factor*y_factor) > 1.0))
+        filter_type=MitchellFilter;
+  resize_filter=AcquireResizeFilter(image,filter_type,blur,MagickFalse,
+    exception);
+  /*
+    Resize image.
+  */
+  offset=0;
+  if ((x_factor*y_factor) > WorkLoadFactor)
+    {
+      span=(MagickSizeType) (filter_image->columns+rows);
+      status=HorizontalFilter(resize_filter,image,filter_image,x_factor,span,
+        &offset,exception);
+      status&=VerticalFilter(resize_filter,filter_image,resize_image,y_factor,
+        span,&offset,exception);
+    }
+  else
+    {
+      span=(MagickSizeType) (filter_image->rows+columns);
+      status=VerticalFilter(resize_filter,image,filter_image,y_factor,span,
+        &offset,exception);
+      status&=HorizontalFilter(resize_filter,filter_image,resize_image,x_factor,
+        span,&offset,exception);
+    }
+  /*
+    Free resources.
+  */
+  filter_image=DestroyImage(filter_image);
+  resize_filter=DestroyResizeFilter(resize_filter);
+  if ((status == MagickFalse) || (resize_image == (Image *) NULL))
+    return((Image *) NULL);
+  resize_image->type=image->type;
+  return(resize_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S a m p l e I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SampleImage() scales an image to the desired dimensions with pixel
+%  sampling.  Unlike other scaling methods, this method does not introduce
+%  any additional color into the scaled image.
+%
+%  The format of the SampleImage method is:
+%
+%      Image *SampleImage(const Image *image,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the sampled image.
+%
+%    o rows: the number of rows in the sampled image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SampleImage(const Image *image,const size_t columns,
+  const size_t rows,ExceptionInfo *exception)
+{
+#define SampleImageTag  "Sample/Image"
+
+  CacheView
+    *image_view,
+    *sample_view;
+
+  Image
+    *sample_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  register ssize_t
+    x;
+
+  ssize_t
+    *x_offset,
+    y;
+
+  /*
+    Initialize sampled image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((columns == 0) || (rows == 0))
+    ThrowImageException(ImageError,"NegativeOrZeroImageSize");
+  if ((columns == image->columns) && (rows == image->rows))
+    return(CloneImage(image,0,0,MagickTrue,exception));
+  sample_image=CloneImage(image,columns,rows,MagickTrue,exception);
+  if (sample_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Allocate scan line buffer and column offset buffers.
+  */
+  x_offset=(ssize_t *) AcquireQuantumMemory((size_t) sample_image->columns,
+    sizeof(*x_offset));
+  if (x_offset == (ssize_t *) NULL)
+    {
+      sample_image=DestroyImage(sample_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  for (x=0; x < (ssize_t) sample_image->columns; x++)
+    x_offset[x]=(ssize_t) (((MagickRealType) x+0.5)*image->columns/
+      sample_image->columns);
+  /*
+    Sample each row.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  sample_view=AcquireCacheView(sample_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) sample_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    ssize_t
+      y_offset;
+
+    if (status == MagickFalse)
+      continue;
+    y_offset=(ssize_t) (((MagickRealType) y+0.5)*image->rows/
+      sample_image->rows);
+    p=GetCacheViewVirtualPixels(image_view,0,y_offset,image->columns,1,
+      exception);
+    q=QueueCacheViewAuthenticPixels(sample_view,0,y,sample_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    /*
+      Sample each column.
+    */
+    for (x=0; x < (ssize_t) sample_image->columns; x++)
+    {
+      SetPixelRed(sample_image,GetPixelRed(image,p+x_offset[x]*
+        GetPixelChannels(image)),q);
+      SetPixelGreen(sample_image,GetPixelGreen(image,p+x_offset[x]*
+        GetPixelChannels(image)),q);
+      SetPixelBlue(sample_image,GetPixelBlue(image,p+x_offset[x]*
+        GetPixelChannels(image)),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(sample_image,GetPixelBlack(image,p+x_offset[x]*
+          GetPixelChannels(image)),q);
+      if (image->matte != MagickFalse)
+        SetPixelAlpha(sample_image,GetPixelAlpha(image,p+x_offset[x]*
+          GetPixelChannels(image)),q);
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(sample_image,GetPixelIndex(image,p+x_offset[x]*
+          GetPixelChannels(image)),q);
+      q+=GetPixelChannels(sample_image);
+    }
+    if (SyncCacheViewAuthenticPixels(sample_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_SampleImage)
+#endif
+        proceed=SetImageProgress(image,SampleImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  sample_view=DestroyCacheView(sample_view);
+  x_offset=(ssize_t *) RelinquishMagickMemory(x_offset);
+  sample_image->type=image->type;
+  return(sample_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S c a l e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ScaleImage() changes the size of an image to the given dimensions.
+%
+%  The format of the ScaleImage method is:
+%
+%      Image *ScaleImage(const Image *image,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the scaled image.
+%
+%    o rows: the number of rows in the scaled image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ScaleImage(const Image *image,const size_t columns,
+  const size_t rows,ExceptionInfo *exception)
+{
+#define ScaleImageTag  "Scale/Image"
+
+  CacheView
+    *image_view,
+    *scale_view;
+
+  Image
+    *scale_image;
+
+  MagickBooleanType
+    next_column,
+    next_row,
+    proceed;
+
+  PixelInfo
+    pixel,
+    *scale_scanline,
+    *scanline,
+    *x_vector,
+    *y_vector,
+    zero;
+
+  MagickRealType
+    alpha;
+
+  PointInfo
+    scale,
+    span;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    number_rows,
+    y;
+
+  /*
+    Initialize scaled image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((columns == 0) || (rows == 0))
+    return((Image *) NULL);
+  if ((columns == image->columns) && (rows == image->rows))
+    return(CloneImage(image,0,0,MagickTrue,exception));
+  scale_image=CloneImage(image,columns,rows,MagickTrue,exception);
+  if (scale_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(scale_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&scale_image->exception);
+      scale_image=DestroyImage(scale_image);
+      return((Image *) NULL);
+    }
+  /*
+    Allocate memory.
+  */
+  x_vector=(PixelInfo *) AcquireQuantumMemory((size_t) image->columns,
+    sizeof(*x_vector));
+  scanline=x_vector;
+  if (image->rows != scale_image->rows)
+    scanline=(PixelInfo *) AcquireQuantumMemory((size_t) image->columns,
+      sizeof(*scanline));
+  scale_scanline=(PixelInfo *) AcquireQuantumMemory((size_t)
+    scale_image->columns,sizeof(*scale_scanline));
+  y_vector=(PixelInfo *) AcquireQuantumMemory((size_t) image->columns,
+    sizeof(*y_vector));
+  if ((scanline == (PixelInfo *) NULL) ||
+      (scale_scanline == (PixelInfo *) NULL) ||
+      (x_vector == (PixelInfo *) NULL) ||
+      (y_vector == (PixelInfo *) NULL))
+    {
+      scale_image=DestroyImage(scale_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  /*
+    Scale image.
+  */
+  number_rows=0;
+  next_row=MagickTrue;
+  span.y=1.0;
+  scale.y=(double) scale_image->rows/(double) image->rows;
+  (void) ResetMagickMemory(y_vector,0,(size_t) image->columns*
+    sizeof(*y_vector));
+  GetPixelInfo(image,&pixel);
+  (void) ResetMagickMemory(&zero,0,sizeof(zero));
+  i=0;
+  image_view=AcquireCacheView(image);
+  scale_view=AcquireCacheView(scale_image);
+  for (y=0; y < (ssize_t) scale_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register PixelInfo
+      *restrict s,
+      *restrict t;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    q=QueueCacheViewAuthenticPixels(scale_view,0,y,scale_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    alpha=1.0;
+    if (scale_image->rows == image->rows)
+      {
+        /*
+          Read a new scanline.
+        */
+        p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,
+          exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          if (image->matte != MagickFalse)
+            alpha=QuantumScale*GetPixelAlpha(image,p);
+          x_vector[x].red=(MagickRealType) (alpha*GetPixelRed(image,p));
+          x_vector[x].green=(MagickRealType) (alpha*GetPixelGreen(image,p));
+          x_vector[x].blue=(MagickRealType) (alpha*GetPixelBlue(image,p));
+          if (image->matte != MagickFalse)
+            x_vector[x].alpha=(MagickRealType) GetPixelAlpha(image,p);
+          if (image->colorspace == CMYKColorspace)
+            x_vector[x].black=(MagickRealType) (alpha*GetPixelBlack(image,p));
+          p+=GetPixelChannels(image);
+        }
+      }
+    else
+      {
+        /*
+          Scale Y direction.
+        */
+        while (scale.y < span.y)
+        {
+          if ((next_row != MagickFalse) &&
+              (number_rows < (ssize_t) image->rows))
+            {
+              /*
+                Read a new scanline.
+              */
+              p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,
+                exception);
+              if (p == (const Quantum *) NULL)
+                break;
+              for (x=0; x < (ssize_t) image->columns; x++)
+              {
+                if (image->matte != MagickFalse)
+                  alpha=QuantumScale*
+                    GetPixelAlpha(image,p);
+                x_vector[x].red=(MagickRealType) (alpha*
+                  GetPixelRed(image,p));
+                x_vector[x].green=(MagickRealType) (alpha*
+                  GetPixelGreen(image,p));
+                x_vector[x].blue=(MagickRealType) (alpha*
+                  GetPixelBlue(image,p));
+                if (image->colorspace == CMYKColorspace)
+                  x_vector[x].black=(MagickRealType) (alpha*
+                    GetPixelBlack(image,p));
+                if (image->matte != MagickFalse)
+                  x_vector[x].alpha=(MagickRealType)
+                    GetPixelAlpha(image,p);
+                p+=GetPixelChannels(image);
+              }
+              number_rows++;
+            }
+          for (x=0; x < (ssize_t) image->columns; x++)
+          {
+            y_vector[x].red+=scale.y*x_vector[x].red;
+            y_vector[x].green+=scale.y*x_vector[x].green;
+            y_vector[x].blue+=scale.y*x_vector[x].blue;
+            if (scale_image->colorspace == CMYKColorspace)
+              y_vector[x].black+=scale.y*x_vector[x].black;
+            if (scale_image->matte != MagickFalse)
+              y_vector[x].alpha+=scale.y*x_vector[x].alpha;
+          }
+          span.y-=scale.y;
+          scale.y=(double) scale_image->rows/(double) image->rows;
+          next_row=MagickTrue;
+        }
+        if ((next_row != MagickFalse) && (number_rows < (ssize_t) image->rows))
+          {
+            /*
+              Read a new scanline.
+            */
+            p=GetCacheViewVirtualPixels(image_view,0,i++,image->columns,1,
+              exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (ssize_t) image->columns; x++)
+            {
+              if (image->matte != MagickFalse)
+                alpha=QuantumScale*GetPixelAlpha(image,p);
+              x_vector[x].red=(MagickRealType) (alpha*GetPixelRed(image,p));
+              x_vector[x].green=(MagickRealType) (alpha*GetPixelGreen(image,p));
+              x_vector[x].blue=(MagickRealType) (alpha*GetPixelBlue(image,p));
+              if (image->colorspace == CMYKColorspace)
+                x_vector[x].black=(MagickRealType) (alpha*
+                  GetPixelBlack(image,p));
+              if (image->matte != MagickFalse)
+                x_vector[x].alpha=(MagickRealType) GetPixelAlpha(image,p);
+              p+=GetPixelChannels(image);
+            }
+            number_rows++;
+            next_row=MagickFalse;
+          }
+        s=scanline;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          pixel.red=y_vector[x].red+span.y*x_vector[x].red;
+          pixel.green=y_vector[x].green+span.y*x_vector[x].green;
+          pixel.blue=y_vector[x].blue+span.y*x_vector[x].blue;
+          if (image->colorspace == CMYKColorspace)
+            pixel.black=y_vector[x].black+span.y*x_vector[x].black;
+          if (image->matte != MagickFalse)
+            pixel.alpha=y_vector[x].alpha+span.y*x_vector[x].alpha;
+          s->red=pixel.red;
+          s->green=pixel.green;
+          s->blue=pixel.blue;
+          if (scale_image->colorspace == CMYKColorspace)
+            s->black=pixel.black;
+          if (scale_image->matte != MagickFalse)
+            s->alpha=pixel.alpha;
+          s++;
+          y_vector[x]=zero;
+        }
+        scale.y-=span.y;
+        if (scale.y <= 0)
+          {
+            scale.y=(double) scale_image->rows/(double) image->rows;
+            next_row=MagickTrue;
+          }
+        span.y=1.0;
+      }
+    if (scale_image->columns == image->columns)
+      {
+        /*
+          Transfer scanline to scaled image.
+        */
+        s=scanline;
+        for (x=0; x < (ssize_t) scale_image->columns; x++)
+        {
+          if (scale_image->matte != MagickFalse)
+            alpha=QuantumScale*s->alpha;
+          alpha=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+          SetPixelRed(scale_image,ClampToQuantum(alpha*s->red),q);
+          SetPixelGreen(scale_image,ClampToQuantum(alpha*s->green),q);
+          SetPixelBlue(scale_image,ClampToQuantum(alpha*s->blue),q);
+          if (scale_image->colorspace == CMYKColorspace)
+            SetPixelBlack(scale_image,ClampToQuantum(alpha*s->black),q);
+          if (scale_image->matte != MagickFalse)
+            SetPixelAlpha(scale_image,ClampToQuantum(s->alpha),q);
+          q+=GetPixelChannels(scale_image);
+          s++;
+        }
+      }
+    else
+      {
+        /*
+          Scale X direction.
+        */
+        pixel=zero;
+        next_column=MagickFalse;
+        span.x=1.0;
+        s=scanline;
+        t=scale_scanline;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          scale.x=(double) scale_image->columns/(double) image->columns;
+          while (scale.x >= span.x)
+          {
+            if (next_column != MagickFalse)
+              {
+                pixel=zero;
+                t++;
+              }
+            pixel.red+=span.x*s->red;
+            pixel.green+=span.x*s->green;
+            pixel.blue+=span.x*s->blue;
+            if (scale_image->colorspace == CMYKColorspace)
+              pixel.black+=span.x*s->black;
+            if (image->matte != MagickFalse)
+              pixel.alpha+=span.x*s->alpha;
+            t->red=pixel.red;
+            t->green=pixel.green;
+            t->blue=pixel.blue;
+            if (scale_image->colorspace == CMYKColorspace)
+              t->black=pixel.black;
+            if (scale_image->matte != MagickFalse)
+              t->alpha=pixel.alpha;
+            scale.x-=span.x;
+            span.x=1.0;
+            next_column=MagickTrue;
+          }
+        if (scale.x > 0)
+          {
+            if (next_column != MagickFalse)
+              {
+                pixel=zero;
+                next_column=MagickFalse;
+                t++;
+              }
+            pixel.red+=scale.x*s->red;
+            pixel.green+=scale.x*s->green;
+            pixel.blue+=scale.x*s->blue;
+            if (scale_image->colorspace == CMYKColorspace)
+              pixel.black+=scale.x*s->black;
+            if (scale_image->matte != MagickFalse)
+              pixel.alpha+=scale.x*s->alpha;
+            span.x-=scale.x;
+          }
+        s++;
+      }
+      if (span.x > 0)
+        {
+          s--;
+          pixel.red+=span.x*s->red;
+          pixel.green+=span.x*s->green;
+          pixel.blue+=span.x*s->blue;
+          if (scale_image->colorspace == CMYKColorspace)
+            pixel.black+=span.x*s->black;
+          if (scale_image->matte != MagickFalse)
+            pixel.alpha+=span.x*s->alpha;
+        }
+      if ((next_column == MagickFalse) &&
+          ((ssize_t) (t-scale_scanline) < (ssize_t) scale_image->columns))
+        {
+          t->red=pixel.red;
+          t->green=pixel.green;
+          t->blue=pixel.blue;
+          if (scale_image->colorspace == CMYKColorspace)
+            t->black=pixel.black;
+          if (scale_image->matte != MagickFalse)
+            t->alpha=pixel.alpha;
+        }
+      /*
+        Transfer scanline to scaled image.
+      */
+      t=scale_scanline;
+      for (x=0; x < (ssize_t) scale_image->columns; x++)
+      {
+        if (scale_image->matte != MagickFalse)
+          alpha=QuantumScale*s->alpha;
+        alpha=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        SetPixelRed(scale_image,ClampToQuantum(alpha*t->red),q);
+        SetPixelGreen(scale_image,ClampToQuantum(alpha*t->green),q);
+        SetPixelBlue(scale_image,ClampToQuantum(alpha*t->blue),q);
+        if (scale_image->colorspace == CMYKColorspace)
+          SetPixelBlack(scale_image,ClampToQuantum(alpha*t->black),q);
+        if (scale_image->matte != MagickFalse)
+          SetPixelAlpha(scale_image,ClampToQuantum(t->alpha),q);
+        t++;
+        q+=GetPixelChannels(scale_image);
+      }
+    }
+    if (SyncCacheViewAuthenticPixels(scale_view,exception) == MagickFalse)
+      break;
+    proceed=SetImageProgress(image,ScaleImageTag,(MagickOffsetType) y,
+      image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  scale_view=DestroyCacheView(scale_view);
+  image_view=DestroyCacheView(image_view);
+  /*
+    Free allocated memory.
+  */
+  y_vector=(PixelInfo *) RelinquishMagickMemory(y_vector);
+  scale_scanline=(PixelInfo *) RelinquishMagickMemory(scale_scanline);
+  if (scale_image->rows != image->rows)
+    scanline=(PixelInfo *) RelinquishMagickMemory(scanline);
+  x_vector=(PixelInfo *) RelinquishMagickMemory(x_vector);
+  scale_image->type=image->type;
+  return(scale_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T h u m b n a i l I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ThumbnailImage() changes the size of an image to the given dimensions and
+%  removes any associated profiles.  The goal is to produce small low cost
+%  thumbnail images suited for display on the Web.
+%
+%  The format of the ThumbnailImage method is:
+%
+%      Image *ThumbnailImage(const Image *image,const size_t columns,
+%        const size_t rows,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o columns: the number of columns in the scaled image.
+%
+%    o rows: the number of rows in the scaled image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ThumbnailImage(const Image *image,const size_t columns,
+  const size_t rows,ExceptionInfo *exception)
+{
+#define SampleFactor  5
+
+  char
+    value[MaxTextExtent];
+
+  const char
+    *name;
+
+  Image
+    *thumbnail_image;
+
+  MagickRealType
+    x_factor,
+    y_factor;
+
+  size_t
+    version;
+
+  struct stat
+    attributes;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  x_factor=(MagickRealType) columns/(MagickRealType) image->columns;
+  y_factor=(MagickRealType) rows/(MagickRealType) image->rows;
+  if ((x_factor*y_factor) > 0.1)
+    thumbnail_image=ResizeImage(image,columns,rows,image->filter,image->blur,
+      exception);
+  else
+    if (((SampleFactor*columns) < 128) || ((SampleFactor*rows) < 128))
+      thumbnail_image=ResizeImage(image,columns,rows,image->filter,
+        image->blur,exception);
+    else
+      {
+        Image
+          *sample_image;
+
+        sample_image=SampleImage(image,SampleFactor*columns,SampleFactor*rows,
+          exception);
+        if (sample_image == (Image *) NULL)
+          return((Image *) NULL);
+        thumbnail_image=ResizeImage(sample_image,columns,rows,image->filter,
+          image->blur,exception);
+        sample_image=DestroyImage(sample_image);
+      }
+  if (thumbnail_image == (Image *) NULL)
+    return(thumbnail_image);
+  (void) ParseAbsoluteGeometry("0x0+0+0",&thumbnail_image->page);
+  if (thumbnail_image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(thumbnail_image,OpaqueAlphaChannel);
+  thumbnail_image->depth=8;
+  thumbnail_image->interlace=NoInterlace;
+  /*
+    Strip all profiles except color profiles.
+  */
+  ResetImageProfileIterator(thumbnail_image);
+  for (name=GetNextImageProfile(thumbnail_image); name != (const char *) NULL; )
+  {
+    if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"icm") != 0))
+     {
+       (void) DeleteImageProfile(thumbnail_image,name);
+       ResetImageProfileIterator(thumbnail_image);
+     }
+    name=GetNextImageProfile(thumbnail_image);
+  }
+  (void) DeleteImageProperty(thumbnail_image,"comment");
+  (void) CopyMagickString(value,image->magick_filename,MaxTextExtent);
+  if (strstr(image->magick_filename,"//") == (char *) NULL)
+    (void) FormatLocaleString(value,MaxTextExtent,"file://%s",
+      image->magick_filename);
+  (void) SetImageProperty(thumbnail_image,"Thumb::URI",value);
+  (void) CopyMagickString(value,image->magick_filename,MaxTextExtent);
+  if (GetPathAttributes(image->filename,&attributes) != MagickFalse)
+    {
+      (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+        attributes.st_mtime);
+      (void) SetImageProperty(thumbnail_image,"Thumb::MTime",value);
+    }
+  (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+    attributes.st_mtime);
+  (void) FormatMagickSize(GetBlobSize(image),MagickFalse,value);
+  (void) ConcatenateMagickString(value,"B",MaxTextExtent);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Size",value);
+  (void) FormatLocaleString(value,MaxTextExtent,"image/%s",image->magick);
+  LocaleLower(value);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Mimetype",value);
+  (void) SetImageProperty(thumbnail_image,"software",
+    GetMagickVersion(&version));
+  (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+    image->magick_columns);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Image::Width",value);
+  (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+    image->magick_rows);
+  (void) SetImageProperty(thumbnail_image,"Thumb::Image::height",value);
+  (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+    GetImageListLength(image));
+  (void) SetImageProperty(thumbnail_image,"Thumb::Document::Pages",value);
+  return(thumbnail_image);
+}
diff --git a/MagickCore/resize.h b/MagickCore/resize.h
new file mode 100644
index 0000000..ca336d8
--- /dev/null
+++ b/MagickCore/resize.h
@@ -0,0 +1,43 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image resize methods.
+*/
+#ifndef _MAGICKCORE_RESIZE_H
+#define _MAGICKCORE_RESIZE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport Image
+  *AdaptiveResizeImage(const Image *,const size_t,const size_t,ExceptionInfo *),
+  *LiquidRescaleImage(const Image *,const size_t,const size_t,const double,
+    const double,ExceptionInfo *),
+  *MagnifyImage(const Image *,ExceptionInfo *),
+  *MinifyImage(const Image *,ExceptionInfo *),
+  *ResampleImage(const Image *,const double,const double,const FilterTypes,
+    const double,ExceptionInfo *),
+  *ResizeImage(const Image *,const size_t,const size_t,const FilterTypes,
+    const double,ExceptionInfo *),
+  *SampleImage(const Image *,const size_t,const size_t,ExceptionInfo *),
+  *ScaleImage(const Image *,const size_t,const size_t,ExceptionInfo *),
+  *ThumbnailImage(const Image *,const size_t,const size_t,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/resource.c b/MagickCore/resource.c
new file mode 100644
index 0000000..1fc7c48
--- /dev/null
+++ b/MagickCore/resource.c
@@ -0,0 +1,1161 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%           RRRR    EEEEE   SSSSS   OOO   U   U  RRRR    CCCC  EEEEE          %
+%           R   R   E       SS     O   O  U   U  R   R  C      E              %
+%           RRRR    EEE      SSS   O   O  U   U  RRRR   C      EEE            %
+%           R R     E          SS  O   O  U   U  R R    C      E              %
+%           R  R    EEEEE   SSSSS   OOO    UUU   R  R    CCCC  EEEEE          %
+%                                                                             %
+%                                                                             %
+%                        Get/Set MagickCore Resources                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               September 2002                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/log.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/registry.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+
+/*
+  Typedef declarations.
+*/
+typedef struct _ResourceInfo
+{
+  MagickOffsetType
+    area,
+    memory,
+    map,
+    disk,
+    file,
+    thread,
+    time;
+
+  MagickSizeType
+    area_limit,
+    memory_limit,
+    map_limit,
+    disk_limit,
+    file_limit,
+    thread_limit,
+    time_limit;
+} ResourceInfo;
+
+/*
+  Global declarations.
+*/
+static RandomInfo
+  *random_info = (RandomInfo *) NULL;
+
+static ResourceInfo
+  resource_info =
+  {
+    MagickULLConstant(0),
+    MagickULLConstant(0),
+    MagickULLConstant(0),
+    MagickULLConstant(0),
+    MagickULLConstant(0),
+    MagickULLConstant(0),
+    MagickULLConstant(0),
+    MagickULLConstant(3072)*1024*1024/sizeof(PixelPacket),
+    MagickULLConstant(1536)*1024*1024,
+    MagickULLConstant(3072)*1024*1024,
+    MagickResourceInfinity,
+    MagickULLConstant(768),
+    MagickULLConstant(4),
+    MagickResourceInfinity
+  };
+
+static SemaphoreInfo
+  *resource_semaphore = (SemaphoreInfo *) NULL;
+
+static SplayTreeInfo
+  *temporary_resources = (SplayTreeInfo *) NULL;
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e M a g i c k R e s o u r c e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireMagickResource() acquires resources of the specified type.
+%  MagickFalse is returned if the specified resource is exhausted otherwise
+%  MagickTrue.
+%
+%  The format of the AcquireMagickResource() method is:
+%
+%      MagickBooleanType AcquireMagickResource(const ResourceType type,
+%        const MagickSizeType size)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type of resource.
+%
+%    o size: the number of bytes needed from for this resource.
+%
+*/
+MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
+  const MagickSizeType size)
+{
+  char
+    resource_current[MaxTextExtent],
+    resource_limit[MaxTextExtent],
+    resource_request[MaxTextExtent];
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    limit;
+
+  status=MagickFalse;
+  (void) FormatMagickSize(size,MagickFalse,resource_request);
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource_info.area=(MagickOffsetType) size;
+      limit=resource_info.area_limit;
+      status=(resource_info.area_limit == MagickResourceInfinity) ||
+        (size < limit) ? MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.area,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
+        resource_limit);
+      break;
+    }
+    case MemoryResource:
+    {
+      resource_info.memory+=size;
+      limit=resource_info.memory_limit;
+      status=(resource_info.memory_limit == MagickResourceInfinity) ||
+        ((MagickSizeType) resource_info.memory < limit) ?
+        MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.memory,MagickTrue,
+        resource_current);
+      (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
+        resource_limit);
+      break;
+    }
+    case MapResource:
+    {
+      resource_info.map+=size;
+      limit=resource_info.map_limit;
+      status=(resource_info.map_limit == MagickResourceInfinity) ||
+        ((MagickSizeType) resource_info.map < limit) ?
+        MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.map,MagickTrue,
+        resource_current);
+      (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
+        resource_limit);
+      break;
+    }
+    case DiskResource:
+    {
+      resource_info.disk+=size;
+      limit=resource_info.disk_limit;
+      status=(resource_info.disk_limit == MagickResourceInfinity) ||
+        ((MagickSizeType) resource_info.disk < limit) ?
+        MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.disk,MagickTrue,
+        resource_current);
+      (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
+        resource_limit);
+      break;
+    }
+    case FileResource:
+    {
+      resource_info.file+=size;
+      limit=resource_info.file_limit;
+      status=(resource_info.file_limit == MagickResourceInfinity) ||
+        ((MagickSizeType) resource_info.file < limit) ?
+        MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.file,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
+        MagickFalse,resource_limit);
+      break;
+    }
+    case ThreadResource:
+    {
+      resource_info.thread+=size;
+      limit=resource_info.thread_limit;
+      status=(resource_info.thread_limit == MagickResourceInfinity) ||
+        ((MagickSizeType) resource_info.thread < limit) ?
+        MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
+        MagickFalse,resource_limit);
+      break;
+    }
+    case TimeResource:
+    {
+      resource_info.time+=size;
+      limit=resource_info.time_limit;
+      status=(resource_info.time_limit == MagickResourceInfinity) ||
+        ((MagickSizeType) resource_info.time < limit) ?
+        MagickTrue : MagickFalse;
+      (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
+        MagickFalse,resource_limit);
+      break;
+    }
+    default:
+      break;
+  }
+  UnlockSemaphoreInfo(resource_semaphore);
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
+    CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
+    resource_request,resource_current,resource_limit);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A s y n c h r o n o u s R e s o u r c e C o m p o n e n t T e r m i n u s %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AsynchronousResourceComponentTerminus() destroys the resource environment.
+%  It differs from ResourceComponentTerminus() in that it can be called from a
+%  asynchronous signal handler.
+%
+%  The format of the ResourceComponentTerminus() method is:
+%
+%      ResourceComponentTerminus(void)
+%
+*/
+MagickExport void AsynchronousResourceComponentTerminus(void)
+{
+  const char
+    *path;
+
+  if (temporary_resources == (SplayTreeInfo *) NULL)
+    return;
+  /*
+    Remove any lingering temporary files.
+  */
+  ResetSplayTreeIterator(temporary_resources);
+  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
+  while (path != (const char *) NULL)
+  {
+    (void) remove(path);
+    path=(const char *) GetNextKeyInSplayTree(temporary_resources);
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e U n i q u e F i l e R e s o u r c e                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireUniqueFileResource() returns a unique file name, and returns a file
+%  descriptor for the file open for reading and writing.
+%
+%  The format of the AcquireUniqueFileResource() method is:
+%
+%      int AcquireUniqueFileResource(char *path)
+%
+%  A description of each parameter follows:
+%
+%   o  path:  Specifies a pointer to an array of characters.  The unique path
+%      name is returned in this array.
+%
+*/
+
+static void *DestroyTemporaryResources(void *temporary_resource)
+{
+  (void) remove((char *) temporary_resource);
+  temporary_resource=DestroyString((char *) temporary_resource);
+  return((void *) NULL);
+}
+
+static MagickBooleanType GetPathTemplate(char *path)
+{
+  char
+    *directory;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  register char
+    *p;
+
+  struct stat
+    attributes;
+
+  (void) CopyMagickString(path,"magick-XXXXXXXX",MaxTextExtent);
+  exception=AcquireExceptionInfo();
+  directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
+    exception);
+  exception=DestroyExceptionInfo(exception);
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("MAGICK_TMPDIR");
+  if (directory == (char *) NULL)
+    directory=GetPolicyValue("temporary-path");
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("TMPDIR");
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("TMP");
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("TEMP");
+#endif
+#if defined(__VMS)
+  if (directory == (char *) NULL)
+    directory=GetEnvironmentValue("MTMPDIR");
+#endif
+#if defined(P_tmpdir)
+  if (directory == (char *) NULL)
+    directory=ConstantString(P_tmpdir);
+#endif
+  if (directory == (char *) NULL)
+    return(MagickTrue);
+  if (strlen(directory) > (MaxTextExtent-15))
+    {
+      directory=DestroyString(directory);
+      return(MagickTrue);
+    }
+  status=GetPathAttributes(directory,&attributes);
+  if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
+    {
+      directory=DestroyString(directory);
+      return(MagickTrue);
+    }
+  if (directory[strlen(directory)-1] == *DirectorySeparator)
+    (void) FormatLocaleString(path,MaxTextExtent,"%smagick-XXXXXXXX",directory);
+  else
+    (void) FormatLocaleString(path,MaxTextExtent,"%s%smagick-XXXXXXXX",
+      directory,DirectorySeparator);
+  directory=DestroyString(directory);
+  if (*DirectorySeparator != '/')
+    for (p=path; *p != '\0'; p++)
+      if (*p == *DirectorySeparator)
+        *p='/';
+  return(MagickTrue);
+}
+
+MagickExport int AcquireUniqueFileResource(char *path)
+{
+#if !defined(O_NOFOLLOW)
+#define O_NOFOLLOW 0
+#endif
+#if !defined(TMP_MAX)
+# define TMP_MAX  238328
+#endif
+
+  int
+    c,
+    file;
+
+  register char
+    *p;
+
+  register ssize_t
+    i;
+
+  static const char
+    portable_filename[65] =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
+
+  StringInfo
+    *key;
+
+  unsigned char
+    *datum;
+
+  assert(path != (char *) NULL);
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
+  if (random_info == (RandomInfo *) NULL)
+    random_info=AcquireRandomInfo();
+  file=(-1);
+  for (i=0; i < (ssize_t) TMP_MAX; i++)
+  {
+    /*
+      Get temporary pathname.
+    */
+    (void) GetPathTemplate(path);
+    key=GetRandomKey(random_info,2);
+    p=path+strlen(path)-8;
+    datum=GetStringInfoDatum(key);
+    for (i=0; i < (ssize_t) GetStringInfoLength(key); i++)
+    {
+      c=(int) (datum[i] & 0x3f);
+      *p++=portable_filename[c];
+    }
+    key=DestroyStringInfo(key);
+#if defined(MAGICKCORE_HAVE_MKSTEMP)
+    file=mkstemp(path);
+#if defined(__OS2__)
+    setmode(file,O_BINARY);
+#endif
+    if (file != -1)
+      break;
+#endif
+    key=GetRandomKey(random_info,6);
+    p=path+strlen(path)-6;
+    datum=GetStringInfoDatum(key);
+    for (i=0; i < (ssize_t) GetStringInfoLength(key); i++)
+    {
+      c=(int) (datum[i] & 0x3f);
+      *p++=portable_filename[c];
+    }
+    key=DestroyStringInfo(key);
+    file=open(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,S_MODE);
+    if ((file >= 0) || (errno != EEXIST))
+      break;
+  }
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
+  if (file == -1)
+    return(file);
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  if (temporary_resources == (SplayTreeInfo *) NULL)
+    temporary_resources=NewSplayTree(CompareSplayTreeString,
+      DestroyTemporaryResources,(void *(*)(void *)) NULL);
+  UnlockSemaphoreInfo(resource_semaphore);
+  (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
+    (const void *) NULL);
+  return(file);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k R e s o u r c e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickResource() returns the specified resource.
+%
+%  The format of the GetMagickResource() method is:
+%
+%      MagickSizeType GetMagickResource(const ResourceType type)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type of resource.
+%
+*/
+MagickExport MagickSizeType GetMagickResource(const ResourceType type)
+{
+  MagickSizeType
+    resource;
+
+  resource=0;
+  LockSemaphoreInfo(resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource=(MagickSizeType) resource_info.area;
+      break;
+    }
+    case MemoryResource:
+    {
+      resource=(MagickSizeType) resource_info.memory;
+      break;
+    }
+    case MapResource:
+    {
+      resource=(MagickSizeType) resource_info.map;
+      break;
+    }
+    case DiskResource:
+    {
+      resource=(MagickSizeType) resource_info.disk;
+      break;
+    }
+    case FileResource:
+    {
+      resource=(MagickSizeType) resource_info.file;
+      break;
+    }
+    case ThreadResource:
+    {
+      resource=(MagickSizeType) resource_info.thread;
+      break;
+    }
+    case TimeResource:
+    {
+      resource=(MagickSizeType) resource_info.time;
+      break;
+    }
+    default:
+      break;
+  }
+  UnlockSemaphoreInfo(resource_semaphore);
+  return(resource);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k R e s o u r c e L i m i t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickResourceLimit() returns the specified resource limit.
+%
+%  The format of the GetMagickResourceLimit() method is:
+%
+%      MagickSizeType GetMagickResourceLimit(const ResourceType type)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type of resource.
+%
+*/
+MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
+{
+  MagickSizeType
+    resource;
+
+  resource=0;
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource=resource_info.area_limit;
+      break;
+    }
+    case MemoryResource:
+    {
+      resource=resource_info.memory_limit;
+      break;
+    }
+    case MapResource:
+    {
+      resource=resource_info.map_limit;
+      break;
+    }
+    case DiskResource:
+    {
+      resource=resource_info.disk_limit;
+      break;
+    }
+    case FileResource:
+    {
+      resource=resource_info.file_limit;
+      break;
+    }
+    case ThreadResource:
+    {
+      resource=resource_info.thread_limit;
+      break;
+    }
+    case TimeResource:
+    {
+      resource=resource_info.time_limit;
+      break;
+    }
+    default:
+      break;
+  }
+  UnlockSemaphoreInfo(resource_semaphore);
+  return(resource);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t M a g i c k R e s o u r c e I n f o                                %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListMagickResourceInfo() lists the resource info to a file.
+%
+%  The format of the ListMagickResourceInfo method is:
+%
+%      MagickBooleanType ListMagickResourceInfo(FILE *file,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
+  ExceptionInfo *magick_unused(exception))
+{
+  char
+    area_limit[MaxTextExtent],
+    disk_limit[MaxTextExtent],
+    map_limit[MaxTextExtent],
+    memory_limit[MaxTextExtent],
+    time_limit[MaxTextExtent];
+
+  if (file == (const FILE *) NULL)
+    file=stdout;
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  (void) FormatMagickSize(resource_info.area_limit,MagickFalse,area_limit);
+  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
+  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
+  (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
+  if (resource_info.disk_limit != MagickResourceInfinity)
+    (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,disk_limit);
+  (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
+  if (resource_info.time_limit != MagickResourceInfinity)
+    (void) FormatLocaleString(time_limit,MaxTextExtent,"%.20g",(double)
+      ((MagickOffsetType) resource_info.time_limit));
+  (void) FormatLocaleFile(file,"File         Area       Memory          Map"
+    "         Disk    Thread         Time\n");
+  (void) FormatLocaleFile(file,
+    "--------------------------------------------------------"
+    "-----------------------\n");
+  (void) FormatLocaleFile(file,"%4g   %10s   %10s   %10s   %10s    %6g  %11s\n",
+    (double) ((MagickOffsetType) resource_info.file_limit),area_limit,
+    memory_limit,map_limit,disk_limit,(double) ((MagickOffsetType)
+    resource_info.thread_limit),time_limit);
+  (void) fflush(file);
+  UnlockSemaphoreInfo(resource_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e l i n q u i s h M a g i c k R e s o u r c e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishMagickResource() relinquishes resources of the specified type.
+%
+%  The format of the RelinquishMagickResource() method is:
+%
+%      void RelinquishMagickResource(const ResourceType type,
+%        const MagickSizeType size)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type of resource.
+%
+%    o size: the size of the resource.
+%
+*/
+MagickExport void RelinquishMagickResource(const ResourceType type,
+  const MagickSizeType size)
+{
+  char
+    resource_current[MaxTextExtent],
+    resource_limit[MaxTextExtent],
+    resource_request[MaxTextExtent];
+
+  (void) FormatMagickSize(size,MagickFalse,resource_request);
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource_info.area=(MagickOffsetType) size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.area,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
+        resource_limit);
+      break;
+    }
+    case MemoryResource:
+    {
+      resource_info.memory-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.memory,
+        MagickTrue,resource_current);
+      (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
+        resource_limit);
+      break;
+    }
+    case MapResource:
+    {
+      resource_info.map-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.map,MagickTrue,
+        resource_current);
+      (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
+        resource_limit);
+      break;
+    }
+    case DiskResource:
+    {
+      resource_info.disk-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.disk,MagickTrue,
+        resource_current);
+      (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
+        resource_limit);
+      break;
+    }
+    case FileResource:
+    {
+      resource_info.file-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.file,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
+        MagickFalse,resource_limit);
+      break;
+    }
+    case ThreadResource:
+    {
+      resource_info.thread-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
+        MagickFalse,resource_limit);
+      break;
+    }
+    case TimeResource:
+    {
+      resource_info.time-=size;
+      (void) FormatMagickSize((MagickSizeType) resource_info.time,MagickFalse,
+        resource_current);
+      (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
+        MagickFalse,resource_limit);
+      break;
+    }
+    default:
+      break;
+  }
+  UnlockSemaphoreInfo(resource_semaphore);
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
+    CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
+      resource_request,resource_current,resource_limit);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%    R e l i n q u i s h U n i q u e F i l e R e s o u r c e                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishUniqueFileResource() relinquishes a unique file resource.
+%
+%  The format of the RelinquishUniqueFileResource() method is:
+%
+%      MagickBooleanType RelinquishUniqueFileResource(const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o name: the name of the temporary resource.
+%
+*/
+MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
+{
+  char
+    cache_path[MaxTextExtent];
+
+  assert(path != (const char *) NULL);
+  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
+  if (temporary_resources != (SplayTreeInfo *) NULL)
+    {
+      register char
+        *p;
+
+      ResetSplayTreeIterator(temporary_resources);
+      p=(char *) GetNextKeyInSplayTree(temporary_resources);
+      while (p != (char *) NULL)
+      {
+        if (LocaleCompare(p,path) == 0)
+          break;
+        p=(char *) GetNextKeyInSplayTree(temporary_resources);
+      }
+      if (p != (char *) NULL)
+        (void) DeleteNodeFromSplayTree(temporary_resources,p);
+    }
+  (void) CopyMagickString(cache_path,path,MaxTextExtent);
+  AppendImageFormat("cache",cache_path);
+  (void) remove(cache_path);
+  return(remove(path) == 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e s o u r c e C o m p o n e n t G e n e s i s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResourceComponentGenesis() instantiates the resource component.
+%
+%  The format of the ResourceComponentGenesis method is:
+%
+%      MagickBooleanType ResourceComponentGenesis(void)
+%
+*/
+
+static inline size_t MagickMax(const size_t x,const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline MagickSizeType StringToSizeType(const char *string,
+  const double interval)
+{
+  double
+    value;
+
+  value=SiPrefixToDouble(string,interval);
+  if (value >= (double) MagickULLConstant(~0))
+    return(MagickULLConstant(~0));
+  return((MagickSizeType) value);
+}
+
+MagickExport MagickBooleanType ResourceComponentGenesis(void)
+{
+  char
+    *limit;
+
+  MagickSizeType
+    memory;
+
+  ssize_t
+    files,
+    pages,
+    pagesize;
+
+  /*
+    Set Magick resource limits.
+  */
+  AcquireSemaphoreInfo(&resource_semaphore);
+  pagesize=GetMagickPageSize();
+  pages=(-1);
+#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
+  pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
+#endif
+  memory=(MagickSizeType) pages*pagesize;
+  if ((pagesize <= 0) || (pages <= 0))
+    memory=2048UL*1024UL*1024UL;
+#if defined(PixelCacheThreshold)
+  memory=PixelCacheThreshold;
+#endif
+  (void) SetMagickResourceLimit(AreaResource,2*memory/sizeof(PixelPacket));
+  (void) SetMagickResourceLimit(MemoryResource,memory);
+  (void) SetMagickResourceLimit(MapResource,2*memory);
+  limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("area");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
+      limit=DestroyString(limit);
+    }
+  limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("memory");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(MemoryResource,
+        StringToSizeType(limit,100.0));
+      limit=DestroyString(limit);
+    }
+  limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("map");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
+      limit=DestroyString(limit);
+    }
+  limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("disk");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
+      limit=DestroyString(limit);
+    }
+  files=(-1);
+#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
+  files=(ssize_t) sysconf(_SC_OPEN_MAX);
+#endif
+#if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
+  if (files < 0)
+    {
+      struct rlimit
+        resources;
+
+      if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
+        files=(ssize_t) resources.rlim_cur;
+  }
+#endif
+#if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
+  if (files < 0)
+    files=(ssize_t) getdtablesize();
+#endif
+  if (files < 0)
+    files=64;
+  (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
+    (3*files/4),64));
+  limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("file");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
+      limit=DestroyString(limit);
+    }
+  (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
+  limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("thread");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
+        100.0));
+      limit=DestroyString(limit);
+    }
+  limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
+  if (limit == (char *) NULL)
+    limit=GetPolicyValue("time");
+  if (limit != (char *) NULL)
+    {
+      (void) SetMagickResourceLimit(TimeResource,StringToSizeType(limit,100.0));
+      limit=DestroyString(limit);
+    }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   R e s o u r c e C o m p o n e n t T e r m i n u s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResourceComponentTerminus() destroys the resource component.
+%
+%  The format of the ResourceComponentTerminus() method is:
+%
+%      ResourceComponentTerminus(void)
+%
+*/
+MagickExport void ResourceComponentTerminus(void)
+{
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  if (temporary_resources != (SplayTreeInfo *) NULL)
+    temporary_resources=DestroySplayTree(temporary_resources);
+  if (random_info != (RandomInfo *) NULL)
+    random_info=DestroyRandomInfo(random_info);
+  UnlockSemaphoreInfo(resource_semaphore);
+  DestroySemaphoreInfo(&resource_semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t M a g i c k R e s o u r c e L i m i t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetMagickResourceLimit() sets the limit for a particular resource.
+%
+%  The format of the SetMagickResourceLimit() method is:
+%
+%      MagickBooleanType SetMagickResourceLimit(const ResourceType type,
+%        const MagickSizeType limit)
+%
+%  A description of each parameter follows:
+%
+%    o type: the type of resource.
+%
+%    o limit: the maximum limit for the resource.
+%
+*/
+
+static inline MagickSizeType MagickMin(const MagickSizeType x,
+  const MagickSizeType y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
+  const MagickSizeType limit)
+{
+  char
+    *value;
+
+  if (resource_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&resource_semaphore);
+  LockSemaphoreInfo(resource_semaphore);
+  switch (type)
+  {
+    case AreaResource:
+    {
+      resource_info.area_limit=limit;
+      value=GetPolicyValue("area");
+      if (value != (char *) NULL)
+        resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
+      break;
+    }
+    case MemoryResource:
+    {
+      resource_info.memory_limit=limit;
+      value=GetPolicyValue("memory");
+      if (value != (char *) NULL)
+        resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
+          100.0));
+      break;
+    }
+    case MapResource:
+    {
+      resource_info.map_limit=limit;
+      value=GetPolicyValue("map");
+      if (value != (char *) NULL)
+        resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
+      break;
+    }
+    case DiskResource:
+    {
+      resource_info.disk_limit=limit;
+      value=GetPolicyValue("disk");
+      if (value != (char *) NULL)
+        resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
+      break;
+    }
+    case FileResource:
+    {
+      resource_info.file_limit=limit;
+      value=GetPolicyValue("file");
+      if (value != (char *) NULL)
+        resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
+      break;
+    }
+    case ThreadResource:
+    {
+      resource_info.thread_limit=limit;
+      value=GetPolicyValue("thread");
+      if (value != (char *) NULL)
+        resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
+          100.0));
+      SetOpenMPMaximumThreads((int) resource_info.thread_limit);
+      break;
+    }
+    case TimeResource:
+    {
+      resource_info.time_limit=limit;
+      value=GetPolicyValue("time");
+      if (value != (char *) NULL)
+        resource_info.time_limit=MagickMin(limit,StringToSizeType(value,100.0));
+      break;
+    }
+    default:
+      break;
+  }
+  UnlockSemaphoreInfo(resource_semaphore);
+  return(MagickTrue);
+}
diff --git a/MagickCore/resource_.h b/MagickCore/resource_.h
new file mode 100644
index 0000000..7fd86e1
--- /dev/null
+++ b/MagickCore/resource_.h
@@ -0,0 +1,63 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore resource methods.
+*/
+#ifndef _MAGICKCORE_RESOURCE_H
+#define _MAGICKCORE_RESOURCE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedResource,
+  AreaResource,
+  DiskResource,
+  FileResource,
+  MapResource,
+  MemoryResource,
+  ThreadResource,
+  TimeResource,
+  ThrottleResource
+} ResourceType;
+
+#define MagickResourceInfinity  MagickULLConstant(~0)
+
+extern MagickExport int
+  AcquireUniqueFileResource(char *);
+
+extern MagickExport MagickBooleanType
+  AcquireMagickResource(const ResourceType,const MagickSizeType),
+  ListMagickResourceInfo(FILE *,ExceptionInfo *),
+  RelinquishUniqueFileResource(const char *),
+  ResourceComponentGenesis(void),
+  SetMagickResourceLimit(const ResourceType,const MagickSizeType);
+
+extern MagickExport MagickSizeType
+  GetMagickResource(const ResourceType),
+  GetMagickResourceLimit(const ResourceType);
+
+extern MagickExport void
+  AsynchronousResourceComponentTerminus(void),
+  RelinquishMagickResource(const ResourceType,const MagickSizeType),
+  ResourceComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/segment.c b/MagickCore/segment.c
new file mode 100644
index 0000000..e8dcc8d
--- /dev/null
+++ b/MagickCore/segment.c
@@ -0,0 +1,1924 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               SSSSS  EEEEE   GGGG  M   M  EEEEE  N   N  TTTTT               %
+%               SS     E      G      MM MM  E      NN  N    T                 %
+%                SSS   EEE    G GGG  M M M  EEE    N N N    T                 %
+%                  SS  E      G   G  M   M  E      N  NN    T                 %
+%               SSSSS  EEEEE   GGGG  M   M  EEEEE  N   N    T                 %
+%                                                                             %
+%                                                                             %
+%    MagickCore Methods to Segment an Image with Thresholding Fuzzy c-Means   %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                April 1993                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Segment segments an image by analyzing the histograms of the color
+%  components and identifying units that are homogeneous with the fuzzy
+%  c-means technique.  The scale-space filter analyzes the histograms of
+%  the three color components of the image and identifies a set of
+%  classes.  The extents of each class is used to coarsely segment the
+%  image with thresholding.  The color associated with each class is
+%  determined by the mean color of all pixels within the extents of a
+%  particular class.  Finally, any unclassified pixels are assigned to
+%  the closest class with the fuzzy c-means technique.
+%
+%  The fuzzy c-Means algorithm can be summarized as follows:
+%
+%    o Build a histogram, one for each color component of the image.
+%
+%    o For each histogram, successively apply the scale-space filter and
+%      build an interval tree of zero crossings in the second derivative
+%      at each scale.  Analyze this scale-space ``fingerprint'' to
+%      determine which peaks and valleys in the histogram are most
+%      predominant.
+%
+%    o The fingerprint defines intervals on the axis of the histogram.
+%      Each interval contains either a minima or a maxima in the original
+%      signal.  If each color component lies within the maxima interval,
+%      that pixel is considered ``classified'' and is assigned an unique
+%      class number.
+%
+%    o Any pixel that fails to be classified in the above thresholding
+%      pass is classified using the fuzzy c-Means technique.  It is
+%      assigned to one of the classes discovered in the histogram analysis
+%      phase.
+%
+%  The fuzzy c-Means technique attempts to cluster a pixel by finding
+%  the local minima of the generalized within group sum of squared error
+%  objective function.  A pixel is assigned to the closest class of
+%  which the fuzzy membership has a maximum value.
+%
+%  Segment is strongly based on software written by Andy Gallo,
+%  University of Delaware.
+%
+%  The following reference was used in creating this program:
+%
+%    Young Won Lim, Sang Uk Lee, "On The Color Image Segmentation
+%    Algorithm Based on the Thresholding and the Fuzzy c-Means
+%    Techniques", Pattern Recognition, Volume 23, Number 9, pages
+%    935-952, 1990.
+%
+%
+*/
+
+#include "MagickCore/studio.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/string_.h"
+
+/*
+  Define declarations.
+*/
+#define MaxDimension  3
+#define DeltaTau  0.5f
+#if defined(FastClassify)
+#define WeightingExponent  2.0
+#define SegmentPower(ratio) (ratio)
+#else
+#define WeightingExponent  2.5
+#define SegmentPower(ratio) pow(ratio,(double) (1.0/(weighting_exponent-1.0)));
+#endif
+#define Tau  5.2f
+
+/*
+  Typedef declarations.
+*/
+typedef struct _ExtentPacket
+{
+  MagickRealType
+    center;
+
+  ssize_t
+    index,
+    left,
+    right;
+} ExtentPacket;
+
+typedef struct _Cluster
+{
+  struct _Cluster
+    *next;
+
+  ExtentPacket
+    red,
+    green,
+    blue;
+
+  ssize_t
+    count,
+    id;
+} Cluster;
+
+typedef struct _IntervalTree
+{
+  MagickRealType
+    tau;
+
+  ssize_t
+    left,
+    right;
+
+  MagickRealType
+    mean_stability,
+    stability;
+
+  struct _IntervalTree
+    *sibling,
+    *child;
+} IntervalTree;
+
+typedef struct _ZeroCrossing
+{
+  MagickRealType
+    tau,
+    histogram[256];
+
+  short
+    crossings[256];
+} ZeroCrossing;
+
+/*
+  Constant declarations.
+*/
+static const int
+  Blue = 2,
+  Green = 1,
+  Red = 0,
+  SafeMargin = 3,
+  TreeLength = 600;
+
+/*
+  Method prototypes.
+*/
+static MagickRealType
+  OptimalTau(const ssize_t *,const double,const double,const double,
+    const double,short *);
+
+static ssize_t
+  DefineRegion(const short *,ExtentPacket *);
+
+static void
+  InitializeHistogram(const Image *,ssize_t **,ExceptionInfo *),
+  ScaleSpace(const ssize_t *,const MagickRealType,MagickRealType *),
+  ZeroCrossHistogram(MagickRealType *,const MagickRealType,short *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C l a s s i f y                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Classify() defines one or more classes.  Each pixel is thresholded to
+%  determine which class it belongs to.  If the class is not identified it is
+%  assigned to the closest class based on the fuzzy c-Means technique.
+%
+%  The format of the Classify method is:
+%
+%      MagickBooleanType Classify(Image *image,short **extrema,
+%        const MagickRealType cluster_threshold,
+%        const MagickRealType weighting_exponent,
+%        const MagickBooleanType verbose)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o extrema:  Specifies a pointer to an array of integers.  They
+%      represent the peaks and valleys of the histogram for each color
+%      component.
+%
+%    o cluster_threshold:  This MagickRealType represents the minimum number of
+%      pixels contained in a hexahedra before it can be considered valid
+%      (expressed as a percentage).
+%
+%    o weighting_exponent: Specifies the membership weighting exponent.
+%
+%    o verbose:  A value greater than zero prints detailed information about
+%      the identified classes.
+%
+*/
+static MagickBooleanType Classify(Image *image,short **extrema,
+  const MagickRealType cluster_threshold,
+  const MagickRealType weighting_exponent,const MagickBooleanType verbose)
+{
+#define SegmentImageTag  "Segment/Image"
+
+  CacheView
+    *image_view;
+
+  Cluster
+    *cluster,
+    *head,
+    *last_cluster,
+    *next_cluster;
+
+  ExceptionInfo
+    *exception;
+
+  ExtentPacket
+    blue,
+    green,
+    red;
+
+  MagickOffsetType
+    progress;
+
+  MagickRealType
+    *free_squares;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  register MagickRealType
+    *squares;
+
+  size_t
+    number_clusters;
+
+  ssize_t
+    count,
+    y;
+
+  /*
+    Form clusters.
+  */
+  cluster=(Cluster *) NULL;
+  head=(Cluster *) NULL;
+  (void) ResetMagickMemory(&red,0,sizeof(red));
+  (void) ResetMagickMemory(&green,0,sizeof(green));
+  (void) ResetMagickMemory(&blue,0,sizeof(blue));
+  while (DefineRegion(extrema[Red],&red) != 0)
+  {
+    green.index=0;
+    while (DefineRegion(extrema[Green],&green) != 0)
+    {
+      blue.index=0;
+      while (DefineRegion(extrema[Blue],&blue) != 0)
+      {
+        /*
+          Allocate a new class.
+        */
+        if (head != (Cluster *) NULL)
+          {
+            cluster->next=(Cluster *) AcquireMagickMemory(
+              sizeof(*cluster->next));
+            cluster=cluster->next;
+          }
+        else
+          {
+            cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
+            head=cluster;
+          }
+        if (cluster == (Cluster *) NULL)
+          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+            image->filename);
+        /*
+          Initialize a new class.
+        */
+        cluster->count=0;
+        cluster->red=red;
+        cluster->green=green;
+        cluster->blue=blue;
+        cluster->next=(Cluster *) NULL;
+      }
+    }
+  }
+  if (head == (Cluster *) NULL)
+    {
+      /*
+        No classes were identified-- create one.
+      */
+      cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
+      if (cluster == (Cluster *) NULL)
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename);
+      /*
+        Initialize a new class.
+      */
+      cluster->count=0;
+      cluster->red=red;
+      cluster->green=green;
+      cluster->blue=blue;
+      cluster->next=(Cluster *) NULL;
+      head=cluster;
+    }
+  /*
+    Count the pixels for each cluster.
+  */
+  status=MagickTrue;
+  count=0;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *p;
+
+    register ssize_t
+      x;
+
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+        if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) >=
+             (cluster->red.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) <=
+             (cluster->red.right+SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) >=
+             (cluster->green.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) <=
+             (cluster->green.right+SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) >=
+             (cluster->blue.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) <=
+             (cluster->blue.right+SafeMargin)))
+          {
+            /*
+              Count this pixel.
+            */
+            count++;
+            cluster->red.center+=(MagickRealType) ScaleQuantumToChar(
+              GetPixelRed(image,p));
+            cluster->green.center+=(MagickRealType) ScaleQuantumToChar(
+              GetPixelGreen(image,p));
+            cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(
+              GetPixelBlue(image,p));
+            cluster->count++;
+            break;
+          }
+      p+=GetPixelChannels(image);
+    }
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_Classify)
+#endif
+        proceed=SetImageProgress(image,SegmentImageTag,progress++,
+          2*image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  /*
+    Remove clusters that do not meet minimum cluster threshold.
+  */
+  count=0;
+  last_cluster=head;
+  next_cluster=head;
+  for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
+  {
+    next_cluster=cluster->next;
+    if ((cluster->count > 0) &&
+        (cluster->count >= (count*cluster_threshold/100.0)))
+      {
+        /*
+          Initialize cluster.
+        */
+        cluster->id=count;
+        cluster->red.center/=cluster->count;
+        cluster->green.center/=cluster->count;
+        cluster->blue.center/=cluster->count;
+        count++;
+        last_cluster=cluster;
+        continue;
+      }
+    /*
+      Delete cluster.
+    */
+    if (cluster == head)
+      head=next_cluster;
+    else
+      last_cluster->next=next_cluster;
+    cluster=(Cluster *) RelinquishMagickMemory(cluster);
+  }
+  number_clusters=(size_t) count;
+  if (verbose != MagickFalse)
+    {
+      /*
+        Print cluster statistics.
+      */
+      (void) FormatLocaleFile(stdout,"Fuzzy C-means Statistics\n");
+      (void) FormatLocaleFile(stdout,"===================\n\n");
+      (void) FormatLocaleFile(stdout,"\tCluster Threshold = %g\n",(double)
+        cluster_threshold);
+      (void) FormatLocaleFile(stdout,"\tWeighting Exponent = %g\n",(double)
+        weighting_exponent);
+      (void) FormatLocaleFile(stdout,"\tTotal Number of Clusters = %.20g\n\n",
+        (double) number_clusters);
+      /*
+        Print the total number of points per cluster.
+      */
+      (void) FormatLocaleFile(stdout,"\n\nNumber of Vectors Per Cluster\n");
+      (void) FormatLocaleFile(stdout,"=============================\n\n");
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+        (void) FormatLocaleFile(stdout,"Cluster #%.20g = %.20g\n",(double)
+          cluster->id,(double) cluster->count);
+      /*
+        Print the cluster extents.
+      */
+      (void) FormatLocaleFile(stdout,
+        "\n\n\nCluster Extents:        (Vector Size: %d)\n",MaxDimension);
+      (void) FormatLocaleFile(stdout,"================");
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+      {
+        (void) FormatLocaleFile(stdout,"\n\nCluster #%.20g\n\n",(double)
+          cluster->id);
+        (void) FormatLocaleFile(stdout,
+          "%.20g-%.20g  %.20g-%.20g  %.20g-%.20g\n",(double)
+          cluster->red.left,(double) cluster->red.right,(double)
+          cluster->green.left,(double) cluster->green.right,(double)
+          cluster->blue.left,(double) cluster->blue.right);
+      }
+      /*
+        Print the cluster center values.
+      */
+      (void) FormatLocaleFile(stdout,
+        "\n\n\nCluster Center Values:        (Vector Size: %d)\n",MaxDimension);
+      (void) FormatLocaleFile(stdout,"=====================");
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+      {
+        (void) FormatLocaleFile(stdout,"\n\nCluster #%.20g\n\n",(double)
+          cluster->id);
+        (void) FormatLocaleFile(stdout,"%g  %g  %g\n",(double)
+          cluster->red.center,(double) cluster->green.center,(double)
+          cluster->blue.center);
+      }
+      (void) FormatLocaleFile(stdout,"\n");
+    }
+  if (number_clusters > 256)
+    ThrowBinaryException(ImageError,"TooManyClusters",image->filename);
+  /*
+    Speed up distance calculations.
+  */
+  squares=(MagickRealType *) AcquireQuantumMemory(513UL,sizeof(*squares));
+  if (squares == (MagickRealType *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  squares+=255;
+  for (i=(-255); i <= 255; i++)
+    squares[i]=(MagickRealType) i*(MagickRealType) i;
+  /*
+    Allocate image colormap.
+  */
+  if (AcquireImageColormap(image,number_clusters) == MagickFalse)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  i=0;
+  for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+  {
+    image->colormap[i].red=ScaleCharToQuantum((unsigned char)
+      (cluster->red.center+0.5));
+    image->colormap[i].green=ScaleCharToQuantum((unsigned char)
+      (cluster->green.center+0.5));
+    image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
+      (cluster->blue.center+0.5));
+    i++;
+  }
+  /*
+    Do course grain classes.
+  */
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    Cluster
+      *cluster;
+
+    register const PixelPacket
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelIndex(image,0,q);
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+      {
+        if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,q)) >=
+             (cluster->red.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,q)) <=
+             (cluster->red.right+SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q)) >=
+             (cluster->green.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q)) <=
+             (cluster->green.right+SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q)) >=
+             (cluster->blue.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q)) <=
+             (cluster->blue.right+SafeMargin)))
+          {
+            /*
+              Classify this pixel.
+            */
+            SetPixelIndex(image,(Quantum) cluster->id,q);
+            break;
+          }
+      }
+      if (cluster == (Cluster *) NULL)
+        {
+          MagickRealType
+            distance_squared,
+            local_minima,
+            numerator,
+            ratio,
+            sum;
+
+          register ssize_t
+            j,
+            k;
+
+          /*
+            Compute fuzzy membership.
+          */
+          local_minima=0.0;
+          for (j=0; j < (ssize_t) image->colors; j++)
+          {
+            sum=0.0;
+            p=image->colormap+j;
+            distance_squared=squares[(ssize_t) ScaleQuantumToChar(
+              GetPixelRed(image,q))-(ssize_t)
+              ScaleQuantumToChar(p->red)]+squares[(ssize_t)
+              ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
+              ScaleQuantumToChar(p->green)]+squares[(ssize_t)
+              ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
+              ScaleQuantumToChar(p->blue)];
+            numerator=distance_squared;
+            for (k=0; k < (ssize_t) image->colors; k++)
+            {
+              p=image->colormap+k;
+                distance_squared=squares[(ssize_t) ScaleQuantumToChar(
+                  GetPixelRed(image,q))-(ssize_t)
+                  ScaleQuantumToChar(p->red)]+squares[(ssize_t)
+                  ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
+                  ScaleQuantumToChar(p->green)]+squares[(ssize_t)
+                  ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
+                  ScaleQuantumToChar(p->blue)];
+              ratio=numerator/distance_squared;
+              sum+=SegmentPower(ratio);
+            }
+            if ((sum != 0.0) && ((1.0/sum) > local_minima))
+              {
+                /*
+                  Classify this pixel.
+                */
+                local_minima=1.0/sum;
+                SetPixelIndex(image,(Quantum) j,q);
+              }
+          }
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_Classify)
+#endif
+        proceed=SetImageProgress(image,SegmentImageTag,progress++,
+          2*image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  status&=SyncImage(image);
+  /*
+    Relinquish resources.
+  */
+  for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
+  {
+    next_cluster=cluster->next;
+    cluster=(Cluster *) RelinquishMagickMemory(cluster);
+  }
+  squares-=255;
+  free_squares=squares;
+  free_squares=(MagickRealType *) RelinquishMagickMemory(free_squares);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C o n s o l i d a t e C r o s s i n g s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConsolidateCrossings() guarantees that an even number of zero crossings
+%  always lie between two crossings.
+%
+%  The format of the ConsolidateCrossings method is:
+%
+%      ConsolidateCrossings(ZeroCrossing *zero_crossing,
+%        const size_t number_crossings)
+%
+%  A description of each parameter follows.
+%
+%    o zero_crossing: Specifies an array of structures of type ZeroCrossing.
+%
+%    o number_crossings: This size_t specifies the number of elements
+%      in the zero_crossing array.
+%
+*/
+
+static inline ssize_t MagickAbsoluteValue(const ssize_t x)
+{
+  if (x < 0)
+    return(-x);
+  return(x);
+}
+
+static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static void ConsolidateCrossings(ZeroCrossing *zero_crossing,
+  const size_t number_crossings)
+{
+  register ssize_t
+    i,
+    j,
+    k,
+    l;
+
+  ssize_t
+    center,
+    correct,
+    count,
+    left,
+    right;
+
+  /*
+    Consolidate zero crossings.
+  */
+  for (i=(ssize_t) number_crossings-1; i >= 0; i--)
+    for (j=0; j <= 255; j++)
+    {
+      if (zero_crossing[i].crossings[j] == 0)
+        continue;
+      /*
+        Find the entry that is closest to j and still preserves the
+        property that there are an even number of crossings between
+        intervals.
+      */
+      for (k=j-1; k > 0; k--)
+        if (zero_crossing[i+1].crossings[k] != 0)
+          break;
+      left=MagickMax(k,0);
+      center=j;
+      for (k=j+1; k < 255; k++)
+        if (zero_crossing[i+1].crossings[k] != 0)
+          break;
+      right=MagickMin(k,255);
+      /*
+        K is the zero crossing just left of j.
+      */
+      for (k=j-1; k > 0; k--)
+        if (zero_crossing[i].crossings[k] != 0)
+          break;
+      if (k < 0)
+        k=0;
+      /*
+        Check center for an even number of crossings between k and j.
+      */
+      correct=(-1);
+      if (zero_crossing[i+1].crossings[j] != 0)
+        {
+          count=0;
+          for (l=k+1; l < center; l++)
+            if (zero_crossing[i+1].crossings[l] != 0)
+              count++;
+          if (((count % 2) == 0) && (center != k))
+            correct=center;
+        }
+      /*
+        Check left for an even number of crossings between k and j.
+      */
+      if (correct == -1)
+        {
+          count=0;
+          for (l=k+1; l < left; l++)
+            if (zero_crossing[i+1].crossings[l] != 0)
+              count++;
+          if (((count % 2) == 0) && (left != k))
+            correct=left;
+        }
+      /*
+        Check right for an even number of crossings between k and j.
+      */
+      if (correct == -1)
+        {
+          count=0;
+          for (l=k+1; l < right; l++)
+            if (zero_crossing[i+1].crossings[l] != 0)
+              count++;
+          if (((count % 2) == 0) && (right != k))
+            correct=right;
+        }
+      l=(ssize_t) zero_crossing[i].crossings[j];
+      zero_crossing[i].crossings[j]=0;
+      if (correct != -1)
+        zero_crossing[i].crossings[correct]=(short) l;
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e f i n e R e g i o n                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DefineRegion() defines the left and right boundaries of a peak region.
+%
+%  The format of the DefineRegion method is:
+%
+%      ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
+%
+%  A description of each parameter follows.
+%
+%    o extrema:  Specifies a pointer to an array of integers.  They
+%      represent the peaks and valleys of the histogram for each color
+%      component.
+%
+%    o extents:  This pointer to an ExtentPacket represent the extends
+%      of a particular peak or valley of a color component.
+%
+*/
+static ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
+{
+  /*
+    Initialize to default values.
+  */
+  extents->left=0;
+  extents->center=0.0;
+  extents->right=255;
+  /*
+    Find the left side (maxima).
+  */
+  for ( ; extents->index <= 255; extents->index++)
+    if (extrema[extents->index] > 0)
+      break;
+  if (extents->index > 255)
+    return(MagickFalse);  /* no left side - no region exists */
+  extents->left=extents->index;
+  /*
+    Find the right side (minima).
+  */
+  for ( ; extents->index <= 255; extents->index++)
+    if (extrema[extents->index] < 0)
+      break;
+  extents->right=extents->index-1;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e r i v a t i v e H i s t o g r a m                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DerivativeHistogram() determines the derivative of the histogram using
+%  central differencing.
+%
+%  The format of the DerivativeHistogram method is:
+%
+%      DerivativeHistogram(const MagickRealType *histogram,
+%        MagickRealType *derivative)
+%
+%  A description of each parameter follows.
+%
+%    o histogram: Specifies an array of MagickRealTypes representing the number
+%      of pixels for each intensity of a particular color component.
+%
+%    o derivative: This array of MagickRealTypes is initialized by
+%      DerivativeHistogram to the derivative of the histogram using central
+%      differencing.
+%
+*/
+static void DerivativeHistogram(const MagickRealType *histogram,
+  MagickRealType *derivative)
+{
+  register ssize_t
+    i,
+    n;
+
+  /*
+    Compute endpoints using second order polynomial interpolation.
+  */
+  n=255;
+  derivative[0]=(-1.5*histogram[0]+2.0*histogram[1]-0.5*histogram[2]);
+  derivative[n]=(0.5*histogram[n-2]-2.0*histogram[n-1]+1.5*histogram[n]);
+  /*
+    Compute derivative using central differencing.
+  */
+  for (i=1; i < n; i++)
+    derivative[i]=(histogram[i+1]-histogram[i-1])/2.0;
+  return;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  G e t I m a g e D y n a m i c T h r e s h o l d                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageDynamicThreshold() returns the dynamic threshold for an image.
+%
+%  The format of the GetImageDynamicThreshold method is:
+%
+%      MagickBooleanType GetImageDynamicThreshold(const Image *image,
+%        const double cluster_threshold,const double smooth_threshold,
+%        PixelInfo *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o cluster_threshold:  This MagickRealType represents the minimum number of
+%      pixels contained in a hexahedra before it can be considered valid
+%      (expressed as a percentage).
+%
+%    o smooth_threshold: the smoothing threshold eliminates noise in the second
+%      derivative of the histogram.  As the value is increased, you can expect a
+%      smoother second derivative.
+%
+%    o pixel: return the dynamic threshold here.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
+  const double cluster_threshold,const double smooth_threshold,
+  PixelInfo *pixel,ExceptionInfo *exception)
+{
+  Cluster
+    *background,
+    *cluster,
+    *object,
+    *head,
+    *last_cluster,
+    *next_cluster;
+
+  ExtentPacket
+    blue,
+    green,
+    red;
+
+  MagickBooleanType
+    proceed;
+
+  MagickRealType
+    threshold;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  short
+    *extrema[MaxDimension];
+
+  ssize_t
+    count,
+    *histogram[MaxDimension],
+    y;
+
+  /*
+    Allocate histogram and extrema.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  GetPixelInfo(image,pixel);
+  for (i=0; i < MaxDimension; i++)
+  {
+    histogram[i]=(ssize_t *) AcquireQuantumMemory(256UL,sizeof(**histogram));
+    extrema[i]=(short *) AcquireQuantumMemory(256UL,sizeof(**histogram));
+    if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (short *) NULL))
+      {
+        for (i-- ; i >= 0; i--)
+        {
+          extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
+          histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
+        }
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+        return(MagickFalse);
+      }
+  }
+  /*
+    Initialize histogram.
+  */
+  InitializeHistogram(image,histogram,exception);
+  (void) OptimalTau(histogram[Red],Tau,0.2f,DeltaTau,
+    (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Red]);
+  (void) OptimalTau(histogram[Green],Tau,0.2f,DeltaTau,
+    (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Green]);
+  (void) OptimalTau(histogram[Blue],Tau,0.2f,DeltaTau,
+    (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Blue]);
+  /*
+    Form clusters.
+  */
+  cluster=(Cluster *) NULL;
+  head=(Cluster *) NULL;
+  (void) ResetMagickMemory(&red,0,sizeof(red));
+  (void) ResetMagickMemory(&green,0,sizeof(green));
+  (void) ResetMagickMemory(&blue,0,sizeof(blue));
+  while (DefineRegion(extrema[Red],&red) != 0)
+  {
+    green.index=0;
+    while (DefineRegion(extrema[Green],&green) != 0)
+    {
+      blue.index=0;
+      while (DefineRegion(extrema[Blue],&blue) != 0)
+      {
+        /*
+          Allocate a new class.
+        */
+        if (head != (Cluster *) NULL)
+          {
+            cluster->next=(Cluster *) AcquireMagickMemory(
+              sizeof(*cluster->next));
+            cluster=cluster->next;
+          }
+        else
+          {
+            cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
+            head=cluster;
+          }
+        if (cluster == (Cluster *) NULL)
+          {
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              ResourceLimitError,"MemoryAllocationFailed","`%s'",
+              image->filename);
+            return(MagickFalse);
+          }
+        /*
+          Initialize a new class.
+        */
+        cluster->count=0;
+        cluster->red=red;
+        cluster->green=green;
+        cluster->blue=blue;
+        cluster->next=(Cluster *) NULL;
+      }
+    }
+  }
+  if (head == (Cluster *) NULL)
+    {
+      /*
+        No classes were identified-- create one.
+      */
+      cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
+      if (cluster == (Cluster *) NULL)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+          return(MagickFalse);
+        }
+      /*
+        Initialize a new class.
+      */
+      cluster->count=0;
+      cluster->red=red;
+      cluster->green=green;
+      cluster->blue=blue;
+      cluster->next=(Cluster *) NULL;
+      head=cluster;
+    }
+  /*
+    Count the pixels for each cluster.
+  */
+  count=0;
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
+        if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) >=
+             (cluster->red.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) <=
+             (cluster->red.right+SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) >=
+             (cluster->green.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) <=
+             (cluster->green.right+SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) >=
+             (cluster->blue.left-SafeMargin)) &&
+            ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) <=
+             (cluster->blue.right+SafeMargin)))
+          {
+            /*
+              Count this pixel.
+            */
+            count++;
+            cluster->red.center+=(MagickRealType) ScaleQuantumToChar(
+              GetPixelRed(image,p));
+            cluster->green.center+=(MagickRealType) ScaleQuantumToChar(
+              GetPixelGreen(image,p));
+            cluster->blue.center+=(MagickRealType) ScaleQuantumToChar(
+              GetPixelBlue(image,p));
+            cluster->count++;
+            break;
+          }
+      p+=GetPixelChannels(image);
+    }
+    proceed=SetImageProgress(image,SegmentImageTag,(MagickOffsetType) y,
+      2*image->rows);
+    if (proceed == MagickFalse)
+      break;
+  }
+  /*
+    Remove clusters that do not meet minimum cluster threshold.
+  */
+  count=0;
+  last_cluster=head;
+  next_cluster=head;
+  for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
+  {
+    next_cluster=cluster->next;
+    if ((cluster->count > 0) &&
+        (cluster->count >= (count*cluster_threshold/100.0)))
+      {
+        /*
+          Initialize cluster.
+        */
+        cluster->id=count;
+        cluster->red.center/=cluster->count;
+        cluster->green.center/=cluster->count;
+        cluster->blue.center/=cluster->count;
+        count++;
+        last_cluster=cluster;
+        continue;
+      }
+    /*
+      Delete cluster.
+    */
+    if (cluster == head)
+      head=next_cluster;
+    else
+      last_cluster->next=next_cluster;
+    cluster=(Cluster *) RelinquishMagickMemory(cluster);
+  }
+  object=head;
+  background=head;
+  if (count > 1)
+    {
+      object=head->next;
+      for (cluster=object; cluster->next != (Cluster *) NULL; )
+      {
+        if (cluster->count < object->count)
+          object=cluster;
+        cluster=cluster->next;
+      }
+      background=head->next;
+      for (cluster=background; cluster->next != (Cluster *) NULL; )
+      {
+        if (cluster->count > background->count)
+          background=cluster;
+        cluster=cluster->next;
+      }
+    }
+  threshold=(background->red.center+object->red.center)/2.0;
+  pixel->red=(MagickRealType) ScaleCharToQuantum((unsigned char)
+    (threshold+0.5));
+  threshold=(background->green.center+object->green.center)/2.0;
+  pixel->green=(MagickRealType) ScaleCharToQuantum((unsigned char)
+    (threshold+0.5));
+  threshold=(background->blue.center+object->blue.center)/2.0;
+  pixel->blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
+    (threshold+0.5));
+  /*
+    Relinquish resources.
+  */
+  for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
+  {
+    next_cluster=cluster->next;
+    cluster=(Cluster *) RelinquishMagickMemory(cluster);
+  }
+  for (i=0; i < MaxDimension; i++)
+  {
+    extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
+    histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  I n i t i a l i z e H i s t o g r a m                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeHistogram() computes the histogram for an image.
+%
+%  The format of the InitializeHistogram method is:
+%
+%      InitializeHistogram(const Image *image,ssize_t **histogram)
+%
+%  A description of each parameter follows.
+%
+%    o image: Specifies a pointer to an Image structure;  returned from
+%      ReadImage.
+%
+%    o histogram: Specifies an array of integers representing the number
+%      of pixels for each intensity of a particular color component.
+%
+*/
+static void InitializeHistogram(const Image *image,ssize_t **histogram,
+  ExceptionInfo *exception)
+{
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize histogram.
+  */
+  for (i=0; i <= 255; i++)
+  {
+    histogram[Red][i]=0;
+    histogram[Green][i]=0;
+    histogram[Blue][i]=0;
+  }
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      histogram[Red][(ssize_t) ScaleQuantumToChar(GetPixelRed(image,p))]++;
+      histogram[Green][(ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p))]++;
+      histogram[Blue][(ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p))]++;
+      p+=GetPixelChannels(image);
+    }
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e I n t e r v a l T r e e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeIntervalTree() initializes an interval tree from the lists of
+%  zero crossings.
+%
+%  The format of the InitializeIntervalTree method is:
+%
+%      InitializeIntervalTree(IntervalTree **list,ssize_t *number_nodes,
+%        IntervalTree *node)
+%
+%  A description of each parameter follows.
+%
+%    o zero_crossing: Specifies an array of structures of type ZeroCrossing.
+%
+%    o number_crossings: This size_t specifies the number of elements
+%      in the zero_crossing array.
+%
+*/
+
+static void InitializeList(IntervalTree **list,ssize_t *number_nodes,
+  IntervalTree *node)
+{
+  if (node == (IntervalTree *) NULL)
+    return;
+  if (node->child == (IntervalTree *) NULL)
+    list[(*number_nodes)++]=node;
+  InitializeList(list,number_nodes,node->sibling);
+  InitializeList(list,number_nodes,node->child);
+}
+
+static void MeanStability(IntervalTree *node)
+{
+  register IntervalTree
+    *child;
+
+  if (node == (IntervalTree *) NULL)
+    return;
+  node->mean_stability=0.0;
+  child=node->child;
+  if (child != (IntervalTree *) NULL)
+    {
+      register ssize_t
+        count;
+
+      register MagickRealType
+        sum;
+
+      sum=0.0;
+      count=0;
+      for ( ; child != (IntervalTree *) NULL; child=child->sibling)
+      {
+        sum+=child->stability;
+        count++;
+      }
+      node->mean_stability=sum/(MagickRealType) count;
+    }
+  MeanStability(node->sibling);
+  MeanStability(node->child);
+}
+
+static void Stability(IntervalTree *node)
+{
+  if (node == (IntervalTree *) NULL)
+    return;
+  if (node->child == (IntervalTree *) NULL)
+    node->stability=0.0;
+  else
+    node->stability=node->tau-(node->child)->tau;
+  Stability(node->sibling);
+  Stability(node->child);
+}
+
+static IntervalTree *InitializeIntervalTree(const ZeroCrossing *zero_crossing,
+  const size_t number_crossings)
+{
+  IntervalTree
+    *head,
+    **list,
+    *node,
+    *root;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j,
+    k,
+    left,
+    number_nodes;
+
+  /*
+    Allocate interval tree.
+  */
+  list=(IntervalTree **) AcquireQuantumMemory((size_t) TreeLength,
+    sizeof(*list));
+  if (list == (IntervalTree **) NULL)
+    return((IntervalTree *) NULL);
+  /*
+    The root is the entire histogram.
+  */
+  root=(IntervalTree *) AcquireMagickMemory(sizeof(*root));
+  root->child=(IntervalTree *) NULL;
+  root->sibling=(IntervalTree *) NULL;
+  root->tau=0.0;
+  root->left=0;
+  root->right=255;
+  for (i=(-1); i < (ssize_t) number_crossings; i++)
+  {
+    /*
+      Initialize list with all nodes with no children.
+    */
+    number_nodes=0;
+    InitializeList(list,&number_nodes,root);
+    /*
+      Split list.
+    */
+    for (j=0; j < number_nodes; j++)
+    {
+      head=list[j];
+      left=head->left;
+      node=head;
+      for (k=head->left+1; k < head->right; k++)
+      {
+        if (zero_crossing[i+1].crossings[k] != 0)
+          {
+            if (node == head)
+              {
+                node->child=(IntervalTree *) AcquireMagickMemory(
+                  sizeof(*node->child));
+                node=node->child;
+              }
+            else
+              {
+                node->sibling=(IntervalTree *) AcquireMagickMemory(
+                  sizeof(*node->sibling));
+                node=node->sibling;
+              }
+            node->tau=zero_crossing[i+1].tau;
+            node->child=(IntervalTree *) NULL;
+            node->sibling=(IntervalTree *) NULL;
+            node->left=left;
+            node->right=k;
+            left=k;
+          }
+        }
+      if (left != head->left)
+        {
+          node->sibling=(IntervalTree *) AcquireMagickMemory(
+            sizeof(*node->sibling));
+          node=node->sibling;
+          node->tau=zero_crossing[i+1].tau;
+          node->child=(IntervalTree *) NULL;
+          node->sibling=(IntervalTree *) NULL;
+          node->left=left;
+          node->right=head->right;
+        }
+    }
+  }
+  /*
+    Determine the stability: difference between a nodes tau and its child.
+  */
+  Stability(root->child);
+  MeanStability(root->child);
+  list=(IntervalTree **) RelinquishMagickMemory(list);
+  return(root);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   O p t i m a l T a u                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OptimalTau() finds the optimal tau for each band of the histogram.
+%
+%  The format of the OptimalTau method is:
+%
+%    MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
+%      const double min_tau,const double delta_tau,
+%      const double smooth_threshold,short *extrema)
+%
+%  A description of each parameter follows.
+%
+%    o histogram: Specifies an array of integers representing the number
+%      of pixels for each intensity of a particular color component.
+%
+%    o extrema:  Specifies a pointer to an array of integers.  They
+%      represent the peaks and valleys of the histogram for each color
+%      component.
+%
+*/
+
+static void ActiveNodes(IntervalTree **list,ssize_t *number_nodes,
+  IntervalTree *node)
+{
+  if (node == (IntervalTree *) NULL)
+    return;
+  if (node->stability >= node->mean_stability)
+    {
+      list[(*number_nodes)++]=node;
+      ActiveNodes(list,number_nodes,node->sibling);
+    }
+  else
+    {
+      ActiveNodes(list,number_nodes,node->sibling);
+      ActiveNodes(list,number_nodes,node->child);
+    }
+}
+
+static void FreeNodes(IntervalTree *node)
+{
+  if (node == (IntervalTree *) NULL)
+    return;
+  FreeNodes(node->sibling);
+  FreeNodes(node->child);
+  node=(IntervalTree *) RelinquishMagickMemory(node);
+}
+
+static MagickRealType OptimalTau(const ssize_t *histogram,const double max_tau,
+  const double min_tau,const double delta_tau,const double smooth_threshold,
+  short *extrema)
+{
+  IntervalTree
+    **list,
+    *node,
+    *root;
+
+  MagickBooleanType
+    peak;
+
+  MagickRealType
+    average_tau,
+    *derivative,
+    *second_derivative,
+    tau,
+    value;
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    count,
+    number_crossings;
+
+  ssize_t
+    index,
+    j,
+    k,
+    number_nodes;
+
+  ZeroCrossing
+    *zero_crossing;
+
+  /*
+    Allocate interval tree.
+  */
+  list=(IntervalTree **) AcquireQuantumMemory((size_t) TreeLength,
+    sizeof(*list));
+  if (list == (IntervalTree **) NULL)
+    return(0.0);
+  /*
+    Allocate zero crossing list.
+  */
+  count=(size_t) ((max_tau-min_tau)/delta_tau)+2;
+  zero_crossing=(ZeroCrossing *) AcquireQuantumMemory((size_t) count,
+    sizeof(*zero_crossing));
+  if (zero_crossing == (ZeroCrossing *) NULL)
+    return(0.0);
+  for (i=0; i < (ssize_t) count; i++)
+    zero_crossing[i].tau=(-1.0);
+  /*
+    Initialize zero crossing list.
+  */
+  derivative=(MagickRealType *) AcquireQuantumMemory(256,sizeof(*derivative));
+  second_derivative=(MagickRealType *) AcquireQuantumMemory(256,
+    sizeof(*second_derivative));
+  if ((derivative == (MagickRealType *) NULL) ||
+      (second_derivative == (MagickRealType *) NULL))
+    ThrowFatalException(ResourceLimitFatalError,
+      "UnableToAllocateDerivatives");
+  i=0;
+  for (tau=max_tau; tau >= min_tau; tau-=delta_tau)
+  {
+    zero_crossing[i].tau=tau;
+    ScaleSpace(histogram,tau,zero_crossing[i].histogram);
+    DerivativeHistogram(zero_crossing[i].histogram,derivative);
+    DerivativeHistogram(derivative,second_derivative);
+    ZeroCrossHistogram(second_derivative,smooth_threshold,
+      zero_crossing[i].crossings);
+    i++;
+  }
+  /*
+    Add an entry for the original histogram.
+  */
+  zero_crossing[i].tau=0.0;
+  for (j=0; j <= 255; j++)
+    zero_crossing[i].histogram[j]=(MagickRealType) histogram[j];
+  DerivativeHistogram(zero_crossing[i].histogram,derivative);
+  DerivativeHistogram(derivative,second_derivative);
+  ZeroCrossHistogram(second_derivative,smooth_threshold,
+    zero_crossing[i].crossings);
+  number_crossings=(size_t) i;
+  derivative=(MagickRealType *) RelinquishMagickMemory(derivative);
+  second_derivative=(MagickRealType *)
+    RelinquishMagickMemory(second_derivative);
+  /*
+    Ensure the scale-space fingerprints form lines in scale-space, not loops.
+  */
+  ConsolidateCrossings(zero_crossing,number_crossings);
+  /*
+    Force endpoints to be included in the interval.
+  */
+  for (i=0; i <= (ssize_t) number_crossings; i++)
+  {
+    for (j=0; j < 255; j++)
+      if (zero_crossing[i].crossings[j] != 0)
+        break;
+    zero_crossing[i].crossings[0]=(-zero_crossing[i].crossings[j]);
+    for (j=255; j > 0; j--)
+      if (zero_crossing[i].crossings[j] != 0)
+        break;
+    zero_crossing[i].crossings[255]=(-zero_crossing[i].crossings[j]);
+  }
+  /*
+    Initialize interval tree.
+  */
+  root=InitializeIntervalTree(zero_crossing,number_crossings);
+  if (root == (IntervalTree *) NULL)
+    return(0.0);
+  /*
+    Find active nodes:  stability is greater (or equal) to the mean stability of
+    its children.
+  */
+  number_nodes=0;
+  ActiveNodes(list,&number_nodes,root->child);
+  /*
+    Initialize extrema.
+  */
+  for (i=0; i <= 255; i++)
+    extrema[i]=0;
+  for (i=0; i < number_nodes; i++)
+  {
+    /*
+      Find this tau in zero crossings list.
+    */
+    k=0;
+    node=list[i];
+    for (j=0; j <= (ssize_t) number_crossings; j++)
+      if (zero_crossing[j].tau == node->tau)
+        k=j;
+    /*
+      Find the value of the peak.
+    */
+    peak=zero_crossing[k].crossings[node->right] == -1 ? MagickTrue :
+      MagickFalse;
+    index=node->left;
+    value=zero_crossing[k].histogram[index];
+    for (x=node->left; x <= node->right; x++)
+    {
+      if (peak != MagickFalse)
+        {
+          if (zero_crossing[k].histogram[x] > value)
+            {
+              value=zero_crossing[k].histogram[x];
+              index=x;
+            }
+        }
+      else
+        if (zero_crossing[k].histogram[x] < value)
+          {
+            value=zero_crossing[k].histogram[x];
+            index=x;
+          }
+    }
+    for (x=node->left; x <= node->right; x++)
+    {
+      if (index == 0)
+        index=256;
+      if (peak != MagickFalse)
+        extrema[x]=(short) index;
+      else
+        extrema[x]=(short) (-index);
+    }
+  }
+  /*
+    Determine the average tau.
+  */
+  average_tau=0.0;
+  for (i=0; i < number_nodes; i++)
+    average_tau+=list[i]->tau;
+  average_tau/=(MagickRealType) number_nodes;
+  /*
+    Relinquish resources.
+  */
+  FreeNodes(root);
+  zero_crossing=(ZeroCrossing *) RelinquishMagickMemory(zero_crossing);
+  list=(IntervalTree **) RelinquishMagickMemory(list);
+  return(average_tau);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S c a l e S p a c e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ScaleSpace() performs a scale-space filter on the 1D histogram.
+%
+%  The format of the ScaleSpace method is:
+%
+%      ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
+%        MagickRealType *scale_histogram)
+%
+%  A description of each parameter follows.
+%
+%    o histogram: Specifies an array of MagickRealTypes representing the number
+%      of pixels for each intensity of a particular color component.
+%
+*/
+
+static void ScaleSpace(const ssize_t *histogram,const MagickRealType tau,
+  MagickRealType *scale_histogram)
+{
+  MagickRealType
+    alpha,
+    beta,
+    *gamma,
+    sum;
+
+  register ssize_t
+    u,
+    x;
+
+  gamma=(MagickRealType *) AcquireQuantumMemory(256,sizeof(*gamma));
+  if (gamma == (MagickRealType *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,
+      "UnableToAllocateGammaMap");
+  alpha=1.0/(tau*sqrt(2.0*MagickPI));
+  beta=(-1.0/(2.0*tau*tau));
+  for (x=0; x <= 255; x++)
+    gamma[x]=0.0;
+  for (x=0; x <= 255; x++)
+  {
+    gamma[x]=exp((double) beta*x*x);
+    if (gamma[x] < MagickEpsilon)
+      break;
+  }
+  for (x=0; x <= 255; x++)
+  {
+    sum=0.0;
+    for (u=0; u <= 255; u++)
+      sum+=(MagickRealType) histogram[u]*gamma[MagickAbsoluteValue(x-u)];
+    scale_histogram[x]=alpha*sum;
+  }
+  gamma=(MagickRealType *) RelinquishMagickMemory(gamma);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  S e g m e n t I m a g e                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SegmentImage() segment an image by analyzing the histograms of the color
+%  components and identifying units that are homogeneous with the fuzzy
+%  C-means technique.
+%
+%  The format of the SegmentImage method is:
+%
+%      MagickBooleanType SegmentImage(Image *image,
+%        const ColorspaceType colorspace,const MagickBooleanType verbose,
+%        const double cluster_threshold,const double smooth_threshold)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o colorspace: Indicate the colorspace.
+%
+%    o verbose:  Set to MagickTrue to print detailed information about the
+%      identified classes.
+%
+%    o cluster_threshold:  This represents the minimum number of pixels
+%      contained in a hexahedra before it can be considered valid (expressed
+%      as a percentage).
+%
+%    o smooth_threshold: the smoothing threshold eliminates noise in the second
+%      derivative of the histogram.  As the value is increased, you can expect a
+%      smoother second derivative.
+%
+*/
+MagickExport MagickBooleanType SegmentImage(Image *image,
+  const ColorspaceType colorspace,const MagickBooleanType verbose,
+  const double cluster_threshold,const double smooth_threshold)
+{
+  MagickBooleanType
+    status;
+
+  register ssize_t
+    i;
+
+  short
+    *extrema[MaxDimension];
+
+  ssize_t
+    *histogram[MaxDimension];
+
+  /*
+    Allocate histogram and extrema.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  for (i=0; i < MaxDimension; i++)
+  {
+    histogram[i]=(ssize_t *) AcquireQuantumMemory(256,sizeof(**histogram));
+    extrema[i]=(short *) AcquireQuantumMemory(256,sizeof(**extrema));
+    if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (short *) NULL))
+      {
+        for (i-- ; i >= 0; i--)
+        {
+          extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
+          histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
+        }
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename)
+      }
+  }
+  if (colorspace != RGBColorspace)
+    (void) TransformImageColorspace(image,colorspace);
+  /*
+    Initialize histogram.
+  */
+  InitializeHistogram(image,histogram,&image->exception);
+  (void) OptimalTau(histogram[Red],Tau,0.2,DeltaTau,
+    smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Red]);
+  (void) OptimalTau(histogram[Green],Tau,0.2,DeltaTau,
+    smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Green]);
+  (void) OptimalTau(histogram[Blue],Tau,0.2,DeltaTau,
+    smooth_threshold == 0.0 ? 1.0 : smooth_threshold,extrema[Blue]);
+  /*
+    Classify using the fuzzy c-Means technique.
+  */
+  status=Classify(image,extrema,cluster_threshold,WeightingExponent,verbose);
+  if (colorspace != RGBColorspace)
+    (void) TransformImageColorspace(image,colorspace);
+  /*
+    Relinquish resources.
+  */
+  for (i=0; i < MaxDimension; i++)
+  {
+    extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
+    histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
+  }
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   Z e r o C r o s s H i s t o g r a m                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ZeroCrossHistogram() find the zero crossings in a histogram and marks
+%  directions as:  1 is negative to positive; 0 is zero crossing; and -1
+%  is positive to negative.
+%
+%  The format of the ZeroCrossHistogram method is:
+%
+%      ZeroCrossHistogram(MagickRealType *second_derivative,
+%        const MagickRealType smooth_threshold,short *crossings)
+%
+%  A description of each parameter follows.
+%
+%    o second_derivative: Specifies an array of MagickRealTypes representing the
+%      second derivative of the histogram of a particular color component.
+%
+%    o crossings:  This array of integers is initialized with
+%      -1, 0, or 1 representing the slope of the first derivative of the
+%      of a particular color component.
+%
+*/
+static void ZeroCrossHistogram(MagickRealType *second_derivative,
+  const MagickRealType smooth_threshold,short *crossings)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    parity;
+
+  /*
+    Merge low numbers to zero to help prevent noise.
+  */
+  for (i=0; i <= 255; i++)
+    if ((second_derivative[i] < smooth_threshold) &&
+        (second_derivative[i] >= -smooth_threshold))
+      second_derivative[i]=0.0;
+  /*
+    Mark zero crossings.
+  */
+  parity=0;
+  for (i=0; i <= 255; i++)
+  {
+    crossings[i]=0;
+    if (second_derivative[i] < 0.0)
+      {
+        if (parity > 0)
+          crossings[i]=(-1);
+        parity=1;
+      }
+    else
+      if (second_derivative[i] > 0.0)
+        {
+          if (parity < 0)
+            crossings[i]=1;
+          parity=(-1);
+        }
+  }
+}
diff --git a/MagickCore/segment.h b/MagickCore/segment.h
new file mode 100644
index 0000000..06314da
--- /dev/null
+++ b/MagickCore/segment.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image segment methods.
+*/
+#ifndef _MAGICKCORE_SEGMENT_H
+#define _MAGICKCORE_SEGMENT_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  GetImageDynamicThreshold(const Image *,const double,const double,
+    PixelInfo *,ExceptionInfo *),
+  SegmentImage(Image *,const ColorspaceType,const MagickBooleanType,
+    const double,const double);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/semaphore-private.h b/MagickCore/semaphore-private.h
new file mode 100644
index 0000000..621d80d
--- /dev/null
+++ b/MagickCore/semaphore-private.h
@@ -0,0 +1,79 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private methods to lock and unlock semaphores.
+*/
+#ifndef _MAGICKCORE_SEMAPHORE_PRIVATE_H
+#define _MAGICKCORE_SEMAPHORE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+static pthread_mutex_t
+  semaphore_mutex = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+static LONG
+  semaphore_mutex = 0;
+#else
+static ssize_t
+  semaphore_mutex = 0;
+#endif
+
+static inline void LockMagickMutex(void)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    int
+      status;
+
+    status=pthread_mutex_lock(&semaphore_mutex);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,"UnableToLockSemaphore");
+      }
+  }
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  while (InterlockedCompareExchange(&semaphore_mutex,1L,0L) != 0)
+    Sleep(10);
+#endif
+}
+
+static inline void UnlockMagickMutex(void)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    int
+      status;
+
+    status=pthread_mutex_unlock(&semaphore_mutex);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,"UnableToUnlockSemaphore");
+      }
+  }
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  InterlockedExchange(&semaphore_mutex,0L);
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/semaphore.c b/MagickCore/semaphore.c
new file mode 100644
index 0000000..3c169f1
--- /dev/null
+++ b/MagickCore/semaphore.c
@@ -0,0 +1,419 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        SSSSS  EEEEE  M   M   AAA   PPPP   H   H   OOO   RRRR   EEEEE        %
+%        SS     E      MM MM  A   A  P   P  H   H  O   O  R   R  E            %
+%         SSS   EEE    M M M  AAAAA  PPPP   HHHHH  O   O  RRRR   EEE          %
+%           SS  E      M   M  A   A  P      H   H  O   O  R R    E            %
+%        SSSSS  EEEEE  M   M  A   A  P      H   H   OOO   R  R   EEEEE        %
+%                                                                             %
+%                                                                             %
+%                        MagickCore Semaphore Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                             William Radcliffe                               %
+%                                John Cristy                                  %
+%                                 June 2000                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/semaphore-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread_.h"
+#include "MagickCore/thread-private.h"
+
+/*
+  Struct declaractions.
+*/
+struct SemaphoreInfo
+{
+  MagickMutexType
+    mutex;
+
+  MagickThreadType
+    id;
+
+  ssize_t
+    reference_count;
+
+  size_t
+    signature;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e S e m a p h o r e I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireSemaphoreInfo() acquires a semaphore.
+%
+%  The format of the AcquireSemaphoreInfo method is:
+%
+%      void AcquireSemaphoreInfo(SemaphoreInfo **semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport void AcquireSemaphoreInfo(SemaphoreInfo **semaphore_info)
+{
+  assert(semaphore_info != (SemaphoreInfo **) NULL);
+  if (*semaphore_info == (SemaphoreInfo *) NULL)
+    {
+      LockMagickMutex();
+      if (*semaphore_info == (SemaphoreInfo *) NULL)
+        *semaphore_info=AllocateSemaphoreInfo();
+      UnlockMagickMutex();
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A l l o c a t e S e m a p h o r e I n f o                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AllocateSemaphoreInfo() initializes the SemaphoreInfo structure.
+%
+%  The format of the AllocateSemaphoreInfo method is:
+%
+%      SemaphoreInfo *AllocateSemaphoreInfo(void)
+%
+*/
+MagickExport SemaphoreInfo *AllocateSemaphoreInfo(void)
+{
+  SemaphoreInfo
+    *semaphore_info;
+
+  /*
+    Allocate semaphore.
+  */
+  semaphore_info=(SemaphoreInfo *) malloc(sizeof(SemaphoreInfo));
+  if (semaphore_info == (SemaphoreInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(semaphore_info,0,sizeof(SemaphoreInfo));
+  /*
+    Initialize the semaphore.
+  */
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    int
+      status;
+
+    pthread_mutexattr_t
+      mutex_info;
+
+    status=pthread_mutexattr_init(&mutex_info);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToInitializeSemaphore");
+      }
+    status=pthread_mutex_init(&semaphore_info->mutex,&mutex_info);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToInitializeSemaphore");
+      }
+    status=pthread_mutexattr_destroy(&mutex_info);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToInitializeSemaphore");
+      }
+  }
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  {
+    int
+      status;
+
+    status=InitializeCriticalSectionAndSpinCount(&semaphore_info->mutex,0x0400);
+    if (status == 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToInitializeSemaphore");
+       }
+  }
+#endif
+  semaphore_info->id=GetMagickThreadId();
+  semaphore_info->reference_count=0;
+  semaphore_info->signature=MagickSignature;
+  return(semaphore_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y S e m a p h o r e I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroySemaphoreInfo() destroys a semaphore.
+%
+%  The format of the DestroySemaphoreInfo method is:
+%
+%      void DestroySemaphoreInfo(SemaphoreInfo **semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport void DestroySemaphoreInfo(SemaphoreInfo **semaphore_info)
+{
+  assert(semaphore_info != (SemaphoreInfo **) NULL);
+  assert((*semaphore_info) != (SemaphoreInfo *) NULL);
+  assert((*semaphore_info)->signature == MagickSignature);
+  LockMagickMutex();
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    int
+      status;
+
+    status=pthread_mutex_destroy(&(*semaphore_info)->mutex);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,"UnableToDestroySemaphore");
+      }
+  }
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  DeleteCriticalSection(&(*semaphore_info)->mutex);
+#endif
+  (*semaphore_info)->signature=(~MagickSignature);
+  free(*semaphore_info);
+  *semaphore_info=(SemaphoreInfo *) NULL;
+  UnlockMagickMutex();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L o c k S e m a p h o r e I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LockSemaphoreInfo() locks a semaphore.
+%
+%  The format of the LockSemaphoreInfo method is:
+%
+%      void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+{
+  assert(semaphore_info != (SemaphoreInfo *) NULL);
+  assert(semaphore_info->signature == MagickSignature);
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    int
+      status;
+
+    status=pthread_mutex_lock(&semaphore_info->mutex);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,"UnableToLockSemaphore");
+      }
+  }
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  EnterCriticalSection(&semaphore_info->mutex);
+#endif
+#if defined(MAGICKCORE_DEBUG)
+  if ((semaphore_info->reference_count > 0) &&
+      (IsMagickThreadEqual(semaphore_info->id) != MagickFalse))
+    {
+      (void) FormatLocaleFile(stderr,"Warning: unexpected recursive lock!\n");
+      (void) fflush(stderr);
+    }
+#endif
+  semaphore_info->id=GetMagickThreadId();
+  semaphore_info->reference_count++;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e l i n g u i s h S e m a p h o r e I n f o                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RelinquishSemaphoreInfo() relinquishes a semaphore.
+%
+%  The format of the RelinquishSemaphoreInfo method is:
+%
+%      RelinquishSemaphoreInfo(SemaphoreInfo *semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo *semaphore_info)
+{
+  assert(semaphore_info != (SemaphoreInfo *) NULL);
+  assert(semaphore_info->signature == MagickSignature);
+  UnlockSemaphoreInfo(semaphore_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e m a p h o r e C o m p o n e n t G e n e s i s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SemaphoreComponentGenesis() instantiates the semaphore environment.
+%
+%  The format of the SemaphoreComponentGenesis method is:
+%
+%      MagickBooleanType SemaphoreComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType SemaphoreComponentGenesis(void)
+{
+  LockMagickMutex();
+  UnlockMagickMutex();
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e m a p h o r e C o m p o n e n t T e r m i n u s                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SemaphoreComponentTerminus() destroys the semaphore component.
+%
+%  The format of the SemaphoreComponentTerminus method is:
+%
+%      SemaphoreComponentTerminus(void)
+%
+*/
+MagickExport void SemaphoreComponentTerminus(void)
+{
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   U n l o c k S e m a p h o r e I n f o                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnlockSemaphoreInfo() unlocks a semaphore.
+%
+%  The format of the UnlockSemaphoreInfo method is:
+%
+%      void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+%
+%  A description of each parameter follows:
+%
+%    o semaphore_info: Specifies a pointer to an SemaphoreInfo structure.
+%
+*/
+MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
+{
+  assert(semaphore_info != (SemaphoreInfo *) NULL);
+  assert(semaphore_info->signature == MagickSignature);
+#if defined(MAGICKCORE_DEBUG)
+  assert(IsMagickThreadEqual(semaphore_info->id) != MagickFalse);
+  if (semaphore_info->reference_count == 0)
+    {
+      (void) FormatLocaleFile(stderr,
+        "Warning: semaphore lock already unlocked!\n");
+      (void) fflush(stderr);
+      return;
+    }
+  semaphore_info->reference_count--;
+#endif
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    int
+      status;
+
+    status=pthread_mutex_unlock(&semaphore_info->mutex);
+    if (status != 0)
+      {
+        errno=status;
+        ThrowFatalException(ResourceLimitFatalError,"UnableToUnlockSemaphore");
+      }
+  }
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  LeaveCriticalSection(&semaphore_info->mutex);
+#endif
+}
diff --git a/MagickCore/semaphore.h b/MagickCore/semaphore.h
new file mode 100644
index 0000000..24cf42f
--- /dev/null
+++ b/MagickCore/semaphore.h
@@ -0,0 +1,46 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore methods to lock and unlock semaphores.
+*/
+#ifndef _MAGICKCORE_SEMAPHORE_H
+#define _MAGICKCORE_SEMAPHORE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct SemaphoreInfo
+  SemaphoreInfo;
+
+extern MagickExport MagickBooleanType
+  SemaphoreComponentGenesis(void);
+
+extern MagickExport SemaphoreInfo
+  *AllocateSemaphoreInfo(void);
+
+extern MagickExport void
+  AcquireSemaphoreInfo(SemaphoreInfo **),
+  DestroySemaphoreInfo(SemaphoreInfo **),
+  LockSemaphoreInfo(SemaphoreInfo *),
+  RelinquishSemaphoreInfo(SemaphoreInfo *),
+  SemaphoreComponentTerminus(void),
+  UnlockSemaphoreInfo(SemaphoreInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/shear.c b/MagickCore/shear.c
new file mode 100644
index 0000000..70f093a
--- /dev/null
+++ b/MagickCore/shear.c
@@ -0,0 +1,2098 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      SSSSS  H   H  EEEEE   AAA    RRRR                      %
+%                      SS     H   H  E      A   A   R   R                     %
+%                       SSS   HHHHH  EEE    AAAAA   RRRR                      %
+%                         SS  H   H  E      A   A   R R                       %
+%                      SSSSS  H   H  EEEEE  A   A   R  R                      %
+%                                                                             %
+%                                                                             %
+%    MagickCore Methods to Shear or Rotate an Image by an Arbitrary Angle     %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                  July 1992                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The RotateImage, XShearImage, and YShearImage methods are based on the
+%  paper "A Fast Algorithm for General Raster Rotatation" by Alan W. Paeth,
+%  Graphics Interface '86 (Vancouver).  RotateImage is adapted from a similar
+%  method based on the Paeth paper written by Michael Halle of the Spatial
+%  Imaging Group, MIT Media Lab.
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/distort.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/list.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/transform.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A f f i n e T r a n s f o r m I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AffineTransformImage() transforms an image as dictated by the affine matrix.
+%  It allocates the memory necessary for the new Image structure and returns
+%  a pointer to the new image.
+%
+%  The format of the AffineTransformImage method is:
+%
+%      Image *AffineTransformImage(const Image *image,
+%        AffineMatrix *affine_matrix,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o affine_matrix: the affine matrix.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *AffineTransformImage(const Image *image,
+  const AffineMatrix *affine_matrix,ExceptionInfo *exception)
+{
+  double
+    distort[6];
+
+  Image
+    *deskew_image;
+
+  /*
+    Affine transform image.
+  */
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(affine_matrix != (AffineMatrix *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  distort[0]=affine_matrix->sx;
+  distort[1]=affine_matrix->rx;
+  distort[2]=affine_matrix->ry;
+  distort[3]=affine_matrix->sy;
+  distort[4]=affine_matrix->tx;
+  distort[5]=affine_matrix->ty;
+  deskew_image=DistortImage(image,AffineProjectionDistortion,6,distort,
+    MagickTrue,exception);
+  return(deskew_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   C r o p T o F i t I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CropToFitImage() crops the sheared image as determined by the bounding box
+%  as defined by width and height and shearing angles.
+%
+%  The format of the CropToFitImage method is:
+%
+%      MagickBooleanType CropToFitImage(Image **image,
+%        const MagickRealType x_shear,const MagickRealType x_shear,
+%        const MagickRealType width,const MagickRealType height,
+%        const MagickBooleanType rotate,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o x_shear, y_shear, width, height: Defines a region of the image to crop.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType CropToFitImage(Image **image,
+  const MagickRealType x_shear,const MagickRealType y_shear,
+  const MagickRealType width,const MagickRealType height,
+  const MagickBooleanType rotate,ExceptionInfo *exception)
+{
+  Image
+    *crop_image;
+
+  PointInfo
+    extent[4],
+    min,
+    max;
+
+  RectangleInfo
+    geometry,
+    page;
+
+  register ssize_t
+    i;
+
+  /*
+    Calculate the rotated image size.
+  */
+  extent[0].x=(double) (-width/2.0);
+  extent[0].y=(double) (-height/2.0);
+  extent[1].x=(double) width/2.0;
+  extent[1].y=(double) (-height/2.0);
+  extent[2].x=(double) (-width/2.0);
+  extent[2].y=(double) height/2.0;
+  extent[3].x=(double) width/2.0;
+  extent[3].y=(double) height/2.0;
+  for (i=0; i < 4; i++)
+  {
+    extent[i].x+=x_shear*extent[i].y;
+    extent[i].y+=y_shear*extent[i].x;
+    if (rotate != MagickFalse)
+      extent[i].x+=x_shear*extent[i].y;
+    extent[i].x+=(double) (*image)->columns/2.0;
+    extent[i].y+=(double) (*image)->rows/2.0;
+  }
+  min=extent[0];
+  max=extent[0];
+  for (i=1; i < 4; i++)
+  {
+    if (min.x > extent[i].x)
+      min.x=extent[i].x;
+    if (min.y > extent[i].y)
+      min.y=extent[i].y;
+    if (max.x < extent[i].x)
+      max.x=extent[i].x;
+    if (max.y < extent[i].y)
+      max.y=extent[i].y;
+  }
+  geometry.x=(ssize_t) ceil(min.x-0.5);
+  geometry.y=(ssize_t) ceil(min.y-0.5);
+  geometry.width=(size_t) floor(max.x-min.x+0.5);
+  geometry.height=(size_t) floor(max.y-min.y+0.5);
+  page=(*image)->page;
+  (void) ParseAbsoluteGeometry("0x0+0+0",&(*image)->page);
+  crop_image=CropImage(*image,&geometry,exception);
+  if (crop_image == (Image *) NULL)
+    return(MagickFalse);
+  crop_image->page=page;
+  *image=DestroyImage(*image);
+  *image=crop_image;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     D e s k e w I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeskewImage() removes skew from the image.  Skew is an artifact that
+%  occurs in scanned images because of the camera being misaligned,
+%  imperfections in the scanning or surface, or simply because the paper was
+%  not placed completely flat when scanned.
+%
+%  The format of the DeskewImage method is:
+%
+%      Image *DeskewImage(const Image *image,const double threshold,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o threshold: separate background from foreground.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+typedef struct _RadonInfo
+{
+  CacheType
+    type;
+
+  size_t
+    width,
+    height;
+
+  MagickSizeType
+    length;
+
+  MagickBooleanType
+    mapped;
+
+  char
+    path[MaxTextExtent];
+
+  int
+    file;
+
+  unsigned short
+    *cells;
+} RadonInfo;
+
+static RadonInfo *DestroyRadonInfo(RadonInfo *radon_info)
+{
+  assert(radon_info != (RadonInfo *) NULL);
+  switch (radon_info->type)
+  {
+    case MemoryCache:
+    {
+      if (radon_info->mapped == MagickFalse)
+        radon_info->cells=(unsigned short *) RelinquishMagickMemory(
+          radon_info->cells);
+      else
+        radon_info->cells=(unsigned short *) UnmapBlob(radon_info->cells,
+          (size_t) radon_info->length);
+      RelinquishMagickResource(MemoryResource,radon_info->length);
+      break;
+    }
+    case MapCache:
+    {
+      radon_info->cells=(unsigned short *) UnmapBlob(radon_info->cells,(size_t)
+        radon_info->length);
+      RelinquishMagickResource(MapResource,radon_info->length);
+    }
+    case DiskCache:
+    {
+      if (radon_info->file != -1)
+        (void) close(radon_info->file);
+      (void) RelinquishUniqueFileResource(radon_info->path);
+      RelinquishMagickResource(DiskResource,radon_info->length);
+      break;
+    }
+    default:
+      break;
+  }
+  return((RadonInfo *) RelinquishMagickMemory(radon_info));
+}
+
+static MagickBooleanType ResetRadonCells(RadonInfo *radon_info)
+{
+  register ssize_t
+    x;
+
+  ssize_t
+    count,
+    y;
+
+  unsigned short
+    value;
+
+  if (radon_info->type != DiskCache)
+    {
+      (void) ResetMagickMemory(radon_info->cells,0,(size_t) radon_info->length);
+      return(MagickTrue);
+    }
+  value=0;
+  (void) lseek(radon_info->file,0,SEEK_SET);
+  for (y=0; y < (ssize_t) radon_info->height; y++)
+  {
+    for (x=0; x < (ssize_t) radon_info->width; x++)
+    {
+      count=write(radon_info->file,&value,sizeof(*radon_info->cells));
+      if (count != (ssize_t) sizeof(*radon_info->cells))
+        break;
+    }
+    if (x < (ssize_t) radon_info->width)
+      break;
+  }
+  return(y < (ssize_t) radon_info->height ? MagickFalse : MagickTrue);
+}
+
+static RadonInfo *AcquireRadonInfo(const Image *image,const size_t width,
+  const size_t height,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  RadonInfo
+    *radon_info;
+
+  radon_info=(RadonInfo *) AcquireMagickMemory(sizeof(*radon_info));
+  if (radon_info == (RadonInfo *) NULL)
+    return((RadonInfo *) NULL);
+  (void) ResetMagickMemory(radon_info,0,sizeof(*radon_info));
+  radon_info->width=width;
+  radon_info->height=height;
+  radon_info->length=(MagickSizeType) width*height*sizeof(*radon_info->cells);
+  radon_info->type=MemoryCache;
+  status=AcquireMagickResource(AreaResource,radon_info->length);
+  if ((status != MagickFalse) &&
+      (radon_info->length == (MagickSizeType) ((size_t) radon_info->length)))
+    {
+      status=AcquireMagickResource(MemoryResource,radon_info->length);
+      if (status != MagickFalse)
+        {
+          radon_info->mapped=MagickFalse;
+          radon_info->cells=(unsigned short *) AcquireMagickMemory((size_t)
+            radon_info->length);
+          if (radon_info->cells == (unsigned short *) NULL)
+            {
+              radon_info->mapped=MagickTrue;
+              radon_info->cells=(unsigned short *) MapBlob(-1,IOMode,0,(size_t)
+                radon_info->length);
+            }
+          if (radon_info->cells == (unsigned short *) NULL)
+            RelinquishMagickResource(MemoryResource,radon_info->length);
+        }
+    }
+  radon_info->file=(-1);
+  if (radon_info->cells == (unsigned short *) NULL)
+    {
+      status=AcquireMagickResource(DiskResource,radon_info->length);
+      if (status == MagickFalse)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+            "CacheResourcesExhausted","`%s'",image->filename);
+          return(DestroyRadonInfo(radon_info));
+        }
+      radon_info->type=DiskCache;
+      (void) AcquireMagickResource(MemoryResource,radon_info->length);
+      radon_info->file=AcquireUniqueFileResource(radon_info->path);
+      if (radon_info->file == -1)
+        return(DestroyRadonInfo(radon_info));
+      status=AcquireMagickResource(MapResource,radon_info->length);
+      if (status != MagickFalse)
+        {
+          status=ResetRadonCells(radon_info);
+          if (status != MagickFalse)
+            {
+              radon_info->cells=(unsigned short *) MapBlob(radon_info->file,
+                IOMode,0,(size_t) radon_info->length);
+              if (radon_info->cells != (unsigned short *) NULL)
+                radon_info->type=MapCache;
+              else
+                RelinquishMagickResource(MapResource,radon_info->length);
+            }
+        }
+    }
+  return(radon_info);
+}
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static inline ssize_t ReadRadonCell(const RadonInfo *radon_info,
+  const MagickOffsetType offset,const size_t length,unsigned char *buffer)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    count;
+
+#if !defined(MAGICKCORE_HAVE_PPREAD)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ReadRadonCell)
+#endif
+  {
+    i=(-1);
+    if (lseek(radon_info->file,offset,SEEK_SET) >= 0)
+      {
+#endif
+        count=0;
+        for (i=0; i < (ssize_t) length; i+=count)
+        {
+#if !defined(MAGICKCORE_HAVE_PPREAD)
+          count=read(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
+            SSIZE_MAX));
+#else
+          count=pread(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
+            SSIZE_MAX),offset+i);
+#endif
+          if (count > 0)
+            continue;
+          count=0;
+          if (errno != EINTR)
+            {
+              i=(-1);
+              break;
+            }
+        }
+#if !defined(MAGICKCORE_HAVE_PPREAD)
+      }
+  }
+#endif
+  return(i);
+}
+
+static inline ssize_t WriteRadonCell(const RadonInfo *radon_info,
+  const MagickOffsetType offset,const size_t length,const unsigned char *buffer)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    count;
+
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_WriteRadonCell)
+#endif
+  {
+    if (lseek(radon_info->file,offset,SEEK_SET) >= 0)
+      {
+#endif
+        count=0;
+        for (i=0; i < (ssize_t) length; i+=count)
+        {
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+          count=write(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
+            SSIZE_MAX));
+#else
+          count=pwrite(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
+            SSIZE_MAX),offset+i);
+#endif
+          if (count > 0)
+            continue;
+          count=0;
+          if (errno != EINTR)
+            {
+              i=(-1);
+              break;
+            }
+        }
+#if !defined(MAGICKCORE_HAVE_PWRITE)
+      }
+  }
+#endif
+  return(i);
+}
+
+static inline unsigned short GetRadonCell(const RadonInfo *radon_info,
+  const ssize_t x,const ssize_t y)
+{
+  MagickOffsetType
+    i;
+
+  unsigned short
+    value;
+
+  i=(MagickOffsetType) radon_info->height*x+y;
+  if ((i < 0) ||
+      ((MagickSizeType) (i*sizeof(*radon_info->cells)) >= radon_info->length))
+    return(0);
+  if (radon_info->type != DiskCache)
+    return(radon_info->cells[i]);
+  value=0;
+  (void) ReadRadonCell(radon_info,i*sizeof(*radon_info->cells),
+    sizeof(*radon_info->cells),(unsigned char *) &value);
+  return(value);
+}
+
+static inline MagickBooleanType SetRadonCell(const RadonInfo *radon_info,
+  const ssize_t x,const ssize_t y,const unsigned short value)
+{
+  MagickOffsetType
+    i;
+
+  ssize_t
+    count;
+
+  i=(MagickOffsetType) radon_info->height*x+y;
+  if ((i < 0) ||
+      ((MagickSizeType) (i*sizeof(*radon_info->cells)) >= radon_info->length))
+    return(MagickFalse);
+  if (radon_info->type != DiskCache)
+    {
+      radon_info->cells[i]=value;
+      return(MagickTrue);
+    }
+  count=WriteRadonCell(radon_info,i*sizeof(*radon_info->cells),
+    sizeof(*radon_info->cells),(const unsigned char *) &value);
+  if (count != (ssize_t) sizeof(*radon_info->cells))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static void RadonProjection(RadonInfo *source_cells,
+  RadonInfo *destination_cells,const ssize_t sign,size_t *projection)
+{
+  RadonInfo
+    *swap;
+
+  register ssize_t
+    x;
+
+  register RadonInfo
+    *p,
+    *q;
+
+  size_t
+    step;
+
+  p=source_cells;
+  q=destination_cells;
+  for (step=1; step < p->width; step*=2)
+  {
+    for (x=0; x < (ssize_t) p->width; x+=2*(ssize_t) step)
+    {
+      register ssize_t
+        i;
+
+      ssize_t
+        y;
+
+      unsigned short
+        cell;
+
+      for (i=0; i < (ssize_t) step; i++)
+      {
+        for (y=0; y < (ssize_t) (p->height-i-1); y++)
+        {
+          cell=GetRadonCell(p,x+i,y);
+          (void) SetRadonCell(q,x+2*i,y,cell+GetRadonCell(p,x+i+(ssize_t)
+            step,y+i));
+          (void) SetRadonCell(q,x+2*i+1,y,cell+GetRadonCell(p,x+i+(ssize_t)
+            step,y+i+1));
+        }
+        for ( ; y < (ssize_t) (p->height-i); y++)
+        {
+          cell=GetRadonCell(p,x+i,y);
+          (void) SetRadonCell(q,x+2*i,y,cell+GetRadonCell(p,x+i+(ssize_t) step,
+            y+i));
+          (void) SetRadonCell(q,x+2*i+1,y,cell);
+        }
+        for ( ; y < (ssize_t) p->height; y++)
+        {
+          cell=GetRadonCell(p,x+i,y);
+          (void) SetRadonCell(q,x+2*i,y,cell);
+          (void) SetRadonCell(q,x+2*i+1,y,cell);
+        }
+      }
+    }
+    swap=p;
+    p=q;
+    q=swap;
+  }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4)
+#endif
+  for (x=0; x < (ssize_t) p->width; x++)
+  {
+    register ssize_t
+      y;
+
+    size_t
+      sum;
+
+    sum=0;
+    for (y=0; y < (ssize_t) (p->height-1); y++)
+    {
+      ssize_t
+        delta;
+
+      delta=GetRadonCell(p,x,y)-(ssize_t) GetRadonCell(p,x,y+1);
+      sum+=delta*delta;
+    }
+    projection[p->width+sign*x-1]=sum;
+  }
+}
+
+static MagickBooleanType RadonTransform(const Image *image,
+  const double threshold,size_t *projection,ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  RadonInfo
+    *destination_cells,
+    *source_cells;
+
+  register ssize_t
+    i;
+
+  size_t
+    count,
+    width;
+
+  ssize_t
+    y;
+
+  unsigned char
+    byte;
+
+  unsigned short
+    bits[256];
+
+  for (width=1; width < ((image->columns+7)/8); width<<=1) ;
+  source_cells=AcquireRadonInfo(image,width,image->rows,exception);
+  destination_cells=AcquireRadonInfo(image,width,image->rows,exception);
+  if ((source_cells == (RadonInfo *) NULL) ||
+      (destination_cells == (RadonInfo *) NULL))
+    {
+      if (destination_cells != (RadonInfo *) NULL)
+        destination_cells=DestroyRadonInfo(destination_cells);
+      if (source_cells != (RadonInfo *) NULL)
+        source_cells=DestroyRadonInfo(source_cells);
+      return(MagickFalse);
+    }
+  if (ResetRadonCells(source_cells) == MagickFalse)
+    {
+      destination_cells=DestroyRadonInfo(destination_cells);
+      source_cells=DestroyRadonInfo(source_cells);
+      return(MagickFalse);
+    }
+  for (i=0; i < 256; i++)
+  {
+    byte=(unsigned char) i;
+    for (count=0; byte != 0; byte>>=1)
+      count+=byte & 0x01;
+    bits[i]=(unsigned short) count;
+  }
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      i,
+      x;
+
+    size_t
+      bit,
+      byte;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    bit=0;
+    byte=0;
+    i=(ssize_t) (image->columns+7)/8;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      byte<<=1;
+      if (((MagickRealType) GetPixelRed(image,p) < threshold) ||
+          ((MagickRealType) GetPixelGreen(image,p) < threshold) ||
+          ((MagickRealType) GetPixelBlue(image,p) < threshold))
+        byte|=0x01;
+      bit++;
+      if (bit == 8)
+        {
+          (void) SetRadonCell(source_cells,--i,y,bits[byte]);
+          bit=0;
+          byte=0;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (bit != 0)
+      {
+        byte<<=(8-bit);
+        (void) SetRadonCell(source_cells,--i,y,bits[byte]);
+      }
+  }
+  RadonProjection(source_cells,destination_cells,-1,projection);
+  (void) ResetRadonCells(source_cells);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      i,
+      x;
+
+    size_t
+      bit,
+      byte;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    bit=0;
+    byte=0;
+    i=0;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      byte<<=1;
+      if (((MagickRealType) GetPixelRed(image,p) < threshold) ||
+          ((MagickRealType) GetPixelGreen(image,p) < threshold) ||
+          ((MagickRealType) GetPixelBlue(image,p) < threshold))
+        byte|=0x01;
+      bit++;
+      if (bit == 8)
+        {
+          (void) SetRadonCell(source_cells,i++,y,bits[byte]);
+          bit=0;
+          byte=0;
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (bit != 0)
+      {
+        byte<<=(8-bit);
+        (void) SetRadonCell(source_cells,i++,y,bits[byte]);
+      }
+  }
+  RadonProjection(source_cells,destination_cells,1,projection);
+  image_view=DestroyCacheView(image_view);
+  destination_cells=DestroyRadonInfo(destination_cells);
+  source_cells=DestroyRadonInfo(source_cells);
+  return(MagickTrue);
+}
+
+static void GetImageBackgroundColor(Image *image,const ssize_t offset,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  PixelInfo
+    background;
+
+  MagickRealType
+    count;
+
+  ssize_t
+    y;
+
+  /*
+    Compute average background color.
+  */
+  if (offset <= 0)
+    return;
+  GetPixelInfo(image,&background);
+  count=0.0;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    if ((y >= offset) && (y < ((ssize_t) image->rows-offset)))
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      continue;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((x >= offset) && (x < ((ssize_t) image->columns-offset)))
+        continue;
+      background.red+=QuantumScale*GetPixelRed(image,p);
+      background.green+=QuantumScale*GetPixelGreen(image,p);
+      background.blue+=QuantumScale*GetPixelBlue(image,p);
+      background.alpha+=QuantumScale*GetPixelAlpha(image,p);
+      count++;
+      p+=GetPixelChannels(image);
+    }
+  }
+  image_view=DestroyCacheView(image_view);
+  image->background_color.red=ClampToQuantum((MagickRealType) QuantumRange*
+    background.red/count);
+  image->background_color.green=ClampToQuantum((MagickRealType) QuantumRange*
+    background.green/count);
+  image->background_color.blue=ClampToQuantum((MagickRealType) QuantumRange*
+    background.blue/count);
+  image->background_color.alpha=ClampToQuantum((MagickRealType) QuantumRange*
+    background.alpha/count);
+}
+
+MagickExport Image *DeskewImage(const Image *image,const double threshold,
+  ExceptionInfo *exception)
+{
+  AffineMatrix
+    affine_matrix;
+
+  const char
+    *artifact;
+
+  double
+    degrees;
+
+  Image
+    *clone_image,
+    *crop_image,
+    *deskew_image,
+    *median_image;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    geometry;
+
+  register ssize_t
+    i;
+
+  size_t
+    max_projection,
+    *projection,
+    width;
+
+  ssize_t
+    skew;
+
+  /*
+    Compute deskew angle.
+  */
+  for (width=1; width < ((image->columns+7)/8); width<<=1) ;
+  projection=(size_t *) AcquireQuantumMemory((size_t) (2*width-1),
+    sizeof(*projection));
+  if (projection == (size_t *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  status=RadonTransform(image,threshold,projection,exception);
+  if (status == MagickFalse)
+    {
+      projection=(size_t *) RelinquishMagickMemory(projection);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
+  max_projection=0;
+  skew=0;
+  for (i=0; i < (ssize_t) (2*width-1); i++)
+  {
+    if (projection[i] > max_projection)
+      {
+        skew=i-(ssize_t) width+1;
+        max_projection=projection[i];
+      }
+  }
+  projection=(size_t *) RelinquishMagickMemory(projection);
+  /*
+    Deskew image.
+  */
+  clone_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (clone_image == (Image *) NULL)
+    return((Image *) NULL);
+  (void) SetImageVirtualPixelMethod(clone_image,BackgroundVirtualPixelMethod);
+  degrees=RadiansToDegrees(-atan((double) skew/width/8));
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+      "  Deskew angle: %g",degrees);
+  affine_matrix.sx=cos(DegreesToRadians(fmod((double) degrees,360.0)));
+  affine_matrix.rx=sin(DegreesToRadians(fmod((double) degrees,360.0)));
+  affine_matrix.ry=(-sin(DegreesToRadians(fmod((double) degrees,360.0))));
+  affine_matrix.sy=cos(DegreesToRadians(fmod((double) degrees,360.0)));
+  affine_matrix.tx=0.0;
+  affine_matrix.ty=0.0;
+  artifact=GetImageArtifact(image,"deskew:auto-crop");
+  if (artifact == (const char *) NULL)
+    {
+      deskew_image=AffineTransformImage(clone_image,&affine_matrix,exception);
+      clone_image=DestroyImage(clone_image);
+      return(deskew_image);
+    }
+  /*
+    Auto-crop image.
+  */
+  GetImageBackgroundColor(clone_image,(ssize_t) StringToLong(artifact),
+    exception);
+  deskew_image=AffineTransformImage(clone_image,&affine_matrix,exception);
+  clone_image=DestroyImage(clone_image);
+  if (deskew_image == (Image *) NULL)
+    return((Image *) NULL);
+  median_image=StatisticImage(deskew_image,MedianStatistic,3,3,exception);
+  if (median_image == (Image *) NULL)
+    {
+      deskew_image=DestroyImage(deskew_image);
+      return((Image *) NULL);
+    }
+  geometry=GetImageBoundingBox(median_image,exception);
+  median_image=DestroyImage(median_image);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TransformEvent,GetMagickModule(),"  Deskew geometry: "
+      "%.20gx%.20g%+.20g%+.20g",(double) geometry.width,(double)
+      geometry.height,(double) geometry.x,(double) geometry.y);
+  crop_image=CropImage(deskew_image,&geometry,exception);
+  deskew_image=DestroyImage(deskew_image);
+  return(crop_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n t e g r a l R o t a t e I m a g e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IntegralRotateImage() rotates the image an integral of 90 degrees.  It
+%  allocates the memory necessary for the new Image structure and returns a
+%  pointer to the rotated image.
+%
+%  The format of the IntegralRotateImage method is:
+%
+%      Image *IntegralRotateImage(const Image *image,size_t rotations,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o rotations: Specifies the number of 90 degree rotations.
+%
+*/
+static Image *IntegralRotateImage(const Image *image,size_t rotations,
+  ExceptionInfo *exception)
+{
+#define RotateImageTag  "Rotate/Image"
+
+  CacheView
+    *image_view,
+    *rotate_view;
+
+  Image
+    *rotate_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    page;
+
+  ssize_t
+    y;
+
+  /*
+    Initialize rotated image attributes.
+  */
+  assert(image != (Image *) NULL);
+  page=image->page;
+  rotations%=4;
+  if (rotations == 0)
+    return(CloneImage(image,0,0,MagickTrue,exception));
+  if ((rotations == 1) || (rotations == 3))
+    rotate_image=CloneImage(image,image->rows,image->columns,MagickTrue,
+      exception);
+  else
+    rotate_image=CloneImage(image,image->columns,image->rows,MagickTrue,
+      exception);
+  if (rotate_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Integral rotate the image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  rotate_view=AcquireCacheView(rotate_image);
+  switch (rotations)
+  {
+    case 0:
+    {
+      /*
+        Rotate 0 degrees.
+      */
+      break;
+    }
+    case 1:
+    {
+      size_t
+        tile_height,
+        tile_width;
+
+      ssize_t
+        tile_y;
+
+      /*
+        Rotate 90 degrees.
+      */
+      GetPixelCacheTileSize(image,&tile_width,&tile_height);
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(static,1) shared(progress, status) omp_throttle(1)
+#endif
+      for (tile_y=0; tile_y < (ssize_t) image->rows; tile_y+=(ssize_t) tile_height)
+      {
+        register ssize_t
+          tile_x;
+
+        if (status == MagickFalse)
+          continue;
+        for (tile_x=0; tile_x < (ssize_t) image->columns; tile_x+=(ssize_t) tile_width)
+        {
+          MagickBooleanType
+            sync;
+
+          register const Quantum
+            *restrict p;
+
+          register ssize_t
+            y;
+
+          register Quantum
+            *restrict q;
+
+          size_t
+            height,
+            width;
+
+          width=tile_width;
+          if ((tile_x+(ssize_t) tile_width) > (ssize_t) image->columns)
+            width=(size_t) (tile_width-(tile_x+tile_width-
+              image->columns));
+          height=tile_height;
+          if ((tile_y+(ssize_t) tile_height) > (ssize_t) image->rows)
+            height=(size_t) (tile_height-(tile_y+tile_height-
+              image->rows));
+          p=GetCacheViewVirtualPixels(image_view,tile_x,tile_y,width,height,
+            exception);
+          if (p == (const Quantum *) NULL)
+            {
+              status=MagickFalse;
+              break;
+            }
+          for (y=0; y < (ssize_t) width; y++)
+          {
+            register const Quantum
+              *restrict tile_pixels;
+
+            register ssize_t
+              x;
+
+            q=QueueCacheViewAuthenticPixels(rotate_view,(ssize_t)
+              (rotate_image->columns-(tile_y+height)),y+tile_x,height,
+              1,exception);
+            if (q == (const Quantum *) NULL)
+              {
+                status=MagickFalse;
+                break;
+              }
+            tile_pixels=p+((height-1)*width+y)*GetPixelChannels(image);
+            for (x=0; x < (ssize_t) height; x++)
+            {
+              SetPixelRed(rotate_image,GetPixelRed(image,tile_pixels),q);
+              SetPixelGreen(rotate_image,GetPixelGreen(image,tile_pixels),q);
+              SetPixelBlue(rotate_image,GetPixelBlue(image,tile_pixels),q);
+              SetPixelAlpha(rotate_image,GetPixelAlpha(image,tile_pixels),q);
+              tile_pixels-=width*GetPixelChannels(image);
+              q+=GetPixelChannels(rotate_image);
+            }
+            sync=SyncCacheViewAuthenticPixels(rotate_view,exception);
+            if (sync == MagickFalse)
+              status=MagickFalse;
+          }
+        }
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(image,RotateImageTag,progress+=tile_height,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      (void) SetImageProgress(image,RotateImageTag,(MagickOffsetType)
+        image->rows-1,image->rows);
+      Swap(page.width,page.height);
+      Swap(page.x,page.y);
+      if (page.width != 0)
+        page.x=(ssize_t) (page.width-rotate_image->columns-page.x);
+      break;
+    }
+    case 2:
+    {
+      /*
+        Rotate 180 degrees.
+      */
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(static,8) shared(progress,status) omp_throttle(1)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register const Quantum
+          *restrict p;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,
+          exception);
+        q=QueueCacheViewAuthenticPixels(rotate_view,0,(ssize_t) (image->rows-
+          y-1),image->columns,1,exception);
+        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+          {
+            status=MagickFalse;
+            continue;
+          }
+        q+=GetPixelChannels(rotate_image)*image->columns;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          q-=GetPixelChannels(rotate_image);
+          SetPixelRed(rotate_image,GetPixelRed(image,p),q);
+          SetPixelGreen(rotate_image,GetPixelGreen(image,p),q);
+          SetPixelBlue(rotate_image,GetPixelBlue(image,p),q);
+          SetPixelAlpha(rotate_image,GetPixelAlpha(image,p),q);
+          p+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(rotate_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(image,RotateImageTag,progress++,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      if (page.width != 0)
+        page.x=(ssize_t) (page.width-rotate_image->columns-page.x);
+      if (page.height != 0)
+        page.y=(ssize_t) (page.height-rotate_image->rows-page.y);
+      break;
+    }
+    case 3:
+    {
+      size_t
+        tile_height,
+        tile_width;
+
+      ssize_t
+        tile_y;
+
+      /*
+        Rotate 270 degrees.
+      */
+      GetPixelCacheTileSize(image,&tile_width,&tile_height);
+#if defined(MAGICKCORE_OPENMP_SUPPORT) 
+  #pragma omp parallel for schedule(static,1) shared(progress,status) omp_throttle(1)
+#endif
+      for (tile_y=0; tile_y < (ssize_t) image->rows; tile_y+=(ssize_t) tile_height)
+      {
+        register ssize_t
+          tile_x;
+
+        if (status == MagickFalse)
+          continue;
+        for (tile_x=0; tile_x < (ssize_t) image->columns; tile_x+=(ssize_t) tile_width)
+        {
+          MagickBooleanType
+            sync;
+
+          register const Quantum
+            *restrict p;
+
+          register ssize_t
+            y;
+
+          register Quantum
+            *restrict q;
+
+          size_t
+            height,
+            width;
+
+          width=tile_width;
+          if ((tile_x+(ssize_t) tile_width) > (ssize_t) image->columns)
+            width=(size_t) (tile_width-(tile_x+tile_width-
+              image->columns));
+          height=tile_height;
+          if ((tile_y+(ssize_t) tile_height) > (ssize_t) image->rows)
+            height=(size_t) (tile_height-(tile_y+tile_height-
+              image->rows));
+          p=GetCacheViewVirtualPixels(image_view,tile_x,tile_y,width,
+            height,exception);
+          if (p == (const Quantum *) NULL)
+            {
+              status=MagickFalse;
+              break;
+            }
+          for (y=0; y < (ssize_t) width; y++)
+          {
+            register const Quantum
+              *restrict tile_pixels;
+
+            register ssize_t
+              x;
+
+            q=QueueCacheViewAuthenticPixels(rotate_view,tile_y,(ssize_t)
+              (y+rotate_image->rows-(tile_x+width)),height,1,exception);
+            if (q == (const Quantum *) NULL)
+              {
+                status=MagickFalse;
+                break;
+              }
+            tile_pixels=p+((width-1)-y)*GetPixelChannels(image);
+            for (x=0; x < (ssize_t) height; x++)
+            {
+              SetPixelRed(rotate_image,GetPixelRed(image,tile_pixels),q);
+              SetPixelGreen(rotate_image,GetPixelGreen(image,tile_pixels),q);
+              SetPixelBlue(rotate_image,GetPixelBlue(image,tile_pixels),q);
+              SetPixelAlpha(rotate_image,GetPixelAlpha(image,tile_pixels),q);
+              tile_pixels+=width*GetPixelChannels(image);
+              q+=GetPixelChannels(rotate_image);
+            }
+            sync=SyncCacheViewAuthenticPixels(rotate_view,exception);
+            if (sync == MagickFalse)
+              status=MagickFalse;
+          }
+        }
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+            proceed=SetImageProgress(image,RotateImageTag,progress+=tile_height,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      (void) SetImageProgress(image,RotateImageTag,(MagickOffsetType)
+        image->rows-1,image->rows);
+      Swap(page.width,page.height);
+      Swap(page.x,page.y);
+      if (page.height != 0)
+        page.y=(ssize_t) (page.height-rotate_image->rows-page.y);
+      break;
+    }
+  }
+  rotate_view=DestroyCacheView(rotate_view);
+  image_view=DestroyCacheView(image_view);
+  rotate_image->type=image->type;
+  rotate_image->page=page;
+  if (status == MagickFalse)
+    rotate_image=DestroyImage(rotate_image);
+  return(rotate_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S h e a r I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XShearImage() shears the image in the X direction with a shear angle of
+%  'degrees'.  Positive angles shear counter-clockwise (right-hand rule), and
+%  negative angles shear clockwise.  Angles are measured relative to a vertical
+%  Y-axis.  X shears will widen an image creating 'empty' triangles on the left
+%  and right sides of the source image.
+%
+%  The format of the XShearImage method is:
+%
+%      MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
+%        const size_t width,const size_t height,
+%        const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o degrees: A MagickRealType representing the shearing angle along the X
+%      axis.
+%
+%    o width, height, x_offset, y_offset: Defines a region of the image
+%      to shear.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
+  const size_t width,const size_t height,const ssize_t x_offset,
+  const ssize_t y_offset,ExceptionInfo *exception)
+{
+#define XShearImageTag  "XShear/Image"
+
+  typedef enum
+  {
+    LEFT,
+    RIGHT
+  } ShearDirection;
+
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    background;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  GetPixelInfo(image,&background);
+  SetPixelInfoPacket(image,&image->background_color,&background);
+  if (image->colorspace == CMYKColorspace)
+    ConvertRGBToCMYK(&background);
+  /*
+    X shear image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress, status)
+#endif
+  for (y=0; y < (ssize_t) height; y++)
+  {
+    PixelInfo
+      pixel,
+      source,
+      destination;
+
+    MagickRealType
+      area,
+      displacement;
+
+    register Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i;
+
+    ShearDirection
+      direction;
+
+    ssize_t
+      step;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewAuthenticPixels(image_view,0,y_offset+y,image->columns,1,
+      exception);
+    if (p == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    p+=x_offset*GetPixelChannels(image);
+    displacement=degrees*(MagickRealType) (y-height/2.0);
+    if (displacement == 0.0)
+      continue;
+    if (displacement > 0.0)
+      direction=RIGHT;
+    else
+      {
+        displacement*=(-1.0);
+        direction=LEFT;
+      }
+    step=(ssize_t) floor((double) displacement);
+    area=(MagickRealType) (displacement-step);
+    step++;
+    pixel=background;
+    GetPixelInfo(image,&source);
+    GetPixelInfo(image,&destination);
+    switch (direction)
+    {
+      case LEFT:
+      {
+        /*
+          Transfer pixels left-to-right.
+        */
+        if (step > x_offset)
+          break;
+        q=p-step*GetPixelChannels(image);
+        for (i=0; i < (ssize_t) width; i++)
+        {
+          if ((x_offset+i) < step)
+            {
+              p+=GetPixelChannels(image);
+              SetPixelInfo(image,p,&pixel);
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          SetPixelInfo(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+            &source,(MagickRealType) GetPixelAlpha(image,p),area,
+            &destination);
+          SetPixelPixelInfo(image,&destination,q);
+          SetPixelInfo(image,p,&pixel);
+          p+=GetPixelChannels(image);
+          q+=GetPixelChannels(image);
+        }
+        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+          &background,(MagickRealType) background.alpha,area,&destination);
+        SetPixelPixelInfo(image,&destination,q);
+        q+=GetPixelChannels(image);
+        for (i=0; i < (step-1); i++)
+        {
+          SetPixelPixelInfo(image,&background,q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case RIGHT:
+      {
+        /*
+          Transfer pixels right-to-left.
+        */
+        p+=width*GetPixelChannels(image);
+        q=p+step*GetPixelChannels(image);
+        for (i=0; i < (ssize_t) width; i++)
+        {
+          p-=GetPixelChannels(image);
+          q-=GetPixelChannels(image);
+          if ((size_t) (x_offset+width+step-i) >= image->columns)
+            continue;
+          SetPixelInfo(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+            &source,(MagickRealType) GetPixelAlpha(image,p),area,
+            &destination);
+          SetPixelPixelInfo(image,&destination,q);
+          SetPixelInfo(image,p,&pixel);
+        }
+        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+          &background,(MagickRealType) background.alpha,area,&destination);
+        q-=GetPixelChannels(image);
+        SetPixelPixelInfo(image,&destination,q);
+        for (i=0; i < (step-1); i++)
+        {
+          q-=GetPixelChannels(image);
+          SetPixelPixelInfo(image,&background,q);
+        }
+        break;
+      }
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_XShearImage)
+#endif
+        proceed=SetImageProgress(image,XShearImageTag,progress++,height);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   Y S h e a r I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  YShearImage shears the image in the Y direction with a shear angle of
+%  'degrees'.  Positive angles shear counter-clockwise (right-hand rule), and
+%  negative angles shear clockwise.  Angles are measured relative to a
+%  horizontal X-axis.  Y shears will increase the height of an image creating
+%  'empty' triangles on the top and bottom of the source image.
+%
+%  The format of the YShearImage method is:
+%
+%      MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
+%        const size_t width,const size_t height,
+%        const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o degrees: A MagickRealType representing the shearing angle along the Y
+%      axis.
+%
+%    o width, height, x_offset, y_offset: Defines a region of the image
+%      to shear.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
+  const size_t width,const size_t height,const ssize_t x_offset,
+  const ssize_t y_offset,ExceptionInfo *exception)
+{
+#define YShearImageTag  "YShear/Image"
+
+  typedef enum
+  {
+    UP,
+    DOWN
+  } ShearDirection;
+
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    background;
+
+  ssize_t
+    x;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  GetPixelInfo(image,&background);
+  SetPixelInfoPacket(image,&image->background_color,&background);
+  if (image->colorspace == CMYKColorspace)
+    ConvertRGBToCMYK(&background);
+  /*
+    Y Shear image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress, status)
+#endif
+  for (x=0; x < (ssize_t) width; x++)
+  {
+    ssize_t
+      step;
+
+    MagickRealType
+      area,
+      displacement;
+
+    PixelInfo
+      pixel,
+      source,
+      destination;
+
+    register Quantum
+      *restrict p,
+      *restrict q;
+
+    register ssize_t
+      i;
+
+    ShearDirection
+      direction;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewAuthenticPixels(image_view,x_offset+x,0,1,image->rows,
+      exception);
+    if (p == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    p+=y_offset*GetPixelChannels(image);
+    displacement=degrees*(MagickRealType) (x-width/2.0);
+    if (displacement == 0.0)
+      continue;
+    if (displacement > 0.0)
+      direction=DOWN;
+    else
+      {
+        displacement*=(-1.0);
+        direction=UP;
+      }
+    step=(ssize_t) floor((double) displacement);
+    area=(MagickRealType) (displacement-step);
+    step++;
+    pixel=background;
+    GetPixelInfo(image,&source);
+    GetPixelInfo(image,&destination);
+    switch (direction)
+    {
+      case UP:
+      {
+        /*
+          Transfer pixels top-to-bottom.
+        */
+        if (step > y_offset)
+          break;
+        q=p-step*GetPixelChannels(image);
+        for (i=0; i < (ssize_t) height; i++)
+        {
+          if ((y_offset+i) < step)
+            {
+              p+=GetPixelChannels(image);
+              SetPixelInfo(image,p,&pixel);
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          SetPixelInfo(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+            &source,(MagickRealType) GetPixelAlpha(image,p),area,
+            &destination);
+          SetPixelPixelInfo(image,&destination,q);
+          SetPixelInfo(image,p,&pixel);
+          p+=GetPixelChannels(image);
+          q+=GetPixelChannels(image);
+        }
+        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+          &background,(MagickRealType) background.alpha,area,&destination);
+        SetPixelPixelInfo(image,&destination,q);
+        q+=GetPixelChannels(image);
+        for (i=0; i < (step-1); i++)
+        {
+          SetPixelPixelInfo(image,&background,q);
+          q+=GetPixelChannels(image);
+        }
+        break;
+      }
+      case DOWN:
+      {
+        /*
+          Transfer pixels bottom-to-top.
+        */
+        p+=height*GetPixelChannels(image);
+        q=p+step*GetPixelChannels(image);
+        for (i=0; i < (ssize_t) height; i++)
+        {
+          p-=GetPixelChannels(image);
+          q-=GetPixelChannels(image);
+          if ((size_t) (y_offset+height+step-i) >= image->rows)
+            continue;
+          SetPixelInfo(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+            &source,(MagickRealType) GetPixelAlpha(image,p),area,
+            &destination);
+          SetPixelPixelInfo(image,&destination,q);
+          SetPixelInfo(image,p,&pixel);
+        }
+        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
+          &background,(MagickRealType) background.alpha,area,&destination);
+        q-=GetPixelChannels(image);
+        SetPixelPixelInfo(image,&destination,q);
+        for (i=0; i < (step-1); i++)
+        {
+          q-=GetPixelChannels(image);
+          SetPixelPixelInfo(image,&background,q);
+        }
+        break;
+      }
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_YShearImage)
+#endif
+        proceed=SetImageProgress(image,YShearImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R o t a t e I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RotateImage() creates a new image that is a rotated copy of an existing
+%  one.  Positive angles rotate counter-clockwise (right-hand rule), while
+%  negative angles rotate clockwise.  Rotated images are usually larger than
+%  the originals and have 'empty' triangular corners.  X axis.  Empty
+%  triangles left over from shearing the image are filled with the background
+%  color defined by member 'background_color' of the image.  RotateImage
+%  allocates the memory necessary for the new Image structure and returns a
+%  pointer to the new image.
+%
+%  RotateImage() is based on the paper "A Fast Algorithm for General
+%  Raster Rotatation" by Alan W. Paeth.  RotateImage is adapted from a similar
+%  method based on the Paeth paper written by Michael Halle of the Spatial
+%  Imaging Group, MIT Media Lab.
+%
+%  The format of the RotateImage method is:
+%
+%      Image *RotateImage(const Image *image,const double degrees,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o degrees: Specifies the number of degrees to rotate the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *RotateImage(const Image *image,const double degrees,
+  ExceptionInfo *exception)
+{
+  Image
+    *integral_image,
+    *rotate_image;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    angle;
+
+  PointInfo
+    shear;
+
+  RectangleInfo
+    border_info;
+
+  size_t
+    height,
+    rotations,
+    width,
+    y_width;
+
+  ssize_t
+    x_offset,
+    y_offset;
+
+  /*
+    Adjust rotation angle.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  angle=degrees;
+  while (angle < -45.0)
+    angle+=360.0;
+  for (rotations=0; angle > 45.0; rotations++)
+    angle-=90.0;
+  rotations%=4;
+  /*
+    Calculate shear equations.
+  */
+  integral_image=IntegralRotateImage(image,rotations,exception);
+  if (integral_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  shear.x=(-tan((double) DegreesToRadians(angle)/2.0));
+  shear.y=sin((double) DegreesToRadians(angle));
+  if ((shear.x == 0.0) && (shear.y == 0.0))
+    return(integral_image);
+  if (SetImageStorageClass(integral_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&integral_image->exception);
+      integral_image=DestroyImage(integral_image);
+      return(integral_image);
+    }
+  if (integral_image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(integral_image,OpaqueAlphaChannel);
+  /*
+    Compute image size.
+  */
+  width=image->columns;
+  height=image->rows;
+  if ((rotations == 1) || (rotations == 3))
+    {
+      width=image->rows;
+      height=image->columns;
+    }
+  y_width=width+(ssize_t) floor(fabs(shear.x)*height+0.5);
+  x_offset=(ssize_t) ceil((double) width+((fabs(shear.y)*height)-width)/2.0-
+    0.5);
+  y_offset=(ssize_t) ceil((double) height+((fabs(shear.y)*y_width)-height)/2.0-
+    0.5);
+  /*
+    Surround image with a border.
+  */
+  integral_image->border_color=integral_image->background_color;
+  integral_image->compose=CopyCompositeOp;
+  border_info.width=(size_t) x_offset;
+  border_info.height=(size_t) y_offset;
+  rotate_image=BorderImage(integral_image,&border_info,exception);
+  integral_image=DestroyImage(integral_image);
+  if (rotate_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  /*
+    Rotate the image.
+  */
+  status=XShearImage(rotate_image,shear.x,width,height,x_offset,(ssize_t)
+    (rotate_image->rows-height)/2,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  status=YShearImage(rotate_image,shear.y,y_width,height,(ssize_t)
+    (rotate_image->columns-y_width)/2,y_offset,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  status=XShearImage(rotate_image,shear.x,y_width,rotate_image->rows,(ssize_t)
+    (rotate_image->columns-y_width)/2,0,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  status=CropToFitImage(&rotate_image,shear.x,shear.y,(MagickRealType) width,
+    (MagickRealType) height,MagickTrue,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  rotate_image->compose=image->compose;
+  rotate_image->page.width=0;
+  rotate_image->page.height=0;
+  return(rotate_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S h e a r I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShearImage() creates a new image that is a shear_image copy of an existing
+%  one.  Shearing slides one edge of an image along the X or Y axis, creating
+%  a parallelogram.  An X direction shear slides an edge along the X axis,
+%  while a Y direction shear slides an edge along the Y axis.  The amount of
+%  the shear is controlled by a shear angle.  For X direction shears, x_shear
+%  is measured relative to the Y axis, and similarly, for Y direction shears
+%  y_shear is measured relative to the X axis.  Empty triangles left over from
+%  shearing the image are filled with the background color defined by member
+%  'background_color' of the image..  ShearImage() allocates the memory
+%  necessary for the new Image structure and returns a pointer to the new image.
+%
+%  ShearImage() is based on the paper "A Fast Algorithm for General Raster
+%  Rotatation" by Alan W. Paeth.
+%
+%  The format of the ShearImage method is:
+%
+%      Image *ShearImage(const Image *image,const double x_shear,
+%        const double y_shear,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o x_shear, y_shear: Specifies the number of degrees to shear the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ShearImage(const Image *image,const double x_shear,
+  const double y_shear,ExceptionInfo *exception)
+{
+  Image
+    *integral_image,
+    *shear_image;
+
+  ssize_t
+    x_offset,
+    y_offset;
+
+  MagickBooleanType
+    status;
+
+  PointInfo
+    shear;
+
+  RectangleInfo
+    border_info;
+
+  size_t
+    y_width;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if ((x_shear != 0.0) && (fmod(x_shear,90.0) == 0.0))
+    ThrowImageException(ImageError,"AngleIsDiscontinuous");
+  if ((y_shear != 0.0) && (fmod(y_shear,90.0) == 0.0))
+    ThrowImageException(ImageError,"AngleIsDiscontinuous");
+  /*
+    Initialize shear angle.
+  */
+  integral_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (integral_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  shear.x=(-tan(DegreesToRadians(fmod(x_shear,360.0))));
+  shear.y=tan(DegreesToRadians(fmod(y_shear,360.0)));
+  if ((shear.x == 0.0) && (shear.y == 0.0))
+    return(integral_image);
+  if (SetImageStorageClass(integral_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&integral_image->exception);
+      integral_image=DestroyImage(integral_image);
+      return(integral_image);
+    }
+  if (integral_image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(integral_image,OpaqueAlphaChannel);
+  /*
+    Compute image size.
+  */
+  y_width=image->columns+(ssize_t) floor(fabs(shear.x)*image->rows+0.5);
+  x_offset=(ssize_t) ceil((double) image->columns+((fabs(shear.x)*image->rows)-
+    image->columns)/2.0-0.5);
+  y_offset=(ssize_t) ceil((double) image->rows+((fabs(shear.y)*y_width)-
+    image->rows)/2.0-0.5);
+  /*
+    Surround image with border.
+  */
+  integral_image->border_color=integral_image->background_color;
+  integral_image->compose=CopyCompositeOp;
+  border_info.width=(size_t) x_offset;
+  border_info.height=(size_t) y_offset;
+  shear_image=BorderImage(integral_image,&border_info,exception);
+  integral_image=DestroyImage(integral_image);
+  if (shear_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  /*
+    Shear the image.
+  */
+  if (shear_image->matte == MagickFalse)
+    (void) SetImageAlphaChannel(shear_image,OpaqueAlphaChannel);
+  status=XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset,
+    (ssize_t) (shear_image->rows-image->rows)/2,exception);
+  if (status == MagickFalse)
+    {
+      shear_image=DestroyImage(shear_image);
+      return((Image *) NULL);
+    }
+  status=YShearImage(shear_image,shear.y,y_width,image->rows,(ssize_t)
+    (shear_image->columns-y_width)/2,y_offset,exception);
+  if (status == MagickFalse)
+    {
+      shear_image=DestroyImage(shear_image);
+      return((Image *) NULL);
+    }
+  status=CropToFitImage(&shear_image,shear.x,shear.y,(MagickRealType)
+    image->columns,(MagickRealType) image->rows,MagickFalse,exception);
+  if (status == MagickFalse)
+    {
+      shear_image=DestroyImage(shear_image);
+      return((Image *) NULL);
+    }
+  shear_image->compose=image->compose;
+  shear_image->page.width=0;
+  shear_image->page.height=0;
+  return(shear_image);
+}
diff --git a/MagickCore/shear.h b/MagickCore/shear.h
new file mode 100644
index 0000000..3d8a2c3
--- /dev/null
+++ b/MagickCore/shear.h
@@ -0,0 +1,35 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image stream methods.
+*/
+#ifndef _MAGICKCORE_SHEAR_H
+#define _MAGICKCORE_SHEAR_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport Image
+  *AffineTransformImage(const Image *,const AffineMatrix *,ExceptionInfo *),
+  *DeskewImage(const Image *,const double,ExceptionInfo *),
+  *RotateImage(const Image *,const double,ExceptionInfo *),
+  *ShearImage(const Image *,const double,const double,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/signature-private.h b/MagickCore/signature-private.h
new file mode 100644
index 0000000..2171e17
--- /dev/null
+++ b/MagickCore/signature-private.h
@@ -0,0 +1,56 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore digital signature methods.
+*/
+#ifndef _MAGICKCORE_SIGNATURE_PRIVATE_H
+#define _MAGICKCORE_SIGNATURE_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MagickSignatureSize  64
+
+#include <MagickCore/string_.h>
+
+typedef struct _SignatureInfo
+  SignatureInfo;
+
+extern MagickExport MagickBooleanType
+  SignatureImage(Image *);
+
+extern MagickExport SignatureInfo
+  *AcquireSignatureInfo(void),
+  *DestroySignatureInfo(SignatureInfo *);
+
+extern MagickExport const StringInfo
+  *GetSignatureDigest(const SignatureInfo *);
+
+extern MagickExport unsigned int
+  GetSignatureBlocksize(const SignatureInfo *),
+  GetSignatureDigestsize(const SignatureInfo *);
+
+extern MagickExport void
+  InitializeSignature(SignatureInfo *),
+  FinalizeSignature(SignatureInfo *),
+  SetSignatureDigest(SignatureInfo *,const StringInfo *),
+  UpdateSignature(SignatureInfo *,const StringInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/signature.c b/MagickCore/signature.c
new file mode 100644
index 0000000..52345bb
--- /dev/null
+++ b/MagickCore/signature.c
@@ -0,0 +1,821 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%        SSSSS  IIIII   GGGG  N   N   AAA   TTTTT  U   U  RRRR   EEEEE        %
+%        SS       I    G      NN  N  A   A    T    U   U  R   R  E            %
+%         SSS     I    G  GG  N N N  AAAAA    T    U   U  RRRR   EEE          %
+%           SS    I    G   G  N  NN  A   A    T    U   U  R R    E            %
+%        SSSSS  IIIII   GGG   N   N  A   A    T     UUU   R  R   EEEEE        %
+%                                                                             %
+%                                                                             %
+%         MagickCore Methods to Compute a Message Digest for an Image         %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                              December 1992                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/property.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/signature.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+/*
+  Define declarations.
+*/
+#define SignatureBlocksize  64
+#define SignatureDigestsize  32
+
+/*
+  Typedef declarations.
+*/
+struct _SignatureInfo
+{
+  unsigned int
+    digestsize,
+    blocksize;
+
+  StringInfo
+    *digest,
+    *message;
+
+  unsigned int
+    *accumulator,
+    low_order,
+    high_order;
+
+  size_t
+    offset;
+
+  MagickBooleanType
+    lsb_first;
+
+  ssize_t
+    timestamp;
+
+  size_t
+    signature;
+};
+
+/*
+  Forward declarations.
+*/
+static void
+  TransformSignature(SignatureInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e S i g n a t u r e I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireSignatureInfo() allocate the SignatureInfo structure.
+%
+%  The format of the AcquireSignatureInfo method is:
+%
+%      SignatureInfo *AcquireSignatureInfo(void)
+%
+*/
+MagickExport SignatureInfo *AcquireSignatureInfo(void)
+{
+  SignatureInfo
+    *signature_info;
+
+  unsigned int
+    lsb_first;
+
+  signature_info=(SignatureInfo *) AcquireMagickMemory(sizeof(*signature_info));
+  if (signature_info == (SignatureInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(signature_info,0,sizeof(*signature_info));
+  signature_info->digestsize=SignatureDigestsize;
+  signature_info->blocksize=SignatureBlocksize;
+  signature_info->digest=AcquireStringInfo(SignatureDigestsize);
+  signature_info->message=AcquireStringInfo(SignatureBlocksize);
+  signature_info->accumulator=(unsigned int *) AcquireQuantumMemory(
+    SignatureBlocksize,sizeof(*signature_info->accumulator));
+  if (signature_info->accumulator == (unsigned int *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  lsb_first=1;
+  signature_info->lsb_first=(int) (*(char *) &lsb_first) == 1 ? MagickTrue :
+    MagickFalse;
+  signature_info->timestamp=(ssize_t) time(0);
+  signature_info->signature=MagickSignature;
+  InitializeSignature(signature_info);
+  return(signature_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y S i g n a t u r e I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroySignatureInfo() zeros memory associated with the SignatureInfo
+%  structure.
+%
+%  The format of the DestroySignatureInfo method is:
+%
+%      SignatureInfo *DestroySignatureInfo(SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the cipher signature_info.
+%
+*/
+MagickExport SignatureInfo *DestroySignatureInfo(SignatureInfo *signature_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  if (signature_info->accumulator != (unsigned int *) NULL)
+    signature_info->accumulator=(unsigned int *) RelinquishMagickMemory(
+      signature_info->accumulator);
+  if (signature_info->message != (StringInfo *) NULL)
+    signature_info->message=DestroyStringInfo(signature_info->message);
+  if (signature_info->digest != (StringInfo *) NULL)
+    signature_info->digest=DestroyStringInfo(signature_info->digest);
+  signature_info->signature=(~MagickSignature);
+  signature_info=(SignatureInfo *) RelinquishMagickMemory(signature_info);
+  return(signature_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   F i n a l i z e S i g n a t u r e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FinalizeSignature() finalizes the Signature message accumulator computation.
+%
+%  The format of the FinalizeSignature method is:
+%
+%      FinalizeSignature(SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the address of a structure of type SignatureInfo.
+%
+*/
+MagickExport void FinalizeSignature(SignatureInfo *signature_info)
+{
+  register ssize_t
+    i;
+
+  register unsigned char
+    *q;
+
+  register unsigned int
+    *p;
+
+  unsigned char
+    *datum;
+
+  unsigned int
+    count,
+    high_order,
+    low_order;
+
+  /*
+    Add padding and return the message accumulator.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  low_order=signature_info->low_order;
+  high_order=signature_info->high_order;
+  count=((low_order >> 3) & 0x3f);
+  datum=GetStringInfoDatum(signature_info->message);
+  datum[count++]=(unsigned char) 0x80;
+  if (count <= (unsigned int) (GetStringInfoLength(signature_info->message)-8))
+    (void) ResetMagickMemory(datum+count,0,GetStringInfoLength(
+      signature_info->message)-8-count);
+  else
+    {
+      (void) ResetMagickMemory(datum+count,0,GetStringInfoLength(
+        signature_info->message)-count);
+      TransformSignature(signature_info);
+      (void) ResetMagickMemory(datum,0,GetStringInfoLength(
+        signature_info->message)-8);
+    }
+  datum[56]=(unsigned char) (high_order >> 24);
+  datum[57]=(unsigned char) (high_order >> 16);
+  datum[58]=(unsigned char) (high_order >> 8);
+  datum[59]=(unsigned char) high_order;
+  datum[60]=(unsigned char) (low_order >> 24);
+  datum[61]=(unsigned char) (low_order >> 16);
+  datum[62]=(unsigned char) (low_order >> 8);
+  datum[63]=(unsigned char) low_order;
+  TransformSignature(signature_info);
+  p=signature_info->accumulator;
+  q=GetStringInfoDatum(signature_info->digest);
+  for (i=0; i < (SignatureDigestsize/4); i++)
+  {
+    *q++=(unsigned char) ((*p >> 24) & 0xff);
+    *q++=(unsigned char) ((*p >> 16) & 0xff);
+    *q++=(unsigned char) ((*p >> 8) & 0xff);
+    *q++=(unsigned char) (*p & 0xff);
+    p++;
+  }
+  /*
+    Reset working registers.
+  */
+  count=0;
+  high_order=0;
+  low_order=0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t S i g n a t u r e B l o c k s i z e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetSignatureBlocksize() returns the Signature blocksize.
+%
+%  The format of the GetSignatureBlocksize method is:
+%
+%      unsigned int *GetSignatureBlocksize(const SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the signature info.
+%
+*/
+MagickExport unsigned int GetSignatureBlocksize(
+  const SignatureInfo *signature_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  return(signature_info->blocksize);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t S i g n a t u r e D i g e s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetSignatureDigest() returns the signature digest.
+%
+%  The format of the GetSignatureDigest method is:
+%
+%      const StringInfo *GetSignatureDigest(const SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the signature info.
+%
+*/
+MagickExport const StringInfo *GetSignatureDigest(
+  const SignatureInfo *signature_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  return(signature_info->digest);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t S i g n a t u r e D i g e s t s i z e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetSignatureDigestsize() returns the Signature digest size.
+%
+%  The format of the GetSignatureDigestsize method is:
+%
+%      unsigned int *GetSignatureDigestsize(const SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the signature info.
+%
+*/
+MagickExport unsigned int GetSignatureDigestsize(
+  const SignatureInfo *signature_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  return(signature_info->digestsize);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e S i g n a t u r e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeSignature() initializes the Signature accumulator.
+%
+%  The format of the DestroySignatureInfo method is:
+%
+%      void InitializeSignatureInfo(SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the cipher signature_info.
+%
+*/
+MagickExport void InitializeSignature(SignatureInfo *signature_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  signature_info->accumulator[0]=0x6a09e667U;
+  signature_info->accumulator[1]=0xbb67ae85U;
+  signature_info->accumulator[2]=0x3c6ef372U;
+  signature_info->accumulator[3]=0xa54ff53aU;
+  signature_info->accumulator[4]=0x510e527fU;
+  signature_info->accumulator[5]=0x9b05688cU;
+  signature_info->accumulator[6]=0x1f83d9abU;
+  signature_info->accumulator[7]=0x5be0cd19U;
+  signature_info->low_order=0;
+  signature_info->high_order=0;
+  signature_info->offset=0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t S i g n a t u r e D i g e s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetSignatureDigest() set the signature digest.
+%
+%  The format of the SetSignatureDigest method is:
+%
+%      SetSignatureDigest(SignatureInfo *signature_info,
+%        const StringInfo *digest)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the signature info.
+%
+%    o digest: the digest.
+%
+*/
+MagickExport void SetSignatureDigest(SignatureInfo *signature_info,
+  const StringInfo *digest)
+{
+  /*
+    Set the signature accumulator.
+  */
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  SetStringInfo(signature_info->digest,digest);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S i g n a t u r e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SignatureImage() computes a message digest from an image pixel stream with
+%  an implementation of the NIST SHA-256 Message Digest algorithm.  This
+%  signature uniquely identifies the image and is convenient for determining
+%  if an image has been modified or whether two images are identical.
+%
+%  The format of the SignatureImage method is:
+%
+%      MagickBooleanType SignatureImage(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType SignatureImage(Image *image)
+{
+  CacheView
+    *image_view;
+
+  char
+    *hex_signature;
+
+  ExceptionInfo
+    *exception;
+
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    quantum_type;
+
+  register const Quantum
+    *p;
+
+  SignatureInfo
+    *signature_info;
+
+  size_t
+    length;
+
+  ssize_t
+    y;
+
+  StringInfo
+    *signature;
+
+  unsigned char
+    *pixels;
+
+  /*
+    Compute image digital signature.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
+  if (quantum_info == (QuantumInfo *) NULL)
+    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+      image->filename);
+  quantum_type=RGBQuantum;
+  if (image->matte != MagickFalse)
+    quantum_type=RGBAQuantum;
+  if (image->colorspace == CMYKColorspace)
+    {
+      quantum_type=CMYKQuantum;
+      if (image->matte != MagickFalse)
+        quantum_type=CMYKAQuantum;
+    }
+  signature_info=AcquireSignatureInfo();
+  signature=AcquireStringInfo(quantum_info->extent);
+  pixels=GetQuantumPixels(quantum_info);
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
+      pixels,&image->exception);
+    SetStringInfoLength(signature,length);
+    SetStringInfoDatum(signature,pixels);
+    UpdateSignature(signature_info,signature);
+  }
+  image_view=DestroyCacheView(image_view);
+  quantum_info=DestroyQuantumInfo(quantum_info);
+  FinalizeSignature(signature_info);
+  hex_signature=StringInfoToHexString(GetSignatureDigest(signature_info));
+  (void) DeleteImageProperty(image,"signature");
+  (void) SetImageProperty(image,"signature",hex_signature);
+  /*
+    Free resources.
+  */
+  hex_signature=DestroyString(hex_signature);
+  signature=DestroyStringInfo(signature);
+  signature_info=DestroySignatureInfo(signature_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   T r a n s f o r m S i g n a t u r e                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformSignature() transforms the Signature message accumulator.
+%
+%  The format of the TransformSignature method is:
+%
+%      TransformSignature(SignatureInfo *signature_info)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the address of a structure of type SignatureInfo.
+%
+*/
+
+static inline unsigned int Ch(unsigned int x,unsigned int y,unsigned int z)
+{
+  return((x & y) ^ (~x & z));
+}
+
+static inline unsigned int Maj(unsigned int x,unsigned int y,unsigned int z)
+{
+  return((x & y) ^ (x & z) ^ (y & z));
+}
+
+static inline unsigned int Trunc32(unsigned int x)
+{
+  return((unsigned int) (x & 0xffffffffU));
+}
+
+static unsigned int RotateRight(unsigned int x,unsigned int n)
+{
+  return(Trunc32((x >> n) | (x << (32-n))));
+}
+
+static void TransformSignature(SignatureInfo *signature_info)
+{
+#define Sigma0(x)  (RotateRight(x,7) ^ RotateRight(x,18) ^ Trunc32((x) >> 3))
+#define Sigma1(x)  (RotateRight(x,17) ^ RotateRight(x,19) ^ Trunc32((x) >> 10))
+#define Suma0(x)  (RotateRight(x,2) ^ RotateRight(x,13) ^ RotateRight(x,22))
+#define Suma1(x)  (RotateRight(x,6) ^ RotateRight(x,11) ^ RotateRight(x,25))
+
+  register ssize_t
+    i;
+
+  register unsigned char
+    *p;
+
+  ssize_t
+    j;
+
+  static unsigned int
+    K[64] =
+    {
+      0x428a2f98U, 0x71374491U, 0xb5c0fbcfU, 0xe9b5dba5U, 0x3956c25bU,
+      0x59f111f1U, 0x923f82a4U, 0xab1c5ed5U, 0xd807aa98U, 0x12835b01U,
+      0x243185beU, 0x550c7dc3U, 0x72be5d74U, 0x80deb1feU, 0x9bdc06a7U,
+      0xc19bf174U, 0xe49b69c1U, 0xefbe4786U, 0x0fc19dc6U, 0x240ca1ccU,
+      0x2de92c6fU, 0x4a7484aaU, 0x5cb0a9dcU, 0x76f988daU, 0x983e5152U,
+      0xa831c66dU, 0xb00327c8U, 0xbf597fc7U, 0xc6e00bf3U, 0xd5a79147U,
+      0x06ca6351U, 0x14292967U, 0x27b70a85U, 0x2e1b2138U, 0x4d2c6dfcU,
+      0x53380d13U, 0x650a7354U, 0x766a0abbU, 0x81c2c92eU, 0x92722c85U,
+      0xa2bfe8a1U, 0xa81a664bU, 0xc24b8b70U, 0xc76c51a3U, 0xd192e819U,
+      0xd6990624U, 0xf40e3585U, 0x106aa070U, 0x19a4c116U, 0x1e376c08U,
+      0x2748774cU, 0x34b0bcb5U, 0x391c0cb3U, 0x4ed8aa4aU, 0x5b9cca4fU,
+      0x682e6ff3U, 0x748f82eeU, 0x78a5636fU, 0x84c87814U, 0x8cc70208U,
+      0x90befffaU, 0xa4506cebU, 0xbef9a3f7U, 0xc67178f2U
+    };  /* 32-bit fractional part of the cube root of the first 64 primes */
+
+  unsigned int
+    A,
+    B,
+    C,
+    D,
+    E,
+    F,
+    G,
+    H,
+    shift,
+    T,
+    T1,
+    T2,
+    W[64];
+
+  shift=32;
+  p=GetStringInfoDatum(signature_info->message);
+  if (signature_info->lsb_first == MagickFalse)
+    {
+      if (sizeof(unsigned int) <= 4)
+        for (i=0; i < 16; i++)
+        {
+          T=(*((unsigned int *) p));
+          p+=4;
+          W[i]=Trunc32(T);
+        }
+      else
+        for (i=0; i < 16; i+=2)
+        {
+          T=(*((unsigned int *) p));
+          p+=8;
+          W[i]=Trunc32(T >> shift);
+          W[i+1]=Trunc32(T);
+        }
+    }
+  else
+    if (sizeof(unsigned int) <= 4)
+      for (i=0; i < 16; i++)
+      {
+        T=(*((unsigned int *) p));
+        p+=4;
+        W[i]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
+          ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+      }
+    else
+      for (i=0; i < 16; i+=2)
+      {
+        T=(*((unsigned int *) p));
+        p+=8;
+        W[i]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
+          ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+        T>>=shift;
+        W[i+1]=((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
+          ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
+      }
+  /*
+    Copy accumulator to registers.
+  */
+  A=signature_info->accumulator[0];
+  B=signature_info->accumulator[1];
+  C=signature_info->accumulator[2];
+  D=signature_info->accumulator[3];
+  E=signature_info->accumulator[4];
+  F=signature_info->accumulator[5];
+  G=signature_info->accumulator[6];
+  H=signature_info->accumulator[7];
+  for (i=16; i < 64; i++)
+    W[i]=Trunc32(Sigma1(W[i-2])+W[i-7]+Sigma0(W[i-15])+W[i-16]);
+  for (j=0; j < 64; j++)
+  {
+    T1=Trunc32(H+Suma1(E)+Ch(E,F,G)+K[j]+W[j]);
+    T2=Trunc32(Suma0(A)+Maj(A,B,C));
+    H=G;
+    G=F;
+    F=E;
+    E=Trunc32(D+T1);
+    D=C;
+    C=B;
+    B=A;
+    A=Trunc32(T1+T2);
+  }
+  /*
+    Add registers back to accumulator.
+  */
+  signature_info->accumulator[0]=Trunc32(signature_info->accumulator[0]+A);
+  signature_info->accumulator[1]=Trunc32(signature_info->accumulator[1]+B);
+  signature_info->accumulator[2]=Trunc32(signature_info->accumulator[2]+C);
+  signature_info->accumulator[3]=Trunc32(signature_info->accumulator[3]+D);
+  signature_info->accumulator[4]=Trunc32(signature_info->accumulator[4]+E);
+  signature_info->accumulator[5]=Trunc32(signature_info->accumulator[5]+F);
+  signature_info->accumulator[6]=Trunc32(signature_info->accumulator[6]+G);
+  signature_info->accumulator[7]=Trunc32(signature_info->accumulator[7]+H);
+  /*
+    Reset working registers.
+  */
+  A=0;
+  B=0;
+  C=0;
+  D=0;
+  E=0;
+  F=0;
+  G=0;
+  H=0;
+  T=0;
+  T1=0;
+  T2=0;
+  (void) ResetMagickMemory(W,0,sizeof(W));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   U p d a t e S i g n a t u r e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UpdateSignature() updates the Signature message accumulator.
+%
+%  The format of the UpdateSignature method is:
+%
+%      UpdateSignature(SignatureInfo *signature_info,const StringInfo *message)
+%
+%  A description of each parameter follows:
+%
+%    o signature_info: the address of a structure of type SignatureInfo.
+%
+%    o message: the message.
+%
+*/
+MagickExport void UpdateSignature(SignatureInfo *signature_info,
+  const StringInfo *message)
+{
+  register size_t
+    i;
+
+  register unsigned char
+    *p;
+
+  size_t
+    n;
+
+  unsigned int
+    length;
+
+  /*
+    Update the Signature accumulator.
+  */
+  assert(signature_info != (SignatureInfo *) NULL);
+  assert(signature_info->signature == MagickSignature);
+  n=GetStringInfoLength(message);
+  length=Trunc32((unsigned int) (signature_info->low_order+(n << 3)));
+  if (length < signature_info->low_order)
+    signature_info->high_order++;
+  signature_info->low_order=length;
+  signature_info->high_order+=(unsigned int) (n >> 29);
+  p=GetStringInfoDatum(message);
+  if (signature_info->offset != 0)
+    {
+      i=GetStringInfoLength(signature_info->message)-signature_info->offset;
+      if (i > n)
+        i=n;
+      (void) CopyMagickMemory(GetStringInfoDatum(signature_info->message)+
+        signature_info->offset,p,i);
+      n-=i;
+      p+=i;
+      signature_info->offset+=i;
+      if (signature_info->offset !=
+          GetStringInfoLength(signature_info->message))
+        return;
+      TransformSignature(signature_info);
+    }
+  while (n >= GetStringInfoLength(signature_info->message))
+  {
+    SetStringInfoDatum(signature_info->message,p);
+    p+=GetStringInfoLength(signature_info->message);
+    n-=GetStringInfoLength(signature_info->message);
+    TransformSignature(signature_info);
+  }
+  (void) CopyMagickMemory(GetStringInfoDatum(signature_info->message),p,n);
+  signature_info->offset=n;
+  /*
+    Reset working registers.
+  */
+  i=0;
+  n=0;
+  length=0;
+}
diff --git a/MagickCore/signature.h b/MagickCore/signature.h
new file mode 100644
index 0000000..6f59e38
--- /dev/null
+++ b/MagickCore/signature.h
@@ -0,0 +1,32 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore digital signature methods.
+*/
+#ifndef _MAGICKCORE_SIGNATURE_H
+#define _MAGICKCORE_SIGNATURE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  SignatureImage(Image *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/splay-tree.c b/MagickCore/splay-tree.c
new file mode 100644
index 0000000..82be190
--- /dev/null
+++ b/MagickCore/splay-tree.c
@@ -0,0 +1,1590 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                      SSSSS  PPPP   L       AAA   Y   Y                      %
+%                      SS     P   P  L      A   A   Y Y                       %
+%                       SSS   PPPP   L      AAAAA    Y                        %
+%                         SS  P      L      A   A    Y                        %
+%                      SSSSS  P      LLLLL  A   A    Y                        %
+%                                                                             %
+%                         TTTTT  RRRR   EEEEE  EEEEE                          %
+%                           T    R   R  E      E                              %
+%                           T    RRRR   EEE    EEE                            %
+%                           T    R R    E      E                              %
+%                           T    R  R   EEEEE  EEEEE                          %
+%                                                                             %
+%                                                                             %
+%             MagickCore Self-adjusting Binary Search Tree Methods            %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               December 2002                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  This module implements the standard handy splay-tree methods for storing and
+%  retrieving large numbers of data elements.  It is loosely based on the Java
+%  implementation of these algorithms.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+
+/*
+  Define declarations.
+*/
+#define MaxSplayTreeDepth  1024
+
+/*
+  Typedef declarations.
+*/
+typedef struct _NodeInfo
+{
+  void
+    *key;
+
+  void
+    *value;
+
+  struct _NodeInfo
+    *left,
+    *right;
+} NodeInfo;
+
+struct _SplayTreeInfo
+{
+  NodeInfo
+    *root;
+
+  int
+    (*compare)(const void *,const void *);
+
+  void
+    *(*relinquish_key)(void *),
+    *(*relinquish_value)(void *);
+
+  MagickBooleanType
+    balance;
+
+  void
+    *key,
+    *next;
+
+  size_t
+    nodes;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+/*
+  Forward declarations.
+*/
+static int
+  IterateOverSplayTree(SplayTreeInfo *,int (*)(NodeInfo *,const void *),
+    const void *);
+
+static void
+  SplaySplayTree(SplayTreeInfo *,const void *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A d d V a l u e T o S p l a y T r e e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AddValueToSplayTree() adds a value to the splay-tree.
+%
+%  The format of the AddValueToSplayTree method is:
+%
+%      MagickBooleanType AddValueToSplayTree(SplayTreeInfo *splay_tree,
+%        const void *key,const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o key: the key.
+%
+%    o value: the value.
+%
+*/
+MagickExport MagickBooleanType AddValueToSplayTree(SplayTreeInfo *splay_tree,
+  const void *key,const void *value)
+{
+  int
+    compare;
+
+  register NodeInfo
+    *node;
+
+  LockSemaphoreInfo(splay_tree->semaphore);
+  SplaySplayTree(splay_tree,key);
+  compare=0;
+  if (splay_tree->root != (NodeInfo *) NULL)
+    {
+      if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+        compare=splay_tree->compare(splay_tree->root->key,key);
+      else
+        compare=(splay_tree->root->key > key) ? 1 :
+          ((splay_tree->root->key < key) ? -1 : 0);
+      if (compare == 0)
+        {
+          if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+              (splay_tree->root->value != (void *) NULL))
+            splay_tree->root->value=splay_tree->relinquish_value(
+              splay_tree->root->value);
+          if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+              (splay_tree->root->key != (void *) NULL))
+            splay_tree->root->key=splay_tree->relinquish_key(
+              splay_tree->root->key);
+          splay_tree->root->key=(void *) key;
+          splay_tree->root->value=(void *) value;
+          UnlockSemaphoreInfo(splay_tree->semaphore);
+          return(MagickTrue);
+        }
+    }
+  node=(NodeInfo *) AcquireMagickMemory(sizeof(*node));
+  if (node == (NodeInfo *) NULL)
+    {
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(MagickFalse);
+    }
+  node->key=(void *) key;
+  node->value=(void *) value;
+  if (splay_tree->root == (NodeInfo *) NULL)
+    {
+      node->left=(NodeInfo *) NULL;
+      node->right=(NodeInfo *) NULL;
+    }
+  else
+    if (compare < 0)
+      {
+        node->left=splay_tree->root;
+        node->right=node->left->right;
+        node->left->right=(NodeInfo *) NULL;
+      }
+    else
+      {
+        node->right=splay_tree->root;
+        node->left=node->right->left;
+        node->right->left=(NodeInfo *) NULL;
+      }
+  splay_tree->root=node;
+  splay_tree->key=(void *) NULL;
+  splay_tree->nodes++;
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   B a l a n c e S p l a y T r e e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BalanceSplayTree() balances the splay-tree.
+%
+%  The format of the BalanceSplayTree method is:
+%
+%      void *BalanceSplayTree(SplayTreeInfo *splay_tree,const void *key)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o key: the key.
+%
+*/
+
+static NodeInfo *LinkSplayTreeNodes(NodeInfo **nodes,const size_t low,
+  const size_t high)
+{
+  register NodeInfo
+    *node;
+
+  size_t
+    bisect;
+
+  bisect=low+(high-low)/2;
+  node=nodes[bisect];
+  if ((low+1) > bisect)
+    node->left=(NodeInfo *) NULL;
+  else
+    node->left=LinkSplayTreeNodes(nodes,low,bisect-1);
+  if ((bisect+1) > high)
+    node->right=(NodeInfo *) NULL;
+  else
+    node->right=LinkSplayTreeNodes(nodes,bisect+1,high);
+  return(node);
+}
+
+static int SplayTreeToNodeArray(NodeInfo *node,const void *nodes)
+{
+  register const NodeInfo
+    ***p;
+
+  p=(const NodeInfo ***) nodes;
+  *(*p)=node;
+  (*p)++;
+  return(0);
+}
+
+static void BalanceSplayTree(SplayTreeInfo *splay_tree)
+{
+  NodeInfo
+    **node,
+    **nodes;
+
+  if (splay_tree->nodes <= 2)
+    {
+      splay_tree->balance=MagickFalse;
+      return;
+    }
+  nodes=(NodeInfo **) AcquireQuantumMemory((size_t) splay_tree->nodes,
+    sizeof(*nodes));
+  if (nodes == (NodeInfo **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  node=nodes;
+  (void) IterateOverSplayTree(splay_tree,SplayTreeToNodeArray,
+    (const void *) &node);
+  splay_tree->root=LinkSplayTreeNodes(nodes,0,splay_tree->nodes-1);
+  splay_tree->balance=MagickFalse;
+  nodes=(NodeInfo **) RelinquishMagickMemory(nodes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e S p l a y T r e e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneSplayTree() clones the splay tree.
+%
+%  The format of the CloneSplayTree method is:
+%
+%      SplayTreeInfo *CloneSplayTree(SplayTreeInfo *splay_tree,
+%        void *(*clone_key)(void *),void *(*cline_value)(void *))
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+%    o clone_key: the key clone method, typically ConstantString(), called
+%      whenever a key is added to the splay-tree.
+%
+%    o clone_value: the value clone method;  typically ConstantString(), called
+%      whenever a value object is added to the splay-tree.
+%
+*/
+
+static void *GetFirstSplayTreeNode(SplayTreeInfo *splay_tree)
+{
+  register NodeInfo
+    *node;
+
+  node=splay_tree->root;
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return((NodeInfo *) NULL);
+  while (node->left != (NodeInfo *) NULL)
+    node=node->left;
+  return(node->key);
+}
+
+MagickExport SplayTreeInfo *CloneSplayTree(SplayTreeInfo *splay_tree,
+  void *(*clone_key)(void *),void *(*clone_value)(void *))
+{
+  register NodeInfo
+    *next,
+    *node;
+
+  SplayTreeInfo
+    *clone_tree;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  clone_tree=NewSplayTree(splay_tree->compare,splay_tree->relinquish_key,
+    splay_tree->relinquish_value);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root == (NodeInfo *) NULL)
+    {
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(clone_tree);
+    }
+  next=(NodeInfo *) GetFirstSplayTreeNode(splay_tree);
+  while (next != (NodeInfo *) NULL)
+  {
+    SplaySplayTree(splay_tree,next);
+    (void) AddValueToSplayTree(clone_tree,clone_key(splay_tree->root->key),
+      clone_value(splay_tree->root->value));
+    next=(NodeInfo *) NULL;
+    node=splay_tree->root->right;
+    if (node != (NodeInfo *) NULL)
+      {
+        while (node->left != (NodeInfo *) NULL)
+          node=node->left;
+        next=(NodeInfo *) node->key;
+      }
+  }
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(clone_tree);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e S p l a y T r e e S t r i n g                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareSplayTreeString() method finds a node in a splay-tree based on the
+%  contents of a string.
+%
+%  The format of the CompareSplayTreeString method is:
+%
+%      int CompareSplayTreeString(const void *target,const void *source)
+%
+%  A description of each parameter follows:
+%
+%    o target: the target string.
+%
+%    o source: the source string.
+%
+*/
+MagickExport int CompareSplayTreeString(const void *target,const void *source)
+{
+  const char
+    *p,
+    *q;
+
+  p=(const char *) target;
+  q=(const char *) source;
+  return(LocaleCompare(p,q));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e S p l a y T r e e S t r i n g I n f o                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareSplayTreeStringInfo() finds a node in a splay-tree based on the
+%  contents of a string.
+%
+%  The format of the CompareSplayTreeStringInfo method is:
+%
+%      int CompareSplayTreeStringInfo(const void *target,const void *source)
+%
+%  A description of each parameter follows:
+%
+%    o target: the target string.
+%
+%    o source: the source string.
+%
+*/
+MagickExport int CompareSplayTreeStringInfo(const void *target,
+  const void *source)
+{
+  const StringInfo
+    *p,
+    *q;
+
+  p=(const StringInfo *) target;
+  q=(const StringInfo *) source;
+  return(CompareStringInfo(p,q));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e N o d e B y V a l u e F r o m S p l a y T r e e               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteNodeByValueFromSplayTree() deletes a node by value from the
+%  splay-tree.
+%
+%  The format of the DeleteNodeByValueFromSplayTree method is:
+%
+%      MagickBooleanType DeleteNodeByValueFromSplayTree(
+%        SplayTreeInfo *splay_tree,const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o value: the value.
+%
+*/
+MagickExport MagickBooleanType DeleteNodeByValueFromSplayTree(
+  SplayTreeInfo *splay_tree,const void *value)
+{
+  register NodeInfo
+    *next,
+    *node;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root == (NodeInfo *) NULL)
+    {
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(MagickFalse);
+    }
+  next=(NodeInfo *) GetFirstSplayTreeNode(splay_tree);
+  while (next != (NodeInfo *) NULL)
+  {
+    SplaySplayTree(splay_tree,next);
+    next=(NodeInfo *) NULL;
+    node=splay_tree->root->right;
+    if (node != (NodeInfo *) NULL)
+      {
+        while (node->left != (NodeInfo *) NULL)
+          node=node->left;
+        next=(NodeInfo *) node->key;
+      }
+    if (splay_tree->root->value == value)
+      {
+        int
+          compare;
+
+        register NodeInfo
+          *left,
+          *right;
+
+        void
+          *key;
+
+        /*
+          We found the node that matches the value; now delete it.
+        */
+        key=splay_tree->root->key;
+        SplaySplayTree(splay_tree,key);
+        splay_tree->key=(void *) NULL;
+        if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+          compare=splay_tree->compare(splay_tree->root->key,key);
+        else
+          compare=(splay_tree->root->key > key) ? 1 :
+            ((splay_tree->root->key < key) ? -1 : 0);
+        if (compare != 0)
+          {
+            UnlockSemaphoreInfo(splay_tree->semaphore);
+            return(MagickFalse);
+          }
+        left=splay_tree->root->left;
+        right=splay_tree->root->right;
+        if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+            (splay_tree->root->value != (void *) NULL))
+          splay_tree->root->value=splay_tree->relinquish_value(
+            splay_tree->root->value);
+        if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+            (splay_tree->root->key != (void *) NULL))
+          splay_tree->root->key=splay_tree->relinquish_key(
+            splay_tree->root->key);
+        splay_tree->root=(NodeInfo *) RelinquishMagickMemory(splay_tree->root);
+        splay_tree->nodes--;
+        if (left == (NodeInfo *) NULL)
+          {
+            splay_tree->root=right;
+            UnlockSemaphoreInfo(splay_tree->semaphore);
+            return(MagickTrue);
+          }
+        splay_tree->root=left;
+        if (right != (NodeInfo *) NULL)
+          {
+            while (left->right != (NodeInfo *) NULL)
+              left=left->right;
+            left->right=right;
+          }
+        UnlockSemaphoreInfo(splay_tree->semaphore);
+        return(MagickTrue);
+      }
+  }
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e l e t e N o d e F r o m S p l a y T r e e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DeleteNodeFromSplayTree() deletes a node from the splay-tree.
+%
+%  The format of the DeleteNodeFromSplayTree method is:
+%
+%      MagickBooleanType DeleteNodeFromSplayTree(SplayTreeInfo *splay_tree,
+%        const void *key)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o key: the key.
+%
+*/
+MagickExport MagickBooleanType DeleteNodeFromSplayTree(
+  SplayTreeInfo *splay_tree,const void *key)
+{
+  int
+    compare;
+
+  register NodeInfo
+    *left,
+    *right;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return(MagickFalse);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  SplaySplayTree(splay_tree,key);
+  splay_tree->key=(void *) NULL;
+  if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+    compare=splay_tree->compare(splay_tree->root->key,key);
+  else
+    compare=(splay_tree->root->key > key) ? 1 :
+      ((splay_tree->root->key < key) ? -1 : 0);
+  if (compare != 0)
+    {
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(MagickFalse);
+    }
+  left=splay_tree->root->left;
+  right=splay_tree->root->right;
+  if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+      (splay_tree->root->value != (void *) NULL))
+    splay_tree->root->value=splay_tree->relinquish_value(
+      splay_tree->root->value);
+  if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+      (splay_tree->root->key != (void *) NULL))
+    splay_tree->root->key=splay_tree->relinquish_key(splay_tree->root->key);
+  splay_tree->root=(NodeInfo *) RelinquishMagickMemory(splay_tree->root);
+  splay_tree->nodes--;
+  if (left == (NodeInfo *) NULL)
+    {
+      splay_tree->root=right;
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(MagickTrue);
+    }
+  splay_tree->root=left;
+  if (right != (NodeInfo *) NULL)
+    {
+      while (left->right != (NodeInfo *) NULL)
+        left=left->right;
+      left->right=right;
+    }
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y S p l a y T r e e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroySplayTree() destroys the splay-tree.
+%
+%  The format of the DestroySplayTree method is:
+%
+%      SplayTreeInfo *DestroySplayTree(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+*/
+MagickExport SplayTreeInfo *DestroySplayTree(SplayTreeInfo *splay_tree)
+{
+  NodeInfo
+    *node;
+
+  register NodeInfo
+    *active,
+    *pend;
+
+  LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root != (NodeInfo *) NULL)
+    {
+      if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+          (splay_tree->root->value != (void *) NULL))
+        splay_tree->root->value=splay_tree->relinquish_value(
+          splay_tree->root->value);
+      if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+          (splay_tree->root->key != (void *) NULL))
+        splay_tree->root->key=splay_tree->relinquish_key(splay_tree->root->key);
+      splay_tree->root->key=(void *) NULL;
+      for (pend=splay_tree->root; pend != (NodeInfo *) NULL; )
+      {
+        active=pend;
+        for (pend=(NodeInfo *) NULL; active != (NodeInfo *) NULL; )
+        {
+          if (active->left != (NodeInfo *) NULL)
+            {
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->left->value != (void *) NULL))
+                active->left->value=splay_tree->relinquish_value(
+                  active->left->value);
+              if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+                  (active->left->key != (void *) NULL))
+                active->left->key=splay_tree->relinquish_key(active->left->key);
+              active->left->key=(void *) pend;
+              pend=active->left;
+            }
+          if (active->right != (NodeInfo *) NULL)
+            {
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->right->value != (void *) NULL))
+                active->right->value=splay_tree->relinquish_value(
+                  active->right->value);
+              if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+                  (active->right->key != (void *) NULL))
+                active->right->key=splay_tree->relinquish_key(
+                  active->right->key);
+              active->right->key=(void *) pend;
+              pend=active->right;
+            }
+          node=active;
+          active=(NodeInfo *) node->key;
+          node=(NodeInfo *) RelinquishMagickMemory(node);
+        }
+      }
+    }
+  splay_tree->signature=(~MagickSignature);
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  DestroySemaphoreInfo(&splay_tree->semaphore);
+  splay_tree=(SplayTreeInfo *) RelinquishMagickMemory(splay_tree);
+  return(splay_tree);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t K e y I n S p l a y T r e e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextKeyInSplayTree() gets the next key in the splay-tree.
+%
+%  The format of the GetNextKeyInSplayTree method is:
+%
+%      const void *GetNextKeyInSplayTree(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+%    o key: the key.
+%
+*/
+MagickExport const void *GetNextKeyInSplayTree(SplayTreeInfo *splay_tree)
+{
+  register NodeInfo
+    *node;
+
+  void
+    *key;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if ((splay_tree->root == (NodeInfo *) NULL) ||
+      (splay_tree->next == (void *) NULL))
+    return((void *) NULL);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  SplaySplayTree(splay_tree,splay_tree->next);
+  splay_tree->next=(void *) NULL;
+  node=splay_tree->root->right;
+  if (node != (NodeInfo *) NULL)
+    {
+      while (node->left != (NodeInfo *) NULL)
+        node=node->left;
+      splay_tree->next=node->key;
+    }
+  key=splay_tree->root->key;
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(key);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t V a l u e I n S p l a y T r e e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextValueInSplayTree() gets the next value in the splay-tree.
+%
+%  The format of the GetNextValueInSplayTree method is:
+%
+%      const void *GetNextValueInSplayTree(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+%    o key: the key.
+%
+*/
+MagickExport const void *GetNextValueInSplayTree(SplayTreeInfo *splay_tree)
+{
+  register NodeInfo
+    *node;
+
+  void
+    *value;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if ((splay_tree->root == (NodeInfo *) NULL) ||
+      (splay_tree->next == (void *) NULL))
+    return((void *) NULL);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  SplaySplayTree(splay_tree,splay_tree->next);
+  splay_tree->next=(void *) NULL;
+  node=splay_tree->root->right;
+  if (node != (NodeInfo *) NULL)
+    {
+      while (node->left != (NodeInfo *) NULL)
+        node=node->left;
+      splay_tree->next=node->key;
+    }
+  value=splay_tree->root->value;
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t V a l u e F r o m S p l a y T r e e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetValueFromSplayTree() gets a value from the splay-tree by its key.
+%
+%  Note, the value is a constant.  Do not attempt to free it.
+%
+%  The format of the GetValueFromSplayTree method is:
+%
+%      const void *GetValueFromSplayTree(SplayTreeInfo *splay_tree,
+%        const void *key)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+%    o key: the key.
+%
+*/
+MagickExport const void *GetValueFromSplayTree(SplayTreeInfo *splay_tree,
+  const void *key)
+{
+  int
+    compare;
+
+  void
+    *value;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return((void *) NULL);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  SplaySplayTree(splay_tree,key);
+  if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+    compare=splay_tree->compare(splay_tree->root->key,key);
+  else
+    compare=(splay_tree->root->key > key) ? 1 :
+      ((splay_tree->root->key < key) ? -1 : 0);
+  if (compare != 0)
+    {
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return((void *) NULL);
+    }
+  value=splay_tree->root->value;
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N u m b e r O f N o d e s I n S p l a y T r e e                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNumberOfNodesInSplayTree() returns the number of nodes in the splay-tree.
+%
+%  The format of the GetNumberOfNodesInSplayTree method is:
+%
+%      size_t GetNumberOfNodesInSplayTree(
+%        const SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+*/
+MagickExport size_t GetNumberOfNodesInSplayTree(
+  const SplayTreeInfo *splay_tree)
+{
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(splay_tree->nodes);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I t e r a t e O v e r S p l a y T r e e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IterateOverSplayTree() iterates over the splay-tree.
+%
+%  The format of the IterateOverSplayTree method is:
+%
+%      int IterateOverSplayTree(SplayTreeInfo *splay_tree,
+%        int (*method)(NodeInfo *,void *),const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o method: the method.
+%
+%    o value: the value.
+%
+*/
+static int IterateOverSplayTree(SplayTreeInfo *splay_tree,
+  int (*method)(NodeInfo *,const void *),const void *value)
+{
+  typedef enum
+  {
+    LeftTransition,
+    RightTransition,
+    DownTransition,
+    UpTransition
+  } TransitionType;
+
+  int
+    status;
+
+  MagickBooleanType
+    final_transition;
+
+  NodeInfo
+    **nodes;
+
+  register ssize_t
+    i;
+
+  register NodeInfo
+    *node;
+
+  TransitionType
+    transition;
+
+  unsigned char
+    *transitions;
+
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return(0);
+  nodes=(NodeInfo **) AcquireQuantumMemory((size_t) splay_tree->nodes,
+    sizeof(*nodes));
+  transitions=(unsigned char *) AcquireQuantumMemory((size_t) splay_tree->nodes,
+    sizeof(*transitions));
+  if ((nodes == (NodeInfo **) NULL) || (transitions == (unsigned char *) NULL))
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  status=0;
+  final_transition=MagickFalse;
+  nodes[0]=splay_tree->root;
+  transitions[0]=(unsigned char) LeftTransition;
+  for (i=0; final_transition == MagickFalse; )
+  {
+    node=nodes[i];
+    transition=(TransitionType) transitions[i];
+    switch (transition)
+    {
+      case LeftTransition:
+      {
+        transitions[i]=(unsigned char) DownTransition;
+        if (node->left == (NodeInfo *) NULL)
+          break;
+        i++;
+        nodes[i]=node->left;
+        transitions[i]=(unsigned char) LeftTransition;
+        break;
+      }
+      case RightTransition:
+      {
+        transitions[i]=(unsigned char) UpTransition;
+        if (node->right == (NodeInfo *) NULL)
+          break;
+        i++;
+        nodes[i]=node->right;
+        transitions[i]=(unsigned char) LeftTransition;
+        break;
+      }
+      case DownTransition:
+      default:
+      {
+        transitions[i]=(unsigned char) RightTransition;
+        status=(*method)(node,value);
+        if (status != 0)
+          final_transition=MagickTrue;
+        break;
+      }
+      case UpTransition:
+      {
+        if (i == 0)
+          {
+            final_transition=MagickTrue;
+            break;
+          }
+        i--;
+        break;
+      }
+    }
+  }
+  nodes=(NodeInfo **) RelinquishMagickMemory(nodes);
+  transitions=(unsigned char *) RelinquishMagickMemory(transitions);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w S p l a y T r e e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewSplayTree() returns a pointer to a SplayTreeInfo structure initialized
+%  to default values.
+%
+%  The format of the NewSplayTree method is:
+%
+%      SplayTreeInfo *NewSplayTree(int (*compare)(const void *,const void *),
+%        void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
+%
+%  A description of each parameter follows:
+%
+%    o compare: the compare method.
+%
+%    o relinquish_key: the key deallocation method, typically
+%      RelinquishMagickMemory(), called whenever a key is removed from the
+%      splay-tree.
+%
+%    o relinquish_value: the value deallocation method;  typically
+%      RelinquishMagickMemory(), called whenever a value object is removed from
+%      the splay-tree.
+%
+*/
+MagickExport SplayTreeInfo *NewSplayTree(
+  int (*compare)(const void *,const void *),void *(*relinquish_key)(void *),
+  void *(*relinquish_value)(void *))
+{
+  SplayTreeInfo
+    *splay_tree;
+
+  splay_tree=(SplayTreeInfo *) AcquireMagickMemory(sizeof(*splay_tree));
+  if (splay_tree == (SplayTreeInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(splay_tree,0,sizeof(*splay_tree));
+  splay_tree->root=(NodeInfo *) NULL;
+  splay_tree->compare=compare;
+  splay_tree->relinquish_key=relinquish_key;
+  splay_tree->relinquish_value=relinquish_value;
+  splay_tree->balance=MagickFalse;
+  splay_tree->key=(void *) NULL;
+  splay_tree->next=(void *) NULL;
+  splay_tree->nodes=0;
+  splay_tree->debug=IsEventLogging();
+  splay_tree->semaphore=AllocateSemaphoreInfo();
+  splay_tree->signature=MagickSignature;
+  return(splay_tree);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e N o d e B y V a l u e F r o m S p l a y T r e e               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveNodeByValueFromSplayTree() removes a node by value from the splay-tree
+%  and returns its key.
+%
+%  The format of the RemoveNodeByValueFromSplayTree method is:
+%
+%      void *RemoveNodeByValueFromSplayTree(SplayTreeInfo *splay_tree,
+%        const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o value: the value.
+%
+*/
+MagickExport void *RemoveNodeByValueFromSplayTree(SplayTreeInfo *splay_tree,
+  const void *value)
+{
+  register NodeInfo
+    *next,
+    *node;
+
+  void
+    *key;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  key=(void *) NULL;
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return(key);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  next=(NodeInfo *) GetFirstSplayTreeNode(splay_tree);
+  while (next != (NodeInfo *) NULL)
+  {
+    SplaySplayTree(splay_tree,next);
+    next=(NodeInfo *) NULL;
+    node=splay_tree->root->right;
+    if (node != (NodeInfo *) NULL)
+      {
+        while (node->left != (NodeInfo *) NULL)
+          node=node->left;
+        next=(NodeInfo *) node->key;
+      }
+    if (splay_tree->root->value == value)
+      {
+        int
+          compare;
+
+        register NodeInfo
+          *left,
+          *right;
+
+        /*
+          We found the node that matches the value; now remove it.
+        */
+        key=splay_tree->root->key;
+        SplaySplayTree(splay_tree,key);
+        splay_tree->key=(void *) NULL;
+        if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+          compare=splay_tree->compare(splay_tree->root->key,key);
+        else
+          compare=(splay_tree->root->key > key) ? 1 :
+            ((splay_tree->root->key < key) ? -1 : 0);
+        if (compare != 0)
+          {
+            UnlockSemaphoreInfo(splay_tree->semaphore);
+            return(key);
+          }
+        left=splay_tree->root->left;
+        right=splay_tree->root->right;
+        if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+            (splay_tree->root->value != (void *) NULL))
+          splay_tree->root->value=splay_tree->relinquish_value(
+            splay_tree->root->value);
+        splay_tree->root=(NodeInfo *) RelinquishMagickMemory(splay_tree->root);
+        splay_tree->nodes--;
+        if (left == (NodeInfo *) NULL)
+          {
+            splay_tree->root=right;
+            UnlockSemaphoreInfo(splay_tree->semaphore);
+            return(key);
+          }
+        splay_tree->root=left;
+        if (right != (NodeInfo *) NULL)
+          {
+            while (left->right != (NodeInfo *) NULL)
+              left=left->right;
+            left->right=right;
+          }
+        UnlockSemaphoreInfo(splay_tree->semaphore);
+        return(key);
+      }
+  }
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(key);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e m o v e N o d e F r o m S p l a y T r e e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RemoveNodeFromSplayTree() removes a node from the splay-tree and returns its
+%  value.
+%
+%  The format of the RemoveNodeFromSplayTree method is:
+%
+%      void *RemoveNodeFromSplayTree(SplayTreeInfo *splay_tree,const void *key)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o key: the key.
+%
+*/
+MagickExport void *RemoveNodeFromSplayTree(SplayTreeInfo *splay_tree,
+  const void *key)
+{
+  int
+    compare;
+
+  register NodeInfo
+    *left,
+    *right;
+
+  void
+    *value;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  value=(void *) NULL;
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return(value);
+  LockSemaphoreInfo(splay_tree->semaphore);
+  SplaySplayTree(splay_tree,key);
+  splay_tree->key=(void *) NULL;
+  if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+    compare=splay_tree->compare(splay_tree->root->key,key);
+  else
+    compare=(splay_tree->root->key > key) ? 1 :
+      ((splay_tree->root->key < key) ? -1 : 0);
+  if (compare != 0)
+    {
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(value);
+    }
+  left=splay_tree->root->left;
+  right=splay_tree->root->right;
+  value=splay_tree->root->value;
+  if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+      (splay_tree->root->key != (void *) NULL))
+    splay_tree->root->key=splay_tree->relinquish_key(splay_tree->root->key);
+  splay_tree->root=(NodeInfo *) RelinquishMagickMemory(splay_tree->root);
+  splay_tree->nodes--;
+  if (left == (NodeInfo *) NULL)
+    {
+      splay_tree->root=right;
+      UnlockSemaphoreInfo(splay_tree->semaphore);
+      return(value);
+    }
+  splay_tree->root=left;
+  if (right != (NodeInfo *) NULL)
+    {
+      while (left->right != (NodeInfo *) NULL)
+        left=left->right;
+      left->right=right;
+    }
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+  return(value);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t S p l a y T r e e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetSplayTree() resets the splay-tree.  That is, it deletes all the nodes
+%  from the tree.
+%
+%  The format of the ResetSplayTree method is:
+%
+%      ResetSplayTree(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+*/
+MagickExport void ResetSplayTree(SplayTreeInfo *splay_tree)
+{
+  NodeInfo
+    *node;
+
+  register NodeInfo
+    *active,
+    *pend;
+
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(splay_tree->semaphore);
+  if (splay_tree->root != (NodeInfo *) NULL)
+    {
+      if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+          (splay_tree->root->value != (void *) NULL))
+        splay_tree->root->value=splay_tree->relinquish_value(
+          splay_tree->root->value);
+      if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+          (splay_tree->root->key != (void *) NULL))
+        splay_tree->root->key=splay_tree->relinquish_key(splay_tree->root->key);
+      splay_tree->root->key=(void *) NULL;
+      for (pend=splay_tree->root; pend != (NodeInfo *) NULL; )
+      {
+        active=pend;
+        for (pend=(NodeInfo *) NULL; active != (NodeInfo *) NULL; )
+        {
+          if (active->left != (NodeInfo *) NULL)
+            {
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->left->value != (void *) NULL))
+                active->left->value=splay_tree->relinquish_value(
+                  active->left->value);
+              if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+                  (active->left->key != (void *) NULL))
+                active->left->key=splay_tree->relinquish_key(active->left->key);
+              active->left->key=(void *) pend;
+              pend=active->left;
+            }
+          if (active->right != (NodeInfo *) NULL)
+            {
+              if ((splay_tree->relinquish_value != (void *(*)(void *)) NULL) &&
+                  (active->right->value != (void *) NULL))
+                active->right->value=splay_tree->relinquish_value(
+                  active->right->value);
+              if ((splay_tree->relinquish_key != (void *(*)(void *)) NULL) &&
+                  (active->right->key != (void *) NULL))
+                active->right->key=splay_tree->relinquish_key(
+                  active->right->key);
+              active->right->key=(void *) pend;
+              pend=active->right;
+            }
+          node=active;
+          active=(NodeInfo *) node->key;
+          node=(NodeInfo *) RelinquishMagickMemory(node);
+        }
+      }
+    }
+  splay_tree->root=(NodeInfo *) NULL;
+  splay_tree->key=(void *) NULL;
+  splay_tree->next=(void *) NULL;
+  splay_tree->nodes=0;
+  splay_tree->balance=MagickFalse;
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t S p l a y T r e e I t e r a t o r                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetSplayTreeIterator() resets the splay-tree iterator.  Use it in
+%  conjunction with GetNextValueInSplayTree() to iterate over all the nodes in
+%  the splay-tree.
+%
+%  The format of the ResetSplayTreeIterator method is:
+%
+%      ResetSplayTreeIterator(SplayTreeInfo *splay_tree)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay tree.
+%
+*/
+MagickExport void ResetSplayTreeIterator(SplayTreeInfo *splay_tree)
+{
+  assert(splay_tree != (SplayTreeInfo *) NULL);
+  assert(splay_tree->signature == MagickSignature);
+  if (splay_tree->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  LockSemaphoreInfo(splay_tree->semaphore);
+  splay_tree->next=GetFirstSplayTreeNode(splay_tree);
+  UnlockSemaphoreInfo(splay_tree->semaphore);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p l a y S p l a y T r e e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SplaySplayTree() splays the splay-tree.
+%
+%  The format of the SplaySplayTree method is:
+%
+%      void SplaySplayTree(SplayTreeInfo *splay_tree,const void *key,
+%        NodeInfo **node,NodeInfo **parent,NodeInfo **grandparent)
+%
+%  A description of each parameter follows:
+%
+%    o splay_tree: the splay-tree info.
+%
+%    o key: the key.
+%
+%    o node: the node.
+%
+%    o parent: the parent node.
+%
+%    o grandparent: the grandparent node.
+%
+*/
+
+static NodeInfo *Splay(SplayTreeInfo *splay_tree,const size_t depth,
+  const void *key,NodeInfo **node,NodeInfo **parent,NodeInfo **grandparent)
+{
+  int
+    compare;
+
+  NodeInfo
+    **next;
+
+  register NodeInfo
+    *n,
+    *p;
+
+  n=(*node);
+  if (n == (NodeInfo *) NULL)
+    return(*parent);
+  if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+    compare=splay_tree->compare(n->key,key);
+  else
+    compare=(n->key > key) ? 1 : ((n->key < key) ? -1 : 0);
+  next=(NodeInfo **) NULL;
+  if (compare > 0)
+    next=(&n->left);
+  else
+    if (compare < 0)
+      next=(&n->right);
+  if (next != (NodeInfo **) NULL)
+    {
+      if (depth >= MaxSplayTreeDepth)
+        {
+          splay_tree->balance=MagickTrue;
+          return(n);
+        }
+      n=Splay(splay_tree,depth+1,key,next,node,parent);
+      if ((n != *node) || (splay_tree->balance != MagickFalse))
+        return(n);
+    }
+  if (parent == (NodeInfo **) NULL)
+    return(n);
+  if (grandparent == (NodeInfo **) NULL)
+    {
+      if (n == (*parent)->left)
+        {
+          *node=n->right;
+          n->right=(*parent);
+        }
+      else
+        {
+          *node=n->left;
+          n->left=(*parent);
+        }
+      *parent=n;
+      return(n);
+    }
+  if ((n == (*parent)->left) && (*parent == (*grandparent)->left))
+    {
+      p=(*parent);
+      (*grandparent)->left=p->right;
+      p->right=(*grandparent);
+      p->left=n->right;
+      n->right=p;
+      *grandparent=n;
+      return(n);
+    }
+  if ((n == (*parent)->right) && (*parent == (*grandparent)->right))
+    {
+      p=(*parent);
+      (*grandparent)->right=p->left;
+      p->left=(*grandparent);
+      p->right=n->left;
+      n->left=p;
+      *grandparent=n;
+      return(n);
+    }
+  if (n == (*parent)->left)
+    {
+      (*parent)->left=n->right;
+      n->right=(*parent);
+      (*grandparent)->right=n->left;
+      n->left=(*grandparent);
+      *grandparent=n;
+      return(n);
+    }
+  (*parent)->right=n->left;
+  n->left=(*parent);
+  (*grandparent)->left=n->right;
+  n->right=(*grandparent);
+  *grandparent=n;
+  return(n);
+}
+
+static void SplaySplayTree(SplayTreeInfo *splay_tree,const void *key)
+{
+  if (splay_tree->root == (NodeInfo *) NULL)
+    return;
+  if (splay_tree->key != (void *) NULL)
+    {
+      int
+        compare;
+
+      if (splay_tree->compare != (int (*)(const void *,const void *)) NULL)
+        compare=splay_tree->compare(splay_tree->root->key,key);
+      else
+        compare=(splay_tree->key > key) ? 1 :
+          ((splay_tree->key < key) ? -1 : 0);
+      if (compare == 0)
+        return;
+    }
+  (void) Splay(splay_tree,0UL,key,&splay_tree->root,(NodeInfo **) NULL,
+    (NodeInfo **) NULL);
+  if (splay_tree->balance != MagickFalse)
+    {
+      BalanceSplayTree(splay_tree);
+      (void) Splay(splay_tree,0UL,key,&splay_tree->root,(NodeInfo **) NULL,
+        (NodeInfo **) NULL);
+      if (splay_tree->balance != MagickFalse)
+        ThrowFatalException(ResourceLimitFatalError,
+          "MemoryAllocationFailed");
+    }
+  splay_tree->key=(void *) key;
+}
diff --git a/MagickCore/splay-tree.h b/MagickCore/splay-tree.h
new file mode 100644
index 0000000..a5a29a1
--- /dev/null
+++ b/MagickCore/splay-tree.h
@@ -0,0 +1,61 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore splay-tree methods.
+*/
+#ifndef _MAGICKCORE_SPLAY_H
+#define _MAGICKCORE_SPLAY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _SplayTreeInfo
+  SplayTreeInfo;
+
+extern MagickExport MagickBooleanType
+  AddValueToSplayTree(SplayTreeInfo *,const void *,const void *),
+  DeleteNodeByValueFromSplayTree(SplayTreeInfo *,const void *),
+  DeleteNodeFromSplayTree(SplayTreeInfo *,const void *);
+
+extern MagickExport const void
+  *GetNextKeyInSplayTree(SplayTreeInfo *),
+  *GetNextValueInSplayTree(SplayTreeInfo *),
+  *GetValueFromSplayTree(SplayTreeInfo *,const void *);
+
+extern MagickExport int
+  CompareSplayTreeString(const void *,const void *),
+  CompareSplayTreeStringInfo(const void *,const void *);
+
+extern MagickExport SplayTreeInfo
+  *CloneSplayTree(SplayTreeInfo *,void *(*)(void *),void *(*)(void *)),
+  *DestroySplayTree(SplayTreeInfo *),
+  *NewSplayTree(int (*)(const void *,const void *),void *(*)(void *),
+    void *(*)(void *));
+
+extern MagickExport size_t
+  GetNumberOfNodesInSplayTree(const SplayTreeInfo *);
+
+extern MagickExport void
+  *RemoveNodeByValueFromSplayTree(SplayTreeInfo *,const void *),
+  *RemoveNodeFromSplayTree(SplayTreeInfo *,const void *),
+  ResetSplayTree(SplayTreeInfo *),
+  ResetSplayTreeIterator(SplayTreeInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/stamp-h.in b/MagickCore/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/MagickCore/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/MagickCore/stamp-h1 b/MagickCore/stamp-h1
new file mode 100644
index 0000000..7bb7372
--- /dev/null
+++ b/MagickCore/stamp-h1
@@ -0,0 +1 @@
+timestamp for magick/magick-config.h
diff --git a/MagickCore/static.c b/MagickCore/static.c
new file mode 100644
index 0000000..9ef564c
--- /dev/null
+++ b/MagickCore/static.c
@@ -0,0 +1,496 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  SSSSS  TTTTT   AAA   TTTTT  IIIII   CCCC                   %
+%                  SS       T    A   A    T      I    C                       %
+%                   SSS     T    AAAAA    T      I    C                       %
+%                     SS    T    A   A    T      I    C                       %
+%                  SSSSS    T    A   A    T    IIIII   CCCC                   %
+%                                                                             %
+%                                                                             %
+%                          MagickCore Static Methods                          %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 March 2000                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/module.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/static.h"
+#include "MagickCore/string_.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n v o k e S t a t i c I m a g e F i l t e r                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InvokeStaticImageFilter() invokes a static image filter.
+%
+%  The format of the InvokeStaticImageFilter method is:
+%
+%      MagickBooleanType InvokeStaticImageFilter(const char *tag,Image **image,
+%        const int argc,const char **argv)
+%
+%  A description of each parameter follows:
+%
+%    o tag: the module tag.
+%
+%    o image: the image.
+%
+%    o argc: the number of elements in the argument vector.
+%
+%    o argv: A text array containing the command line arguments.
+%
+%    o argv: A text array containing the command line arguments.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+#if defined(MAGICKCORE_MODULES_SUPPORT)
+MagickExport MagickBooleanType InvokeStaticImageFilter(const char *tag,
+  Image **image,const int argc,const char **argv,ExceptionInfo *exception)
+{
+  PolicyRights
+    rights;
+
+  assert(image != (Image **) NULL);
+  assert((*image)->signature == MagickSignature);
+  if ((*image)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
+  rights=ReadPolicyRights;
+  if (IsRightsAuthorized(FilterPolicyDomain,rights,tag) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",tag);
+      return(MagickFalse);
+    }
+#if defined(MAGICKCORE_BUILD_MODULES)
+  (void) tag;
+  (void) argc;
+  (void) argv;
+  (void) exception;
+#else
+  {
+    extern size_t
+      analyzeImage(Image **,const int,char **,ExceptionInfo *);
+
+    ImageFilterHandler
+      *image_filter;
+
+    image_filter=(ImageFilterHandler *) NULL;
+    if (LocaleCompare("analyze",tag) == 0)
+      image_filter=(ImageFilterHandler *) analyzeImage;
+    if (image_filter == (ImageFilterHandler *) NULL)
+      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+        "UnableToLoadModule","`%s'",tag);
+    else
+      {
+        size_t
+          signature;
+
+        if ((*image)->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "Invoking \"%s\" static image filter",tag);
+        signature=image_filter(image,argc,argv,exception);
+        if ((*image)->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"\"%s\" completes",
+            tag);
+        if (signature != MagickImageFilterSignature)
+          {
+            (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
+              "ImageFilterSignatureMismatch","`%s': %8lx != %8lx",tag,
+              (unsigned long) signature,(unsigned long)
+              MagickImageFilterSignature);
+            return(MagickFalse);
+          }
+      }
+  }
+#endif
+  return(MagickTrue);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e g i s t e r S t a t i c M o d u l e s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  (void) RegisterStaticModules() statically registers all the available module
+%  handlers.
+%
+%  The format of the RegisterStaticModules method is:
+%
+%      (void) RegisterStaticModules(void)
+%
+*/
+MagickExport void RegisterStaticModules(void)
+{
+#if !defined(MAGICKCORE_BUILD_MODULES)
+  (void) RegisterAAIImage();
+  (void) RegisterARTImage();
+  (void) RegisterAVSImage();
+  (void) RegisterBMPImage();
+  (void) RegisterCALSImage();
+  (void) RegisterCAPTIONImage();
+  (void) RegisterCINImage();
+  (void) RegisterCIPImage();
+  (void) RegisterCLIPImage();
+#if defined(MAGICKCORE_WINGDI32_DELEGATE)
+  (void) RegisterCLIPBOARDImage();
+#endif
+  (void) RegisterCMYKImage();
+  (void) RegisterCUTImage();
+  (void) RegisterDCMImage();
+  (void) RegisterDDSImage();
+  (void) RegisterDEBUGImage();
+  (void) RegisterDIBImage();
+#if defined(MAGICKCORE_DJVU_DELEGATE)
+  (void) RegisterDJVUImage();
+#endif
+  (void) RegisterDNGImage();
+#if defined(MAGICKCORE_DPS_DELEGATE)
+  (void) RegisterDPSImage();
+#endif
+  (void) RegisterDPXImage();
+#if defined(MAGICKCORE_WINGDI32_DELEGATE)
+  (void) RegisterEMFImage();
+#endif
+#if defined(MAGICKCORE_TIFF_DELEGATE)
+  (void) RegisterEPTImage();
+#endif
+#if defined(MAGICKCORE_OPENEXR_DELEGATE)
+  (void) RegisterEXRImage();
+#endif
+  (void) RegisterFAXImage();
+  (void) RegisterFITSImage();
+#if defined(MAGICKCORE_FPX_DELEGATE)
+  (void) RegisterFPXImage();
+#endif
+  (void) RegisterGIFImage();
+  (void) RegisterGRAYImage();
+  (void) RegisterGRADIENTImage();
+  (void) RegisterHALDImage();
+  (void) RegisterHDRImage();
+  (void) RegisterHISTOGRAMImage();
+  (void) RegisterHRZImage();
+  (void) RegisterHTMLImage();
+  (void) RegisterICONImage();
+  (void) RegisterINFOImage();
+  (void) RegisterINLINEImage();
+  (void) RegisterIPLImage();
+#if defined(MAGICKCORE_JBIG_DELEGATE)
+  (void) RegisterJBIGImage();
+#endif
+#if defined(MAGICKCORE_JPEG_DELEGATE)
+  (void) RegisterJPEGImage();
+#endif
+#if defined(MAGICKCORE_JP2_DELEGATE)
+  (void) RegisterJP2Image();
+#endif
+  (void) RegisterLABELImage();
+  (void) RegisterMACImage();
+  (void) RegisterMAGICKImage();
+  (void) RegisterMAPImage();
+  (void) RegisterMATImage();
+  (void) RegisterMATTEImage();
+  (void) RegisterMETAImage();
+  (void) RegisterMIFFImage();
+  (void) RegisterMONOImage();
+  (void) RegisterMPCImage();
+  (void) RegisterMPEGImage();
+  (void) RegisterMPRImage();
+  (void) RegisterMSLImage();
+  (void) RegisterMTVImage();
+  (void) RegisterMVGImage();
+  (void) RegisterNULLImage();
+  (void) RegisterOTBImage();
+  (void) RegisterPALMImage();
+  (void) RegisterPATTERNImage();
+  (void) RegisterPCDImage();
+  (void) RegisterPCLImage();
+  (void) RegisterPCXImage();
+  (void) RegisterPDBImage();
+  (void) RegisterPDFImage();
+  (void) RegisterPESImage();
+  (void) RegisterPICTImage();
+  (void) RegisterPIXImage();
+  (void) RegisterPLASMAImage();
+#if defined(MAGICKCORE_PNG_DELEGATE)
+  (void) RegisterPNGImage();
+#endif
+  (void) RegisterPNMImage();
+  (void) RegisterPREVIEWImage();
+  (void) RegisterPSImage();
+  (void) RegisterPS2Image();
+  (void) RegisterPS3Image();
+  (void) RegisterPSDImage();
+  (void) RegisterPWPImage();
+  (void) RegisterRAWImage();
+  (void) RegisterRGBImage();
+  (void) RegisterRLAImage();
+  (void) RegisterRLEImage();
+  (void) RegisterSCRImage();
+  (void) RegisterSCTImage();
+  (void) RegisterSFWImage();
+  (void) RegisterSGIImage();
+  (void) RegisterSTEGANOImage();
+  (void) RegisterSUNImage();
+  (void) RegisterSVGImage();
+  (void) RegisterTGAImage();
+  (void) RegisterTHUMBNAILImage();
+#if defined(MAGICKCORE_TIFF_DELEGATE)
+  (void) RegisterTIFFImage();
+#endif
+  (void) RegisterTILEImage();
+  (void) RegisterTIMImage();
+  (void) RegisterTTFImage();
+  (void) RegisterTXTImage();
+  (void) RegisterUILImage();
+  (void) RegisterURLImage();
+  (void) RegisterUYVYImage();
+  (void) RegisterVICARImage();
+  (void) RegisterVIDImage();
+  (void) RegisterVIFFImage();
+  (void) RegisterWBMPImage();
+#if defined(MAGICKCORE_WEBP_DELEGATE)
+  (void) RegisterWEBPImage();
+#endif
+#if defined(MAGICKCORE_WMF_DELEGATE) || defined(MAGICKCORE_WMFLITE_DELEGATE)
+  (void) RegisterWMFImage();
+#endif
+  (void) RegisterWPGImage();
+#if defined(MAGICKCORE_X11_DELEGATE)
+  (void) RegisterXImage();
+#endif
+  (void) RegisterXBMImage();
+  (void) RegisterXCImage();
+  (void) RegisterXCFImage();
+  (void) RegisterXPMImage();
+  (void) RegisterXPSImage();
+#if defined(_VISUALC_)
+  (void) RegisterXTRNImage();
+#endif
+#if defined(MAGICKCORE_X11_DELEGATE)
+  (void) RegisterXWDImage();
+#endif
+  (void) RegisterYCBCRImage();
+  (void) RegisterYUVImage();
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   U n r e g i s t e r S t a t i c M o d u l e s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UnregisterStaticModules() statically unregisters all the available module
+%  handlers.
+%
+%  The format of the UnregisterStaticModules method is:
+%
+%      UnregisterStaticModules(void)
+%
+*/
+MagickExport void UnregisterStaticModules(void)
+{
+#if !defined(MAGICKCORE_BUILD_MODULES)
+  UnregisterAAIImage();
+  UnregisterARTImage();
+  UnregisterAVSImage();
+  UnregisterBMPImage();
+  UnregisterBRAILLEImage();
+  UnregisterCALSImage();
+  UnregisterCAPTIONImage();
+  UnregisterCINImage();
+  UnregisterCIPImage();
+  UnregisterCLIPImage();
+#if defined(MAGICKCORE_WINGDI32_DELEGATE)
+  UnregisterCLIPBOARDImage();
+#endif
+  UnregisterCMYKImage();
+  UnregisterCUTImage();
+  UnregisterDCMImage();
+  UnregisterDDSImage();
+  UnregisterDEBUGImage();
+  UnregisterDIBImage();
+#if defined(MAGICKCORE_DJVU_DELEGATE)
+  UnregisterDJVUImage();
+#endif
+  UnregisterDNGImage();
+#if defined(MAGICKCORE_DPS_DELEGATE)
+  UnregisterDPSImage();
+#endif
+  UnregisterDPXImage();
+#if defined(MAGICKCORE_WINGDI32_DELEGATE)
+  UnregisterEMFImage();
+#endif
+#if defined(MAGICKCORE_TIFF_DELEGATE)
+  UnregisterEPTImage();
+#endif
+#if defined(MAGICKCORE_OPENEXR_DELEGATE)
+  UnregisterEXRImage();
+#endif
+  UnregisterFAXImage();
+  UnregisterFITSImage();
+#if defined(MAGICKCORE_FPX_DELEGATE)
+  UnregisterFPXImage();
+#endif
+  UnregisterGIFImage();
+  UnregisterGRAYImage();
+  UnregisterGRADIENTImage();
+  UnregisterHALDImage();
+  UnregisterHDRImage();
+  UnregisterHISTOGRAMImage();
+  UnregisterHRZImage();
+  UnregisterHTMLImage();
+  UnregisterICONImage();
+  UnregisterINFOImage();
+  UnregisterINLINEImage();
+  UnregisterIPLImage();
+#if defined(MAGICKCORE_JBIG_DELEGATE)
+  UnregisterJBIGImage();
+#endif
+#if defined(MAGICKCORE_JPEG_DELEGATE)
+  UnregisterJPEGImage();
+#endif
+#if defined(MAGICKCORE_JP2_DELEGATE)
+  UnregisterJP2Image();
+#endif
+  UnregisterLABELImage();
+  UnregisterMACImage();
+  UnregisterMAGICKImage();
+  UnregisterMAPImage();
+  UnregisterMATImage();
+  UnregisterMATTEImage();
+  UnregisterMETAImage();
+  UnregisterMIFFImage();
+  UnregisterMONOImage();
+  UnregisterMPCImage();
+  UnregisterMPEGImage();
+  UnregisterMPRImage();
+  UnregisterMSLImage();
+  UnregisterMTVImage();
+  UnregisterMVGImage();
+  UnregisterNULLImage();
+  UnregisterOTBImage();
+  UnregisterPALMImage();
+  UnregisterPATTERNImage();
+  UnregisterPCDImage();
+  UnregisterPCLImage();
+  UnregisterPCXImage();
+  UnregisterPDBImage();
+  UnregisterPDFImage();
+  UnregisterPESImage();
+  UnregisterPICTImage();
+  UnregisterPIXImage();
+  UnregisterPLASMAImage();
+#if defined(MAGICKCORE_PNG_DELEGATE)
+  UnregisterPNGImage();
+#endif
+  UnregisterPNMImage();
+  UnregisterPREVIEWImage();
+  UnregisterPSImage();
+  UnregisterPS2Image();
+  UnregisterPS3Image();
+  UnregisterPSDImage();
+  UnregisterPWPImage();
+  UnregisterRAWImage();
+  UnregisterRGBImage();
+  UnregisterRLAImage();
+  UnregisterRLEImage();
+  UnregisterSCRImage();
+  UnregisterSCTImage();
+  UnregisterSFWImage();
+  UnregisterSGIImage();
+  UnregisterSTEGANOImage();
+  UnregisterSUNImage();
+  UnregisterSVGImage();
+  UnregisterTGAImage();
+  UnregisterTHUMBNAILImage();
+#if defined(MAGICKCORE_TIFF_DELEGATE)
+  UnregisterTIFFImage();
+#endif
+  UnregisterTILEImage();
+  UnregisterTIMImage();
+  UnregisterTTFImage();
+  UnregisterTXTImage();
+  UnregisterUILImage();
+  UnregisterURLImage();
+  UnregisterUYVYImage();
+  UnregisterVICARImage();
+  UnregisterVIDImage();
+  UnregisterVIFFImage();
+  UnregisterWBMPImage();
+#if defined(MAGICKCORE_WEBP_DELEGATE)
+  UnregisterWEBPImage();
+#endif
+#if defined(MAGICKCORE_WMF_DELEGATE) || defined(MAGICKCORE_WMFLITE_DELEGATE)
+  UnregisterWMFImage();
+#endif
+  UnregisterWPGImage();
+#if defined(MAGICKCORE_X11_DELEGATE)
+  UnregisterXImage();
+#endif
+  UnregisterXBMImage();
+  UnregisterXCImage();
+  UnregisterXCFImage();
+  UnregisterXPMImage();
+  UnregisterXPSImage();
+#if defined(_VISUALC_)
+  UnregisterXTRNImage();
+#endif
+#if defined(MAGICKCORE_X11_DELEGATE)
+  UnregisterXWDImage();
+#endif
+  UnregisterYCBCRImage();
+  UnregisterYUVImage();
+#endif
+}
diff --git a/MagickCore/static.h b/MagickCore/static.h
new file mode 100644
index 0000000..fb412eb
--- /dev/null
+++ b/MagickCore/static.h
@@ -0,0 +1,340 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore static coder registration methods.
+*/
+#ifndef _MAGICKCORE_STATIC_H
+#define _MAGICKCORE_STATIC_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport MagickBooleanType
+  InvokeStaticImageFilter(const char *,Image **,const int,const char **,
+    ExceptionInfo *);
+
+extern ModuleExport size_t
+  RegisterAAIImage(void),
+  RegisterARTImage(void),
+  RegisterAVIImage(void),
+  RegisterAVSImage(void),
+  RegisterBIEImage(void),
+  RegisterBMPImage(void),
+  RegisterBRAILLEImage(void),
+  RegisterCALSImage(void),
+  RegisterCAPTIONImage(void),
+  RegisterCINImage(void),
+  RegisterCIPImage(void),
+  RegisterCLIPImage(void),
+  RegisterCLIPBOARDImage(void),
+  RegisterCMYKImage(void),
+  RegisterCUTImage(void),
+  RegisterDCMImage(void),
+  RegisterDCXImage(void),
+  RegisterDDSImage(void),
+  RegisterDEBUGImage(void),
+  RegisterDIBImage(void),
+  RegisterDJVUImage(void),
+  RegisterDNGImage(void),
+  RegisterDPSImage(void),
+  RegisterDPXImage(void),
+  RegisterEMFImage(void),
+  RegisterEPDFImage(void),
+  RegisterEPIImage(void),
+  RegisterEPSImage(void),
+  RegisterEPS2Image(void),
+  RegisterEPSFImage(void),
+  RegisterEPSIImage(void),
+  RegisterEPTImage(void),
+  RegisterEXRImage(void),
+  RegisterFAXImage(void),
+  RegisterFITSImage(void),
+  RegisterFPXImage(void),
+  RegisterG3Image(void),
+  RegisterGIFImage(void),
+  RegisterGIF87Image(void),
+  RegisterGRADIENTImage(void),
+  RegisterGRANITEImage(void),
+  RegisterGRAYImage(void),
+  RegisterHALDImage(void),
+  RegisterHDRImage(void),
+  RegisterHImage(void),
+  RegisterHISTOGRAMImage(void),
+  RegisterHRZImage(void),
+  RegisterHTMLImage(void),
+  RegisterICBImage(void),
+  RegisterICONImage(void),
+  RegisterINFOImage(void),
+  RegisterINLINEImage(void),
+  RegisterIPLImage(void),
+  RegisterJBGImage(void),
+  RegisterJBIGImage(void),
+  RegisterJPGImage(void),
+  RegisterJPEGImage(void),
+  RegisterJP2Image(void),
+  RegisterLABELImage(void),
+  RegisterMACImage(void),
+  RegisterMAGICKImage(void),
+  RegisterMAPImage(void),
+  RegisterMATImage(void),
+  RegisterMATTEImage(void),
+  RegisterMETAImage(void),
+  RegisterMIFFImage(void),
+  RegisterMNGImage(void),
+  RegisterMONOImage(void),
+  RegisterMPCImage(void),
+  RegisterMPEGImage(void),
+  RegisterMPRImage(void),
+  RegisterMSLImage(void),
+  RegisterMTVImage(void),
+  RegisterMVGImage(void),
+  RegisterNETSCAPEImage(void),
+  RegisterNULLImage(void),
+  RegisterP7Image(void),
+  RegisterPBMImage(void),
+  RegisterOTBImage(void),
+  RegisterPALMImage(void),
+  RegisterPATTERNImage(void),
+  RegisterPCDImage(void),
+  RegisterPCDSImage(void),
+  RegisterPCLImage(void),
+  RegisterPCTImage(void),
+  RegisterPCXImage(void),
+  RegisterPDBImage(void),
+  RegisterPDFImage(void),
+  RegisterPESImage(void),
+  RegisterPICImage(void),
+  RegisterPICTImage(void),
+  RegisterPIXImage(void),
+  RegisterPGMImage(void),
+  RegisterPLASMAImage(void),
+  RegisterPMImage(void),
+  RegisterPNGImage(void),
+  RegisterPNMImage(void),
+  RegisterPPMImage(void),
+  RegisterPREVIEWImage(void),
+  RegisterPSImage(void),
+  RegisterPS2Image(void),
+  RegisterPS3Image(void),
+  RegisterPSDImage(void),
+  RegisterPTIFImage(void),
+  RegisterPWPImage(void),
+  RegisterRASImage(void),
+  RegisterRAWImage(void),
+  RegisterRGBImage(void),
+  RegisterRGBAImage(void),
+  RegisterRLAImage(void),
+  RegisterRLEImage(void),
+  RegisterSCRImage(void),
+  RegisterSCTImage(void),
+  RegisterSFWImage(void),
+  RegisterSGIImage(void),
+  RegisterSHTMLImage(void),
+  RegisterSTEGANOImage(void),
+  RegisterSUNImage(void),
+  RegisterSVGImage(void),
+  RegisterTEXTImage(void),
+  RegisterTGAImage(void),
+  RegisterTHUMBNAILImage(void),
+  RegisterTIFImage(void),
+  RegisterTIFFImage(void),
+  RegisterTILEImage(void),
+  RegisterTIMImage(void),
+  RegisterTTFImage(void),
+  RegisterTXTImage(void),
+  RegisterUILImage(void),
+  RegisterURLImage(void),
+  RegisterUYVYImage(void),
+  RegisterVDAImage(void),
+  RegisterVICARImage(void),
+  RegisterVIDImage(void),
+  RegisterVIFFImage(void),
+  RegisterVSTImage(void),
+  RegisterWBMPImage(void),
+  RegisterWEBPImage(void),
+  RegisterWMFImage(void),
+  RegisterWPGImage(void),
+  RegisterXImage(void),
+  RegisterXBMImage(void),
+  RegisterXCImage(void),
+  RegisterXCFImage(void),
+  RegisterXPMImage(void),
+  RegisterXPSImage(void),
+  RegisterXTRNImage(void),
+  RegisterXVImage(void),
+  RegisterXWDImage(void),
+  RegisterYCBCRImage(void),
+  RegisterYUVImage(void);
+
+extern ModuleExport void
+  UnregisterAAIImage(void),
+  UnregisterARTImage(void),
+  UnregisterAVIImage(void),
+  UnregisterAVSImage(void),
+  UnregisterBIEImage(void),
+  UnregisterBMPImage(void),
+  UnregisterBRAILLEImage(void),
+  UnregisterCALSImage(void),
+  UnregisterCAPTIONImage(void),
+  UnregisterCINImage(void),
+  UnregisterCIPImage(void),
+  UnregisterCLIPImage(void),
+  UnregisterCLIPBOARDImage(void),
+  UnregisterCMYKImage(void),
+  UnregisterCUTImage(void),
+  UnregisterDCMImage(void),
+  UnregisterDCXImage(void),
+  UnregisterDDSImage(void),
+  UnregisterDEBUGImage(void),
+  UnregisterDIBImage(void),
+  UnregisterDJVUImage(void),
+  UnregisterDNGImage(void),
+  UnregisterDPSImage(void),
+  UnregisterDPXImage(void),
+  UnregisterEMFImage(void),
+  UnregisterEPDFImage(void),
+  UnregisterEPIImage(void),
+  UnregisterEPSImage(void),
+  UnregisterEPS2Image(void),
+  UnregisterEPSFImage(void),
+  UnregisterEPSIImage(void),
+  UnregisterEPTImage(void),
+  UnregisterEXRImage(void),
+  UnregisterFAXImage(void),
+  UnregisterFITSImage(void),
+  UnregisterFPXImage(void),
+  UnregisterG3Image(void),
+  UnregisterGIFImage(void),
+  UnregisterGIF87Image(void),
+  UnregisterGRADIENTImage(void),
+  UnregisterGRANITEImage(void),
+  UnregisterGRAYImage(void),
+  UnregisterHALDImage(void),
+  UnregisterHDRImage(void),
+  UnregisterHImage(void),
+  UnregisterHISTOGRAMImage(void),
+  UnregisterHRZImage(void),
+  UnregisterHTMLImage(void),
+  UnregisterICBImage(void),
+  UnregisterICONImage(void),
+  UnregisterINFOImage(void),
+  UnregisterINLINEImage(void),
+  UnregisterIPLImage(void),
+  UnregisterJBGImage(void),
+  UnregisterJBIGImage(void),
+  UnregisterJPGImage(void),
+  UnregisterJPEGImage(void),
+  UnregisterJP2Image(void),
+  UnregisterLABELImage(void),
+  UnregisterLOCALEImage(void),
+  UnregisterMACImage(void),
+  UnregisterMAGICKImage(void),
+  UnregisterMAPImage(void),
+  UnregisterMATImage(void),
+  UnregisterMATTEImage(void),
+  UnregisterMETAImage(void),
+  UnregisterMIFFImage(void),
+  UnregisterMNGImage(void),
+  UnregisterMONOImage(void),
+  UnregisterMPCImage(void),
+  UnregisterMPEGImage(void),
+  UnregisterMPRImage(void),
+  UnregisterMSLImage(void),
+  UnregisterMTVImage(void),
+  UnregisterMVGImage(void),
+  UnregisterNETSCAPEImage(void),
+  UnregisterNULLImage(void),
+  UnregisterP7Image(void),
+  UnregisterPBMImage(void),
+  UnregisterOTBImage(void),
+  UnregisterPALMImage(void),
+  UnregisterPATTERNImage(void),
+  UnregisterPCDImage(void),
+  UnregisterPCDSImage(void),
+  UnregisterPCLImage(void),
+  UnregisterPCTImage(void),
+  UnregisterPCXImage(void),
+  UnregisterPDBImage(void),
+  UnregisterPDFImage(void),
+  UnregisterPESImage(void),
+  UnregisterPICImage(void),
+  UnregisterPICTImage(void),
+  UnregisterPIXImage(void),
+  UnregisterPLASMAImage(void),
+  UnregisterPGMImage(void),
+  UnregisterPMImage(void),
+  UnregisterPNGImage(void),
+  UnregisterPNMImage(void),
+  UnregisterPPMImage(void),
+  UnregisterPREVIEWImage(void),
+  UnregisterPSImage(void),
+  UnregisterPS2Image(void),
+  UnregisterPS3Image(void),
+  UnregisterPSDImage(void),
+  UnregisterPTIFImage(void),
+  UnregisterPWPImage(void),
+  UnregisterRASImage(void),
+  UnregisterRAWImage(void),
+  UnregisterRGBImage(void),
+  UnregisterRGBAImage(void),
+  UnregisterRLAImage(void),
+  UnregisterRLEImage(void),
+  UnregisterSCRImage(void),
+  UnregisterSCTImage(void),
+  UnregisterSFWImage(void),
+  UnregisterSGIImage(void),
+  UnregisterSHTMLImage(void),
+  UnregisterSTEGANOImage(void),
+  UnregisterSUNImage(void),
+  UnregisterSVGImage(void),
+  UnregisterTEXTImage(void),
+  UnregisterTGAImage(void),
+  UnregisterTHUMBNAILImage(void),
+  UnregisterTIFImage(void),
+  UnregisterTIFFImage(void),
+  UnregisterTILEImage(void),
+  UnregisterTIMImage(void),
+  UnregisterTTFImage(void),
+  UnregisterTXTImage(void),
+  UnregisterUILImage(void),
+  UnregisterURLImage(void),
+  UnregisterUYVYImage(void),
+  UnregisterVDAImage(void),
+  UnregisterVICARImage(void),
+  UnregisterVIDImage(void),
+  UnregisterVIFFImage(void),
+  UnregisterVSTImage(void),
+  UnregisterWBMPImage(void),
+  UnregisterWEBPImage(void),
+  UnregisterWMFImage(void),
+  UnregisterWPGImage(void),
+  UnregisterXImage(void),
+  UnregisterXBMImage(void),
+  UnregisterXCImage(void),
+  UnregisterXCFImage(void),
+  UnregisterXPMImage(void),
+  UnregisterXPSImage(void),
+  UnregisterXTRNImage(void),
+  UnregisterXVImage(void),
+  UnregisterXWDImage(void),
+  UnregisterYCBCRImage(void),
+  UnregisterYUVImage(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/statistic.c b/MagickCore/statistic.c
new file mode 100644
index 0000000..9054354
--- /dev/null
+++ b/MagickCore/statistic.c
@@ -0,0 +1,1833 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%        SSSSS  TTTTT   AAA   TTTTT  IIIII  SSSSS  TTTTT  IIIII   CCCC        %
+%        SS       T    A   A    T      I    SS       T      I    C            %
+%         SSS     T    AAAAA    T      I     SSS     T      I    C            %
+%           SS    T    A   A    T      I       SS    T      I    C            %
+%        SSSSS    T    A   A    T    IIIII  SSSSS    T    IIIII   CCCC        %
+%                                                                             %
+%                                                                             %
+%                     MagickCore Image Statistical Methods                    %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/animate.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/compress.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/display.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/magic.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/module.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
+#include "MagickCore/paint.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/profile.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/random-private.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/timer.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     E v a l u a t e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EvaluateImage() applies a value to the image with an arithmetic, relational,
+%  or logical operator to an image. Use these operations to lighten or darken
+%  an image, to increase or decrease contrast in an image, or to produce the
+%  "negative" of an image.
+%
+%  The format of the EvaluateImageChannel method is:
+%
+%      MagickBooleanType EvaluateImage(Image *image,
+%        const MagickEvaluateOperator op,const double value,
+%        ExceptionInfo *exception)
+%      MagickBooleanType EvaluateImages(Image *images,
+%        const MagickEvaluateOperator op,const double value,
+%        ExceptionInfo *exception)
+%      MagickBooleanType EvaluateImageChannel(Image *image,
+%        const ChannelType channel,const MagickEvaluateOperator op,
+%        const double value,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o op: A channel op.
+%
+%    o value: A value value.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static PixelInfo **DestroyPixelThreadSet(PixelInfo **pixels)
+{
+  register ssize_t
+    i;
+
+  assert(pixels != (PixelInfo **) NULL);
+  for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+    if (pixels[i] != (PixelInfo *) NULL)
+      pixels[i]=(PixelInfo *) RelinquishMagickMemory(pixels[i]);
+  pixels=(PixelInfo **) RelinquishMagickMemory(pixels);
+  return(pixels);
+}
+
+static PixelInfo **AcquirePixelThreadSet(const Image *image,
+  const size_t number_images)
+{
+  register ssize_t
+    i,
+    j;
+
+  PixelInfo
+    **pixels;
+
+  size_t
+    length,
+    number_threads;
+
+  number_threads=GetOpenMPMaximumThreads();
+  pixels=(PixelInfo **) AcquireQuantumMemory(number_threads,
+    sizeof(*pixels));
+  if (pixels == (PixelInfo **) NULL)
+    return((PixelInfo **) NULL);
+  (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    length=image->columns;
+    if (length < number_images)
+      length=number_images;
+    pixels[i]=(PixelInfo *) AcquireQuantumMemory(length,
+      sizeof(**pixels));
+    if (pixels[i] == (PixelInfo *) NULL)
+      return(DestroyPixelThreadSet(pixels));
+    for (j=0; j < (ssize_t) length; j++)
+      GetPixelInfo(image,&pixels[i][j]);
+  }
+  return(pixels);
+}
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int IntensityCompare(const void *x,const void *y)
+{
+  const PixelInfo
+    *color_1,
+    *color_2;
+
+  int
+    intensity;
+
+  color_1=(const PixelInfo *) x;
+  color_2=(const PixelInfo *) y;
+  intensity=(int) GetPixelInfoIntensity(color_2)-(int)
+    GetPixelInfoIntensity(color_1);
+  return(intensity);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static MagickRealType ApplyEvaluateOperator(RandomInfo *random_info,
+  Quantum pixel,const MagickEvaluateOperator op,const MagickRealType value)
+{
+  MagickRealType
+    result;
+
+  result=0.0;
+  switch (op)
+  {
+    case UndefinedEvaluateOperator:
+      break;
+    case AbsEvaluateOperator:
+    {
+      result=(MagickRealType) fabs((double) (pixel+value));
+      break;
+    }
+    case AddEvaluateOperator:
+    {
+      result=(MagickRealType) (pixel+value);
+      break;
+    }
+    case AddModulusEvaluateOperator:
+    {
+      /*
+        This returns a 'floored modulus' of the addition which is a
+        positive result.  It differs from  % or fmod() which returns a
+        'truncated modulus' result, where floor() is replaced by trunc()
+        and could return a negative result (which is clipped).
+      */
+      result=pixel+value;
+      result-=(QuantumRange+1.0)*floor((double) result/(QuantumRange+1.0));
+      break;
+    }
+    case AndEvaluateOperator:
+    {
+      result=(MagickRealType) ((size_t) pixel & (size_t) (value+0.5));
+      break;
+    }
+    case CosineEvaluateOperator:
+    {
+      result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
+        QuantumScale*pixel*value))+0.5));
+      break;
+    }
+    case DivideEvaluateOperator:
+    {
+      result=pixel/(value == 0.0 ? 1.0 : value);
+      break;
+    }
+    case ExponentialEvaluateOperator:
+    {
+      result=(MagickRealType) (QuantumRange*exp((double) (value*QuantumScale*
+        pixel)));
+      break;
+    }
+    case GaussianNoiseEvaluateOperator:
+    {
+      result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
+        GaussianNoise,value);
+      break;
+    }
+    case ImpulseNoiseEvaluateOperator:
+    {
+      result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
+        ImpulseNoise,value);
+      break;
+    }
+    case LaplacianNoiseEvaluateOperator:
+    {
+      result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
+        LaplacianNoise,value);
+      break;
+    }
+    case LeftShiftEvaluateOperator:
+    {
+      result=(MagickRealType) ((size_t) pixel << (size_t) (value+0.5));
+      break;
+    }
+    case LogEvaluateOperator:
+    {
+      result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
+        pixel+1.0))/log((double) (value+1.0)));
+      break;
+    }
+    case MaxEvaluateOperator:
+    {
+      result=(MagickRealType) MagickMax((double) pixel,value);
+      break;
+    }
+    case MeanEvaluateOperator:
+    {
+      result=(MagickRealType) (pixel+value);
+      break;
+    }
+    case MedianEvaluateOperator:
+    {
+      result=(MagickRealType) (pixel+value);
+      break;
+    }
+    case MinEvaluateOperator:
+    {
+      result=(MagickRealType) MagickMin((double) pixel,value);
+      break;
+    }
+    case MultiplicativeNoiseEvaluateOperator:
+    {
+      result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
+        MultiplicativeGaussianNoise,value);
+      break;
+    }
+    case MultiplyEvaluateOperator:
+    {
+      result=(MagickRealType) (value*pixel);
+      break;
+    }
+    case OrEvaluateOperator:
+    {
+      result=(MagickRealType) ((size_t) pixel | (size_t) (value+0.5));
+      break;
+    }
+    case PoissonNoiseEvaluateOperator:
+    {
+      result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
+        PoissonNoise,value);
+      break;
+    }
+    case PowEvaluateOperator:
+    {
+      result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
+        (double) value));
+      break;
+    }
+    case RightShiftEvaluateOperator:
+    {
+      result=(MagickRealType) ((size_t) pixel >> (size_t) (value+0.5));
+      break;
+    }
+    case SetEvaluateOperator:
+    {
+      result=value;
+      break;
+    }
+    case SineEvaluateOperator:
+    {
+      result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
+        QuantumScale*pixel*value))+0.5));
+      break;
+    }
+    case SubtractEvaluateOperator:
+    {
+      result=(MagickRealType) (pixel-value);
+      break;
+    }
+    case ThresholdEvaluateOperator:
+    {
+      result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
+        QuantumRange);
+      break;
+    }
+    case ThresholdBlackEvaluateOperator:
+    {
+      result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
+      break;
+    }
+    case ThresholdWhiteEvaluateOperator:
+    {
+      result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
+        pixel);
+      break;
+    }
+    case UniformNoiseEvaluateOperator:
+    {
+      result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
+        UniformNoise,value);
+      break;
+    }
+    case XorEvaluateOperator:
+    {
+      result=(MagickRealType) ((size_t) pixel ^ (size_t) (value+0.5));
+      break;
+    }
+  }
+  return(result);
+}
+
+MagickExport MagickBooleanType EvaluateImage(Image *image,
+  const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=EvaluateImageChannel(image,CompositeChannels,op,value,exception);
+  return(status);
+}
+
+MagickExport Image *EvaluateImages(const Image *images,
+  const MagickEvaluateOperator op,ExceptionInfo *exception)
+{
+#define EvaluateImageTag  "Evaluate/Image"
+
+  CacheView
+    *evaluate_view;
+
+  const Image
+    *next;
+
+  Image
+    *evaluate_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    **restrict evaluate_pixels,
+    zero;
+
+  RandomInfo
+    **restrict random_info;
+
+  size_t
+    number_images;
+
+  ssize_t
+    y;
+
+  /*
+    Ensure the image are the same size.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  for (next=images; next != (Image *) NULL; next=GetNextImageInList(next))
+    if ((next->columns != images->columns) || (next->rows != images->rows))
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "ImageWidthsOrHeightsDiffer","`%s'",images->filename);
+        return((Image *) NULL);
+      }
+  /*
+    Initialize evaluate next attributes.
+  */
+  evaluate_image=CloneImage(images,images->columns,images->rows,MagickTrue,
+    exception);
+  if (evaluate_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(evaluate_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&evaluate_image->exception);
+      evaluate_image=DestroyImage(evaluate_image);
+      return((Image *) NULL);
+    }
+  number_images=GetImageListLength(images);
+  evaluate_pixels=AcquirePixelThreadSet(images,number_images);
+  if (evaluate_pixels == (PixelInfo **) NULL)
+    {
+      evaluate_image=DestroyImage(evaluate_image);
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
+      return((Image *) NULL);
+    }
+  /*
+    Evaluate image pixels.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(images,&zero);
+  random_info=AcquireRandomInfoThreadSet();
+  evaluate_view=AcquireCacheView(evaluate_image);
+  if (op == MedianEvaluateOperator)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+    for (y=0; y < (ssize_t) evaluate_image->rows; y++)
+    {
+      CacheView
+        *image_view;
+
+      const Image
+        *next;
+
+      const int
+        id = GetOpenMPThreadId();
+
+      register PixelInfo
+        *evaluate_pixel;
+
+      register Quantum
+        *restrict q;
+
+      register ssize_t
+        x;
+
+      if (status == MagickFalse)
+        continue;
+      q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
+        1,exception);
+      if (q == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      evaluate_pixel=evaluate_pixels[id];
+      for (x=0; x < (ssize_t) evaluate_image->columns; x++)
+      {
+        register ssize_t
+          i;
+
+        for (i=0; i < (ssize_t) number_images; i++)
+          evaluate_pixel[i]=zero;
+        next=images;
+        for (i=0; i < (ssize_t) number_images; i++)
+        {
+          register const Quantum
+            *p;
+
+          image_view=AcquireCacheView(next);
+          p=GetCacheViewVirtualPixels(image_view,x,y,1,1,exception);
+          if (p == (const Quantum *) NULL)
+            {
+              image_view=DestroyCacheView(image_view);
+              break;
+            }
+          evaluate_pixel[i].red=ApplyEvaluateOperator(random_info[id],
+            GetPixelRed(next,p),op,evaluate_pixel[i].red);
+          evaluate_pixel[i].green=ApplyEvaluateOperator(random_info[id],
+            GetPixelGreen(next,p),op,evaluate_pixel[i].green);
+          evaluate_pixel[i].blue=ApplyEvaluateOperator(random_info[id],
+            GetPixelBlue(next,p),op,evaluate_pixel[i].blue);
+          if (evaluate_image->colorspace == CMYKColorspace)
+            evaluate_pixel[i].black=ApplyEvaluateOperator(random_info[id],
+              GetPixelBlack(next,p),op,evaluate_pixel[i].black);
+          evaluate_pixel[i].alpha=ApplyEvaluateOperator(random_info[id],
+            GetPixelAlpha(next,p),op,evaluate_pixel[i].alpha);
+          image_view=DestroyCacheView(image_view);
+          next=GetNextImageInList(next);
+        }
+        qsort((void *) evaluate_pixel,number_images,sizeof(*evaluate_pixel),
+          IntensityCompare);
+        SetPixelRed(evaluate_image,
+          ClampToQuantum(evaluate_pixel[i/2].red),q);
+        SetPixelGreen(evaluate_image,
+          ClampToQuantum(evaluate_pixel[i/2].green),q);
+        SetPixelBlue(evaluate_image,
+          ClampToQuantum(evaluate_pixel[i/2].blue),q);
+        if (evaluate_image->colorspace == CMYKColorspace)
+          SetPixelBlack(evaluate_image,
+          ClampToQuantum(evaluate_pixel[i/2].black),q);
+        if (evaluate_image->matte == MagickFalse)
+          SetPixelAlpha(evaluate_image,
+            ClampToQuantum(evaluate_pixel[i/2].alpha),q);
+        else
+          SetPixelAlpha(evaluate_image,
+            ClampToQuantum(evaluate_pixel[i/2].alpha),q);
+        q+=GetPixelChannels(evaluate_image);
+      }
+      if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
+        status=MagickFalse;
+      if (images->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp critical (MagickCore_EvaluateImages)
+#endif
+          proceed=SetImageProgress(images,EvaluateImageTag,progress++,
+            evaluate_image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+    }
+  else
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic) shared(progress,status)
+#endif
+    for (y=0; y < (ssize_t) evaluate_image->rows; y++)
+    {
+      CacheView
+        *image_view;
+
+      const Image
+        *next;
+
+      const int
+        id = GetOpenMPThreadId();
+
+      register ssize_t
+        i,
+        x;
+
+      register PixelInfo
+        *evaluate_pixel;
+
+      register Quantum
+        *restrict q;
+
+      if (status == MagickFalse)
+        continue;
+      q=QueueCacheViewAuthenticPixels(evaluate_view,0,y,evaluate_image->columns,
+        1,exception);
+      if (q == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      evaluate_pixel=evaluate_pixels[id];
+      for (x=0; x < (ssize_t) evaluate_image->columns; x++)
+        evaluate_pixel[x]=zero;
+      next=images;
+      for (i=0; i < (ssize_t) number_images; i++)
+      {
+        register const Quantum
+          *p;
+
+        image_view=AcquireCacheView(next);
+        p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          {
+            image_view=DestroyCacheView(image_view);
+            break;
+          }
+        for (x=0; x < (ssize_t) next->columns; x++)
+        {
+          evaluate_pixel[x].red=ApplyEvaluateOperator(random_info[id],
+            GetPixelRed(next,p),i == 0 ? AddEvaluateOperator : op,
+            evaluate_pixel[x].red);
+          evaluate_pixel[x].green=ApplyEvaluateOperator(random_info[id],
+            GetPixelGreen(next,p),i == 0 ? AddEvaluateOperator : op,
+              evaluate_pixel[x].green);
+          evaluate_pixel[x].blue=ApplyEvaluateOperator(random_info[id],
+            GetPixelBlue(next,p),i == 0 ? AddEvaluateOperator : op,
+              evaluate_pixel[x].blue);
+          if (evaluate_image->colorspace == CMYKColorspace)
+            evaluate_pixel[x].black=ApplyEvaluateOperator(random_info[id],
+              GetPixelBlack(next,p),i == 0 ? AddEvaluateOperator : op,
+              evaluate_pixel[x].black);
+          evaluate_pixel[x].alpha=ApplyEvaluateOperator(random_info[id],
+            GetPixelAlpha(next,p),i == 0 ? AddEvaluateOperator : op,
+            evaluate_pixel[x].alpha);
+          p+=GetPixelChannels(next);
+        }
+        image_view=DestroyCacheView(image_view);
+        next=GetNextImageInList(next);
+      }
+      if (op == MeanEvaluateOperator)
+        for (x=0; x < (ssize_t) evaluate_image->columns; x++)
+        {
+          evaluate_pixel[x].red/=number_images;
+          evaluate_pixel[x].green/=number_images;
+          evaluate_pixel[x].blue/=number_images;
+          evaluate_pixel[x].black/=number_images;
+          evaluate_pixel[x].alpha/=number_images;
+        }
+      for (x=0; x < (ssize_t) evaluate_image->columns; x++)
+      {
+        SetPixelRed(evaluate_image,ClampToQuantum(evaluate_pixel[x].red),q);
+        SetPixelGreen(evaluate_image,ClampToQuantum(evaluate_pixel[x].green),q);
+        SetPixelBlue(evaluate_image,ClampToQuantum(evaluate_pixel[x].blue),q);
+        if (evaluate_image->colorspace == CMYKColorspace)
+          SetPixelBlack(evaluate_image,
+          ClampToQuantum(evaluate_pixel[x].black),q);
+        if (evaluate_image->matte == MagickFalse)
+          SetPixelAlpha(evaluate_image,
+            ClampToQuantum(evaluate_pixel[x].alpha),q);
+        else
+          SetPixelAlpha(evaluate_image,
+            ClampToQuantum(evaluate_pixel[x].alpha),q);
+        q+=GetPixelChannels(evaluate_image);
+      }
+      if (SyncCacheViewAuthenticPixels(evaluate_view,exception) == MagickFalse)
+        status=MagickFalse;
+      if (images->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+          #pragma omp critical (MagickCore_EvaluateImages)
+#endif
+          proceed=SetImageProgress(images,EvaluateImageTag,progress++,
+            evaluate_image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+    }
+  evaluate_view=DestroyCacheView(evaluate_view);
+  evaluate_pixels=DestroyPixelThreadSet(evaluate_pixels);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  if (status == MagickFalse)
+    evaluate_image=DestroyImage(evaluate_image);
+  return(evaluate_image);
+}
+
+MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
+  const ChannelType channel,const MagickEvaluateOperator op,const double value,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RandomInfo
+    **restrict random_info;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&image->exception);
+      return(MagickFalse);
+    }
+  status=MagickTrue;
+  progress=0;
+  random_info=AcquireRandomInfoThreadSet();
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,ClampToQuantum(
+          ApplyEvaluateOperator(random_info[id],
+          GetPixelRed(image,q),op,value)),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,ClampToQuantum(
+          ApplyEvaluateOperator(random_info[id],
+          GetPixelGreen(image,q),op,value)),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,ClampToQuantum(
+          ApplyEvaluateOperator(random_info[id],
+          GetPixelBlue(image,q),op,value)),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,ClampToQuantum(
+          ApplyEvaluateOperator(random_info[id],
+          GetPixelBlack(image,q),op,value)),q);
+      if ((channel & AlphaChannel) != 0)
+        {
+          if (image->matte == MagickFalse)
+            SetPixelAlpha(image,
+              ClampToQuantum(ApplyEvaluateOperator(random_info[id],
+                GetPixelAlpha(image,q),op,value)),q);
+          else
+            SetPixelAlpha(image,
+              ClampToQuantum(ApplyEvaluateOperator(random_info[id],
+                GetPixelAlpha(image,q),op,value)),q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_EvaluateImageChannel)
+#endif
+        proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     F u n c t i o n I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FunctionImage() applies a value to the image with an arithmetic, relational,
+%  or logical operator to an image. Use these operations to lighten or darken
+%  an image, to increase or decrease contrast in an image, or to produce the
+%  "negative" of an image.
+%
+%  The format of the FunctionImageChannel method is:
+%
+%      MagickBooleanType FunctionImage(Image *image,
+%        const MagickFunction function,const ssize_t number_parameters,
+%        const double *parameters,ExceptionInfo *exception)
+%      MagickBooleanType FunctionImageChannel(Image *image,
+%        const ChannelType channel,const MagickFunction function,
+%        const ssize_t number_parameters,const double *argument,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o function: A channel function.
+%
+%    o parameters: one or more parameters.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
+  const size_t number_parameters,const double *parameters,
+  ExceptionInfo *exception)
+{
+  MagickRealType
+    result;
+
+  register ssize_t
+    i;
+
+  (void) exception;
+  result=0.0;
+  switch (function)
+  {
+    case PolynomialFunction:
+    {
+      /*
+       * Polynomial
+       * Parameters:   polynomial constants,  highest to lowest order
+       *   For example:      c0*x^3 + c1*x^2 + c2*x  + c3
+       */
+      result=0.0;
+      for (i=0; i < (ssize_t) number_parameters; i++)
+        result = result*QuantumScale*pixel + parameters[i];
+      result *= QuantumRange;
+      break;
+    }
+    case SinusoidFunction:
+    {
+      /* Sinusoid Function
+       * Parameters:   Freq, Phase, Ampl, bias
+       */
+      double  freq,phase,ampl,bias;
+      freq  = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
+      phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
+      ampl  = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
+      bias  = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
+      result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
+        (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
+      break;
+    }
+    case ArcsinFunction:
+    {
+      /* Arcsin Function  (peged at range limits for invalid results)
+       * Parameters:   Width, Center, Range, Bias
+       */
+      double  width,range,center,bias;
+      width  = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
+      center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
+      range  = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
+      bias   = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
+      result = 2.0/width*(QuantumScale*pixel - center);
+      if ( result <= -1.0 )
+        result = bias - range/2.0;
+      else if ( result >= 1.0 )
+        result = bias + range/2.0;
+      else
+        result=(MagickRealType) (range/MagickPI*asin((double) result)+bias);
+      result *= QuantumRange;
+      break;
+    }
+    case ArctanFunction:
+    {
+      /* Arctan Function
+       * Parameters:   Slope, Center, Range, Bias
+       */
+      double  slope,range,center,bias;
+      slope  = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
+      center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
+      range  = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
+      bias   = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
+      result=(MagickRealType) (MagickPI*slope*(QuantumScale*pixel-center));
+      result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
+                  result) + bias ) );
+      break;
+    }
+    case UndefinedFunction:
+      break;
+  }
+  return(ClampToQuantum(result));
+}
+
+MagickExport MagickBooleanType FunctionImage(Image *image,
+  const MagickFunction function,const size_t number_parameters,
+  const double *parameters,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=FunctionImageChannel(image,CompositeChannels,function,number_parameters,
+    parameters,exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType FunctionImageChannel(Image *image,
+  const ChannelType channel,const MagickFunction function,
+  const size_t number_parameters,const double *parameters,
+  ExceptionInfo *exception)
+{
+#define FunctionImageTag  "Function/Image "
+
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&image->exception);
+      return(MagickFalse);
+    }
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,ApplyFunction(GetPixelRed(image,q),function,
+          number_parameters,parameters,exception),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,ApplyFunction(GetPixelGreen(image,q),function,
+          number_parameters,parameters,exception),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,ApplyFunction(GetPixelBlue(image,q),function,
+          number_parameters,parameters,exception),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,ApplyFunction(GetPixelBlack(image,q),function,
+          number_parameters,parameters,exception),q);
+      if ((channel & AlphaChannel) != 0)
+        {
+          if (image->matte == MagickFalse)
+            SetPixelAlpha(image,ApplyFunction(GetPixelAlpha(image,q),function,
+              number_parameters,parameters,exception),q);
+          else
+            SetPixelAlpha(image,ApplyFunction(GetPixelAlpha(image,q),function,
+              number_parameters,parameters,exception),q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_FunctionImageChannel)
+#endif
+        proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t I m a g e C h a n n e l E x t r e m a                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelExtrema() returns the extrema of one or more image channels.
+%
+%  The format of the GetImageChannelExtrema method is:
+%
+%      MagickBooleanType GetImageChannelExtrema(const Image *image,
+%        const ChannelType channel,size_t *minima,size_t *maxima,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o minima: the minimum value in the channel.
+%
+%    o maxima: the maximum value in the channel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType GetImageExtrema(const Image *image,
+  size_t *minima,size_t *maxima,ExceptionInfo *exception)
+{
+  return(GetImageChannelExtrema(image,CompositeChannels,minima,maxima,exception));
+}
+
+MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
+  const ChannelType channel,size_t *minima,size_t *maxima,
+  ExceptionInfo *exception)
+{
+  double
+    max,
+    min;
+
+  MagickBooleanType
+    status;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  status=GetImageChannelRange(image,channel,&min,&max,exception);
+  *minima=(size_t) ceil(min-0.5);
+  *maxima=(size_t) floor(max+0.5);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l M e a n                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelMean() returns the mean and standard deviation of one or more
+%  image channels.
+%
+%  The format of the GetImageChannelMean method is:
+%
+%      MagickBooleanType GetImageChannelMean(const Image *image,
+%        const ChannelType channel,double *mean,double *standard_deviation,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o mean: the average value in the channel.
+%
+%    o standard_deviation: the standard deviation of the channel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
+  double *standard_deviation,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetImageChannelMean(image,CompositeChannels,mean,standard_deviation,
+    exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
+  const ChannelType channel,double *mean,double *standard_deviation,
+  ExceptionInfo *exception)
+{
+  ChannelStatistics
+    *channel_statistics;
+
+  size_t
+    channels;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  channel_statistics=GetImageChannelStatistics(image,exception);
+  if (channel_statistics == (ChannelStatistics *) NULL)
+    return(MagickFalse);
+  channels=0;
+  channel_statistics[CompositeChannels].mean=0.0;
+  channel_statistics[CompositeChannels].standard_deviation=0.0;
+  if ((channel & RedChannel) != 0)
+    {
+      channel_statistics[CompositeChannels].mean+=
+        channel_statistics[RedChannel].mean;
+      channel_statistics[CompositeChannels].standard_deviation+=
+        channel_statistics[RedChannel].variance-
+        channel_statistics[RedChannel].mean*
+        channel_statistics[RedChannel].mean;
+      channels++;
+    }
+  if ((channel & GreenChannel) != 0)
+    {
+      channel_statistics[CompositeChannels].mean+=
+        channel_statistics[GreenChannel].mean;
+      channel_statistics[CompositeChannels].standard_deviation+=
+        channel_statistics[GreenChannel].variance-
+        channel_statistics[GreenChannel].mean*
+        channel_statistics[GreenChannel].mean;
+      channels++;
+    }
+  if ((channel & BlueChannel) != 0)
+    {
+      channel_statistics[CompositeChannels].mean+=
+        channel_statistics[BlueChannel].mean;
+      channel_statistics[CompositeChannels].standard_deviation+=
+        channel_statistics[BlueChannel].variance-
+        channel_statistics[BlueChannel].mean*
+        channel_statistics[BlueChannel].mean;
+      channels++;
+    }
+  if (((channel & BlackChannel) != 0) &&
+      (image->colorspace == CMYKColorspace))
+    {
+      channel_statistics[CompositeChannels].mean+=
+        channel_statistics[BlackChannel].mean;
+      channel_statistics[CompositeChannels].standard_deviation+=
+        channel_statistics[BlackChannel].variance-
+        channel_statistics[BlackChannel].mean*
+        channel_statistics[BlackChannel].mean;
+      channels++;
+    }
+  if (((channel & AlphaChannel) != 0) &&
+      (image->matte != MagickFalse))
+    {
+      channel_statistics[CompositeChannels].mean+=
+        channel_statistics[AlphaChannel].mean;
+      channel_statistics[CompositeChannels].standard_deviation+=
+        channel_statistics[AlphaChannel].variance-
+        channel_statistics[AlphaChannel].mean*
+        channel_statistics[AlphaChannel].mean;
+      channels++;
+    }
+  channel_statistics[CompositeChannels].mean/=channels;
+  channel_statistics[CompositeChannels].standard_deviation=
+    sqrt(channel_statistics[CompositeChannels].standard_deviation/channels);
+  *mean=channel_statistics[CompositeChannels].mean;
+  *standard_deviation=channel_statistics[CompositeChannels].standard_deviation;
+  channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
+    channel_statistics);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l K u r t o s i s                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
+%  image channels.
+%
+%  The format of the GetImageChannelKurtosis method is:
+%
+%      MagickBooleanType GetImageChannelKurtosis(const Image *image,
+%        const ChannelType channel,double *kurtosis,double *skewness,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o kurtosis: the kurtosis of the channel.
+%
+%    o skewness: the skewness of the channel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
+  double *kurtosis,double *skewness,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=GetImageChannelKurtosis(image,CompositeChannels,kurtosis,skewness,
+    exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
+  const ChannelType channel,double *kurtosis,double *skewness,
+  ExceptionInfo *exception)
+{
+  double
+    area,
+    mean,
+    standard_deviation,
+    sum_squares,
+    sum_cubes,
+    sum_fourth_power;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  *kurtosis=0.0;
+  *skewness=0.0;
+  area=0.0;
+  mean=0.0;
+  standard_deviation=0.0;
+  sum_squares=0.0;
+  sum_cubes=0.0;
+  sum_fourth_power=0.0;
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          mean+=GetPixelRed(image,p);
+          sum_squares+=(double) GetPixelRed(image,p)*GetPixelRed(image,p);
+          sum_cubes+=(double) GetPixelRed(image,p)*GetPixelRed(image,p)*
+            GetPixelRed(image,p);
+          sum_fourth_power+=(double) GetPixelRed(image,p)*
+            GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p);
+          area++;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          mean+=GetPixelGreen(image,p);
+          sum_squares+=(double) GetPixelGreen(image,p)*GetPixelGreen(image,p);
+          sum_cubes+=(double) GetPixelGreen(image,p)*GetPixelGreen(image,p)*
+            GetPixelGreen(image,p);
+          sum_fourth_power+=(double) GetPixelGreen(image,p)*
+            GetPixelGreen(image,p)*GetPixelGreen(image,p)*
+            GetPixelGreen(image,p);
+          area++;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          mean+=GetPixelBlue(image,p);
+          sum_squares+=(double) GetPixelBlue(image,p)*GetPixelBlue(image,p);
+          sum_cubes+=(double) GetPixelBlue(image,p)*GetPixelBlue(image,p)*
+            GetPixelBlue(image,p);
+          sum_fourth_power+=(double) GetPixelBlue(image,p)*
+            GetPixelBlue(image,p)*GetPixelBlue(image,p)*
+            GetPixelBlue(image,p);
+          area++;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          mean+=GetPixelBlack(image,p);
+          sum_squares+=(double) GetPixelBlack(image,p)*GetPixelBlack(image,p);
+          sum_cubes+=(double) GetPixelBlack(image,p)*GetPixelBlack(image,p)*
+            GetPixelBlack(image,p);
+          sum_fourth_power+=(double) GetPixelBlack(image,p)*
+            GetPixelBlack(image,p)*GetPixelBlack(image,p)*
+            GetPixelBlack(image,p);
+          area++;
+        }
+      if ((channel & AlphaChannel) != 0)
+        {
+          mean+=GetPixelAlpha(image,p);
+          sum_squares+=(double) GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
+          sum_cubes+=(double) GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
+            GetPixelAlpha(image,p);
+          sum_fourth_power+=(double) GetPixelAlpha(image,p)*
+            GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
+            GetPixelAlpha(image,p);
+          area++;
+        }
+      p+=GetPixelChannels(image);
+    }
+  }
+  if (y < (ssize_t) image->rows)
+    return(MagickFalse);
+  if (area != 0.0)
+    {
+      mean/=area;
+      sum_squares/=area;
+      sum_cubes/=area;
+      sum_fourth_power/=area;
+    }
+  standard_deviation=sqrt(sum_squares-(mean*mean));
+  if (standard_deviation != 0.0)
+    {
+      *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
+        3.0*mean*mean*mean*mean;
+      *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
+        standard_deviation;
+      *kurtosis-=3.0;
+      *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
+      *skewness/=standard_deviation*standard_deviation*standard_deviation;
+    }
+  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l R a n g e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelRange() returns the range of one or more image channels.
+%
+%  The format of the GetImageChannelRange method is:
+%
+%      MagickBooleanType GetImageChannelRange(const Image *image,
+%        const ChannelType channel,double *minima,double *maxima,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel.
+%
+%    o minima: the minimum value in the channel.
+%
+%    o maxima: the maximum value in the channel.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType GetImageRange(const Image *image,
+  double *minima,double *maxima,ExceptionInfo *exception)
+{
+  return(GetImageChannelRange(image,CompositeChannels,minima,maxima,exception));
+}
+
+MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
+  const ChannelType channel,double *minima,double *maxima,
+  ExceptionInfo *exception)
+{
+  PixelInfo
+    pixel;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  *maxima=(-1.0E-37);
+  *minima=1.0E+37;
+  GetPixelInfo(image,&pixel);
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelInfo(image,p,&pixel);
+      if ((channel & RedChannel) != 0)
+        {
+          if (pixel.red < *minima)
+            *minima=(double) pixel.red;
+          if (pixel.red > *maxima)
+            *maxima=(double) pixel.red;
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          if (pixel.green < *minima)
+            *minima=(double) pixel.green;
+          if (pixel.green > *maxima)
+            *maxima=(double) pixel.green;
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          if (pixel.blue < *minima)
+            *minima=(double) pixel.blue;
+          if (pixel.blue > *maxima)
+            *maxima=(double) pixel.blue;
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          if (pixel.black < *minima)
+            *minima=(double) pixel.black;
+          if (pixel.black > *maxima)
+            *maxima=(double) pixel.black;
+        }
+      if ((channel & AlphaChannel) != 0)
+        {
+          if (pixel.alpha < *minima)
+            *minima=(double) pixel.alpha;
+          if (pixel.alpha > *maxima)
+            *maxima=(double) pixel.alpha;
+        }
+      p+=GetPixelChannels(image);
+    }
+  }
+  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t I m a g e C h a n n e l S t a t i s t i c s                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetImageChannelStatistics() returns statistics for each channel in the
+%  image.  The statistics include the channel depth, its minima, maxima, mean,
+%  standard deviation, kurtosis and skewness.  You can access the red channel
+%  mean, for example, like this:
+%
+%      channel_statistics=GetImageChannelStatistics(image,exception);
+%      red_mean=channel_statistics[RedChannel].mean;
+%
+%  Use MagickRelinquishMemory() to free the statistics buffer.
+%
+%  The format of the GetImageChannelStatistics method is:
+%
+%      ChannelStatistics *GetImageChannelStatistics(const Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
+  ExceptionInfo *exception)
+{
+  ChannelStatistics
+    *channel_statistics;
+
+  double
+    area;
+
+  MagickStatusType
+    status;
+
+  QuantumAny
+    range;
+
+  register ssize_t
+    i;
+
+  size_t
+    channels,
+    depth,
+    length;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  length=CompositeChannels+1UL;
+  channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
+    sizeof(*channel_statistics));
+  if (channel_statistics == (ChannelStatistics *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(channel_statistics,0,length*
+    sizeof(*channel_statistics));
+  for (i=0; i <= (ssize_t) CompositeChannels; i++)
+  {
+    channel_statistics[i].depth=1;
+    channel_statistics[i].maxima=(-1.0E-37);
+    channel_statistics[i].minima=1.0E+37;
+  }
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (ssize_t) image->columns; )
+    {
+      if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+        {
+          depth=channel_statistics[RedChannel].depth;
+          range=GetQuantumRange(depth);
+          status=GetPixelRed(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelRed(image,p),range),range) ? MagickTrue : MagickFalse;
+          if (status != MagickFalse)
+            {
+              channel_statistics[RedChannel].depth++;
+              continue;
+            }
+        }
+      if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+        {
+          depth=channel_statistics[GreenChannel].depth;
+          range=GetQuantumRange(depth);
+          status=GetPixelGreen(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelGreen(image,p),range),range) ? MagickTrue : MagickFalse;
+          if (status != MagickFalse)
+            {
+              channel_statistics[GreenChannel].depth++;
+              continue;
+            }
+        }
+      if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+        {
+          depth=channel_statistics[BlueChannel].depth;
+          range=GetQuantumRange(depth);
+          status=GetPixelBlue(image,p) != ScaleAnyToQuantum(ScaleQuantumToAny(
+            GetPixelBlue(image,p),range),range) ? MagickTrue : MagickFalse;
+          if (status != MagickFalse)
+            {
+              channel_statistics[BlueChannel].depth++;
+              continue;
+            }
+        }
+      if (image->matte != MagickFalse)
+        {
+          if (channel_statistics[AlphaChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+            {
+              depth=channel_statistics[AlphaChannel].depth;
+              range=GetQuantumRange(depth);
+              status=GetPixelAlpha(image,p) != ScaleAnyToQuantum(
+                ScaleQuantumToAny(GetPixelAlpha(image,p),range),range) ?
+                MagickTrue : MagickFalse;
+              if (status != MagickFalse)
+                {
+                  channel_statistics[AlphaChannel].depth++;
+                  continue;
+                }
+            }
+          }
+      if (image->colorspace == CMYKColorspace)
+        {
+          if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
+            {
+              depth=channel_statistics[BlackChannel].depth;
+              range=GetQuantumRange(depth);
+              status=GetPixelBlack(image,p) != ScaleAnyToQuantum(
+                ScaleQuantumToAny(GetPixelBlack(image,p),range),range) ?
+                MagickTrue : MagickFalse;
+              if (status != MagickFalse)
+                {
+                  channel_statistics[BlackChannel].depth++;
+                  continue;
+                }
+            }
+        }
+      if ((double) GetPixelRed(image,p) < channel_statistics[RedChannel].minima)
+        channel_statistics[RedChannel].minima=(double) GetPixelRed(image,p);
+      if ((double) GetPixelRed(image,p) > channel_statistics[RedChannel].maxima)
+        channel_statistics[RedChannel].maxima=(double) GetPixelRed(image,p);
+      channel_statistics[RedChannel].sum+=GetPixelRed(image,p);
+      channel_statistics[RedChannel].sum_squared+=(double)
+        GetPixelRed(image,p)*GetPixelRed(image,p);
+      channel_statistics[RedChannel].sum_cubed+=(double)
+        GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p);
+      channel_statistics[RedChannel].sum_fourth_power+=(double)
+        GetPixelRed(image,p)*GetPixelRed(image,p)*GetPixelRed(image,p)*
+        GetPixelRed(image,p);
+      if ((double) GetPixelGreen(image,p) < channel_statistics[GreenChannel].minima)
+        channel_statistics[GreenChannel].minima=(double)
+          GetPixelGreen(image,p);
+      if ((double) GetPixelGreen(image,p) > channel_statistics[GreenChannel].maxima)
+        channel_statistics[GreenChannel].maxima=(double) GetPixelGreen(image,p);
+      channel_statistics[GreenChannel].sum+=GetPixelGreen(image,p);
+      channel_statistics[GreenChannel].sum_squared+=(double)
+        GetPixelGreen(image,p)*GetPixelGreen(image,p);
+      channel_statistics[GreenChannel].sum_cubed+=(double)
+        GetPixelGreen(image,p)*GetPixelGreen(image,p)*GetPixelGreen(image,p);
+      channel_statistics[GreenChannel].sum_fourth_power+=(double)
+        GetPixelGreen(image,p)*GetPixelGreen(image,p)*GetPixelGreen(image,p)*
+        GetPixelGreen(image,p);
+      if ((double) GetPixelBlue(image,p) < channel_statistics[BlueChannel].minima)
+        channel_statistics[BlueChannel].minima=(double) GetPixelBlue(image,p);
+      if ((double) GetPixelBlue(image,p) > channel_statistics[BlueChannel].maxima)
+        channel_statistics[BlueChannel].maxima=(double) GetPixelBlue(image,p);
+      channel_statistics[BlueChannel].sum+=GetPixelBlue(image,p);
+      channel_statistics[BlueChannel].sum_squared+=(double)
+        GetPixelBlue(image,p)*GetPixelBlue(image,p);
+      channel_statistics[BlueChannel].sum_cubed+=(double)
+        GetPixelBlue(image,p)*GetPixelBlue(image,p)*GetPixelBlue(image,p);
+      channel_statistics[BlueChannel].sum_fourth_power+=(double)
+        GetPixelBlue(image,p)*GetPixelBlue(image,p)*GetPixelBlue(image,p)*
+        GetPixelBlue(image,p);
+      if (image->colorspace == CMYKColorspace)
+        {
+          if ((double) GetPixelBlack(image,p) < channel_statistics[BlackChannel].minima)
+            channel_statistics[BlackChannel].minima=(double)
+              GetPixelBlack(image,p);
+          if ((double) GetPixelBlack(image,p) > channel_statistics[BlackChannel].maxima)
+            channel_statistics[BlackChannel].maxima=(double)
+              GetPixelBlack(image,p);
+          channel_statistics[BlackChannel].sum+=GetPixelBlack(image,p);
+          channel_statistics[BlackChannel].sum_squared+=(double)
+            GetPixelBlack(image,p)*GetPixelBlack(image,p);
+          channel_statistics[BlackChannel].sum_cubed+=(double)
+            GetPixelBlack(image,p)*GetPixelBlack(image,p)*
+            GetPixelBlack(image,p);
+          channel_statistics[BlackChannel].sum_fourth_power+=(double)
+            GetPixelBlack(image,p)*GetPixelBlack(image,p)*
+            GetPixelBlack(image,p)*GetPixelBlack(image,p);
+        }
+      if (image->matte != MagickFalse)
+        {
+          if ((double) GetPixelAlpha(image,p) < channel_statistics[AlphaChannel].minima)
+            channel_statistics[AlphaChannel].minima=(double)
+              GetPixelAlpha(image,p);
+          if ((double) GetPixelAlpha(image,p) > channel_statistics[AlphaChannel].maxima)
+            channel_statistics[AlphaChannel].maxima=(double)
+              GetPixelAlpha(image,p);
+          channel_statistics[AlphaChannel].sum+=GetPixelAlpha(image,p);
+          channel_statistics[AlphaChannel].sum_squared+=(double)
+            GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
+          channel_statistics[AlphaChannel].sum_cubed+=(double)
+            GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
+            GetPixelAlpha(image,p);
+          channel_statistics[AlphaChannel].sum_fourth_power+=(double)
+            GetPixelAlpha(image,p)*GetPixelAlpha(image,p)*
+            GetPixelAlpha(image,p)*GetPixelAlpha(image,p);
+        }
+      x++;
+      p+=GetPixelChannels(image);
+    }
+  }
+  area=(double) image->columns*image->rows;
+  for (i=0; i < (ssize_t) CompositeChannels; i++)
+  {
+    channel_statistics[i].sum/=area;
+    channel_statistics[i].sum_squared/=area;
+    channel_statistics[i].sum_cubed/=area;
+    channel_statistics[i].sum_fourth_power/=area;
+    channel_statistics[i].mean=channel_statistics[i].sum;
+    channel_statistics[i].variance=channel_statistics[i].sum_squared;
+    channel_statistics[i].standard_deviation=sqrt(
+      channel_statistics[i].variance-(channel_statistics[i].mean*
+      channel_statistics[i].mean));
+  }
+  for (i=0; i < (ssize_t) CompositeChannels; i++)
+  {
+    channel_statistics[CompositeChannels].depth=(size_t) MagickMax((double)
+      channel_statistics[CompositeChannels].depth,(double)
+      channel_statistics[i].depth);
+    channel_statistics[CompositeChannels].minima=MagickMin(
+      channel_statistics[CompositeChannels].minima,
+      channel_statistics[i].minima);
+    channel_statistics[CompositeChannels].maxima=MagickMax(
+      channel_statistics[CompositeChannels].maxima,
+      channel_statistics[i].maxima);
+    channel_statistics[CompositeChannels].sum+=channel_statistics[i].sum;
+    channel_statistics[CompositeChannels].sum_squared+=
+      channel_statistics[i].sum_squared;
+    channel_statistics[CompositeChannels].sum_cubed+=
+      channel_statistics[i].sum_cubed;
+    channel_statistics[CompositeChannels].sum_fourth_power+=
+      channel_statistics[i].sum_fourth_power;
+    channel_statistics[CompositeChannels].mean+=channel_statistics[i].mean;
+    channel_statistics[CompositeChannels].variance+=
+      channel_statistics[i].variance-channel_statistics[i].mean*
+      channel_statistics[i].mean;
+    channel_statistics[CompositeChannels].standard_deviation+=
+      channel_statistics[i].variance-channel_statistics[i].mean*
+      channel_statistics[i].mean;
+  }
+  channels=3;
+  if (image->matte != MagickFalse)
+    channels++;
+  if (image->colorspace == CMYKColorspace)
+    channels++;
+  channel_statistics[CompositeChannels].sum/=channels;
+  channel_statistics[CompositeChannels].sum_squared/=channels;
+  channel_statistics[CompositeChannels].sum_cubed/=channels;
+  channel_statistics[CompositeChannels].sum_fourth_power/=channels;
+  channel_statistics[CompositeChannels].mean/=channels;
+  channel_statistics[CompositeChannels].variance/=channels;
+  channel_statistics[CompositeChannels].standard_deviation=
+    sqrt(channel_statistics[CompositeChannels].standard_deviation/channels);
+  channel_statistics[CompositeChannels].kurtosis/=channels;
+  channel_statistics[CompositeChannels].skewness/=channels;
+  for (i=0; i <= (ssize_t) CompositeChannels; i++)
+  {
+    if (channel_statistics[i].standard_deviation == 0.0)
+      continue;
+    channel_statistics[i].skewness=(channel_statistics[i].sum_cubed-
+      3.0*channel_statistics[i].mean*channel_statistics[i].sum_squared+
+      2.0*channel_statistics[i].mean*channel_statistics[i].mean*
+      channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
+      channel_statistics[i].standard_deviation*
+      channel_statistics[i].standard_deviation);
+    channel_statistics[i].kurtosis=(channel_statistics[i].sum_fourth_power-
+      4.0*channel_statistics[i].mean*channel_statistics[i].sum_cubed+
+      6.0*channel_statistics[i].mean*channel_statistics[i].mean*
+      channel_statistics[i].sum_squared-3.0*channel_statistics[i].mean*
+      channel_statistics[i].mean*1.0*channel_statistics[i].mean*
+      channel_statistics[i].mean)/(channel_statistics[i].standard_deviation*
+      channel_statistics[i].standard_deviation*
+      channel_statistics[i].standard_deviation*
+      channel_statistics[i].standard_deviation)-3.0;
+  }
+  return(channel_statistics);
+}
diff --git a/MagickCore/statistic.h b/MagickCore/statistic.h
new file mode 100644
index 0000000..1ce8e50
--- /dev/null
+++ b/MagickCore/statistic.h
@@ -0,0 +1,120 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore statistical methods.
+*/
+#ifndef _MAGICKCORE_STATISTIC_H
+#define _MAGICKCORE_STATISTIC_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _ChannelStatistics
+{
+  size_t
+    depth;
+
+  double
+    minima,
+    maxima,
+    sum,
+    sum_squared,
+    sum_cubed,
+    sum_fourth_power,
+    mean,
+    variance,
+    standard_deviation,
+    kurtosis,
+    skewness;
+} ChannelStatistics;
+
+typedef enum
+{
+  UndefinedEvaluateOperator,
+  AddEvaluateOperator,
+  AndEvaluateOperator,
+  DivideEvaluateOperator,
+  LeftShiftEvaluateOperator,
+  MaxEvaluateOperator,
+  MinEvaluateOperator,
+  MultiplyEvaluateOperator,
+  OrEvaluateOperator,
+  RightShiftEvaluateOperator,
+  SetEvaluateOperator,
+  SubtractEvaluateOperator,
+  XorEvaluateOperator,
+  PowEvaluateOperator,
+  LogEvaluateOperator,
+  ThresholdEvaluateOperator,
+  ThresholdBlackEvaluateOperator,
+  ThresholdWhiteEvaluateOperator,
+  GaussianNoiseEvaluateOperator,
+  ImpulseNoiseEvaluateOperator,
+  LaplacianNoiseEvaluateOperator,
+  MultiplicativeNoiseEvaluateOperator,
+  PoissonNoiseEvaluateOperator,
+  UniformNoiseEvaluateOperator,
+  CosineEvaluateOperator,
+  SineEvaluateOperator,
+  AddModulusEvaluateOperator,
+  MeanEvaluateOperator,
+  AbsEvaluateOperator,
+  ExponentialEvaluateOperator,
+  MedianEvaluateOperator
+} MagickEvaluateOperator;
+
+typedef enum
+{
+  UndefinedFunction,
+  PolynomialFunction,
+  SinusoidFunction,
+  ArcsinFunction,
+  ArctanFunction
+} MagickFunction;
+
+extern MagickExport ChannelStatistics
+  *GetImageChannelStatistics(const Image *,ExceptionInfo *);
+
+extern MagickExport Image
+  *EvaluateImages(const Image *,const MagickEvaluateOperator,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  EvaluateImage(Image *,const MagickEvaluateOperator,const double,
+    ExceptionInfo *),
+  EvaluateImageChannel(Image *,const ChannelType,const MagickEvaluateOperator,
+    const double,ExceptionInfo *),
+  FunctionImage(Image *,const MagickFunction,const size_t,const double *,
+    ExceptionInfo *),
+  FunctionImageChannel(Image *,const ChannelType,const MagickFunction,
+    const size_t,const double *,ExceptionInfo *),
+  GetImageChannelExtrema(const Image *,const ChannelType,size_t *,size_t *,
+    ExceptionInfo *),
+  GetImageChannelMean(const Image *,const ChannelType,double *,double *,
+    ExceptionInfo *),
+  GetImageChannelKurtosis(const Image *,const ChannelType,double *,double *,
+    ExceptionInfo *),
+  GetImageChannelRange(const Image *,const ChannelType,double *,double *,
+    ExceptionInfo *),
+  GetImageExtrema(const Image *,size_t *,size_t *,ExceptionInfo *),
+  GetImageRange(const Image *,double *,double *,ExceptionInfo *),
+  GetImageMean(const Image *,double *,double *,ExceptionInfo *),
+  GetImageKurtosis(const Image *,double *,double *,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/stream-private.h b/MagickCore/stream-private.h
new file mode 100644
index 0000000..9912d6d
--- /dev/null
+++ b/MagickCore/stream-private.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image stream private methods.
+*/
+#ifndef _MAGICKCORE_STREAM_PRIVATE_H
+#define _MAGICKCORE_STREAM_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _StreamInfo
+  StreamInfo;
+
+extern MagickExport const void
+  *GetStreamInfoClientData(StreamInfo *);
+
+extern MagickExport Image
+  *StreamImage(const ImageInfo *,StreamInfo *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  OpenStream(const ImageInfo *,StreamInfo *,const char *,ExceptionInfo *);
+
+extern MagickExport StreamInfo
+  *AcquireStreamInfo(const ImageInfo *),
+  *DestroyStreamInfo(StreamInfo *);
+
+extern MagickExport void
+  SetStreamInfoClientData(StreamInfo *,const void *),
+  SetStreamInfoMap(StreamInfo *,const char *),
+  SetStreamInfoStorageType(StreamInfo *,const StorageType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/stream.c b/MagickCore/stream.c
new file mode 100644
index 0000000..ee3a483
--- /dev/null
+++ b/MagickCore/stream.c
@@ -0,0 +1,2701 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  SSSSS  TTTTT  RRRR   EEEEE   AAA   M   M                   %
+%                  SS       T    R   R  E      A   A  MM MM                   %
+%                   SSS     T    RRRR   EEE    AAAAA  M M M                   %
+%                     SS    T    R R    E      A   A  M   M                   %
+%                  SSSSS    T    R  R   EEEEE  A   A  M   M                   %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Pixel Stream Methods                       %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 March 2000                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/composite-private.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/pixel.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/stream.h"
+#include "MagickCore/stream-private.h"
+#include "MagickCore/string_.h"
+
+/*
+  Typedef declaractions.
+*/
+struct _StreamInfo
+{
+  const ImageInfo
+    *image_info;
+
+  const Image
+    *image;
+
+  Image
+    *stream;
+
+  QuantumInfo
+    *quantum_info;
+
+  char
+    *map;
+
+  StorageType
+    storage_type;
+
+  unsigned char
+    *pixels;
+
+  RectangleInfo
+    extract_info;
+
+  ssize_t
+    y;
+
+  ExceptionInfo
+    *exception;
+
+  const void
+    *client_data;
+
+  size_t
+    signature;
+};
+
+/*
+  Declare pixel cache interfaces.
+*/
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static const Quantum
+  *GetVirtualPixelStream(const Image *,const VirtualPixelMethod,const ssize_t,
+    const ssize_t,const size_t,const size_t,ExceptionInfo *);
+
+static MagickBooleanType
+  StreamImagePixels(const StreamInfo *,const Image *,ExceptionInfo *),
+  SyncAuthenticPixelsStream(Image *,ExceptionInfo *);
+
+static Quantum
+  *QueueAuthenticPixelsStream(Image *,const ssize_t,const ssize_t,const size_t,
+    const size_t,ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   A c q u i r e S t r e a m I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireStreamInfo() allocates the StreamInfo structure.
+%
+%  The format of the AcquireStreamInfo method is:
+%
+%      StreamInfo *AcquireStreamInfo(const ImageInfo *image_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+*/
+MagickExport StreamInfo *AcquireStreamInfo(const ImageInfo *image_info)
+{
+  StreamInfo
+    *stream_info;
+
+  stream_info=(StreamInfo *) AcquireMagickMemory(sizeof(*stream_info));
+  if (stream_info == (StreamInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(stream_info,0,sizeof(*stream_info));
+  stream_info->pixels=(unsigned char *) AcquireMagickMemory(
+    sizeof(*stream_info->pixels));
+  if (stream_info->pixels == (unsigned char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  stream_info->map=ConstantString("RGB");
+  stream_info->storage_type=CharPixel;
+  stream_info->stream=AcquireImage(image_info);
+  stream_info->signature=MagickSignature;
+  return(stream_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y P i x e l S t r e a m                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyPixelStream() deallocates memory associated with the pixel stream.
+%
+%  The format of the DestroyPixelStream() method is:
+%
+%      void DestroyPixelStream(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+
+static inline void RelinquishStreamPixels(CacheInfo *cache_info)
+{
+  assert(cache_info != (CacheInfo *) NULL);
+  if (cache_info->mapped == MagickFalse)
+    (void) RelinquishMagickMemory(cache_info->pixels);
+  else
+    (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
+  cache_info->pixels=(Quantum *) NULL;
+  cache_info->metacontent=(void *) NULL;
+  cache_info->length=0;
+  cache_info->mapped=MagickFalse;
+}
+
+static void DestroyPixelStream(Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    destroy;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  destroy=MagickFalse;
+  LockSemaphoreInfo(cache_info->semaphore);
+  cache_info->reference_count--;
+  if (cache_info->reference_count == 0)
+    destroy=MagickTrue;
+  UnlockSemaphoreInfo(cache_info->semaphore);
+  if (destroy == MagickFalse)
+    return;
+  RelinquishStreamPixels(cache_info);
+  if (cache_info->nexus_info != (NexusInfo **) NULL)
+    cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
+      cache_info->number_threads);
+  if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&cache_info->disk_semaphore);
+  if (cache_info->semaphore != (SemaphoreInfo *) NULL)
+    DestroySemaphoreInfo(&cache_info->semaphore);
+  cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   D e s t r o y S t r e a m I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyStreamInfo() destroys memory associated with the StreamInfo
+%  structure.
+%
+%  The format of the DestroyStreamInfo method is:
+%
+%      StreamInfo *DestroyStreamInfo(StreamInfo *stream_info)
+%
+%  A description of each parameter follows:
+%
+%    o stream_info: the stream info.
+%
+*/
+MagickExport StreamInfo *DestroyStreamInfo(StreamInfo *stream_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  if (stream_info->map != (char *) NULL)
+    stream_info->map=DestroyString(stream_info->map);
+  if (stream_info->pixels != (unsigned char *) NULL)
+    stream_info->pixels=(unsigned char *) RelinquishMagickMemory(
+      stream_info->pixels);
+  if (stream_info->stream != (Image *) NULL)
+    {
+      (void) CloseBlob(stream_info->stream);
+      stream_info->stream=DestroyImage(stream_info->stream);
+    }
+  if (stream_info->quantum_info != (QuantumInfo *) NULL)
+    stream_info->quantum_info=DestroyQuantumInfo(stream_info->quantum_info);
+  stream_info->signature=(~MagickSignature);
+  stream_info=(StreamInfo *) RelinquishMagickMemory(stream_info);
+  return(stream_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c M e t a c o n t e n t F r o m S t r e a m         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticMetacontentFromStream() returns the metacontent corresponding
+%  with the last call to QueueAuthenticPixelsStream() or
+%  GetAuthenticPixelsStream().
+%
+%  The format of the GetAuthenticMetacontentFromStream() method is:
+%
+%      void *GetAuthenticMetacontentFromStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static void *GetAuthenticMetacontentFromStream(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  return(cache_info->metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c P i x e l S t r e a m                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixelsStream() gets pixels from the in-memory or disk pixel
+%  cache as defined by the geometry parameters.   A pointer to the pixels is
+%  returned if the pixels are transferred, otherwise a NULL is returned.  For
+%  streams this method is a no-op.
+%
+%  The format of the GetAuthenticPixelsStream() method is:
+%
+%      Quantum *GetAuthenticPixelsStream(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static Quantum *GetAuthenticPixelsStream(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  Quantum
+    *pixels;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  pixels=QueueAuthenticPixelsStream(image,x,y,columns,rows,exception);
+  return(pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t A u t h e n t i c P i x e l F r o m S t e a m                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetAuthenticPixelsFromStream() returns the pixels associated with the last
+%  call to QueueAuthenticPixelsStream() or GetAuthenticPixelsStream().
+%
+%  The format of the GetAuthenticPixelsFromStream() method is:
+%
+%      Quantum *GetAuthenticPixelsFromStream(const Image image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static Quantum *GetAuthenticPixelsFromStream(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  return(cache_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t O n e A u t h e n t i c P i x e l F r o m S t r e a m               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneAuthenticPixelFromStream() returns a single pixel at the specified
+%  (x,y) location.  The image background color is returned if an error occurs.
+%
+%  The format of the GetOneAuthenticPixelFromStream() method is:
+%
+%      MagickBooleanType GetOneAuthenticPixelFromStream(const Image image,
+%        const ssize_t x,const ssize_t y,PixelPacket *pixel,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType GetOneAuthenticPixelFromStream(Image *image,
+  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+{
+  register Quantum
+    *q;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *pixel=image->background_color;
+  q=GetAuthenticPixelsStream(image,x,y,1,1,exception);
+  if (q != (Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,q,pixel);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t O n e V i r t u a l P i x e l F r o m S t r e a m                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetOneVirtualPixelFromStream() returns a single pixel at the specified
+%  (x.y) location.  The image background color is returned if an error occurs.
+%
+%  The format of the GetOneVirtualPixelFromStream() method is:
+%
+%      MagickBooleanType GetOneVirtualPixelFromStream(const Image image,
+%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
+%        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y:  These values define the location of the pixel to return.
+%
+%    o pixel: return a pixel at the specified (x,y) location.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType GetOneVirtualPixelFromStream(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
+  PixelPacket *pixel,ExceptionInfo *exception)
+{
+  const Quantum
+    *q;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  *pixel=image->background_color;
+  q=GetVirtualPixelStream(image,virtual_pixel_method,x,y,1,1,exception);
+  if (q != (const Quantum *) NULL)
+    return(MagickFalse);
+  GetPixelPacket(image,q,pixel);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t S t r e a m I n f o C l i e n t D a t a                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetStreamInfoClientData() gets the stream info client data.
+%
+%  The format of the SetStreamInfoClientData method is:
+%
+%      const void *GetStreamInfoClientData(StreamInfo *stream_info)
+%
+%  A description of each parameter follows:
+%
+%    o stream_info: the stream info.
+%
+*/
+MagickExport const void *GetStreamInfoClientData(StreamInfo *stream_info)
+{
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  return(stream_info->client_data);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t  V i r t u a l P i x e l s F r o m S t r e a m                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelsStream() returns the pixels associated with the last
+%  call to QueueAuthenticPixelsStream() or GetVirtualPixelStream().
+%
+%  The format of the GetVirtualPixelsStream() method is:
+%
+%      const Quantum *GetVirtualPixelsStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o pixels: return the pixels associated corresponding with the last call to
+%      QueueAuthenticPixelsStream() or GetVirtualPixelStream().
+%
+%    o image: the image.
+%
+*/
+static const Quantum *GetVirtualPixelsStream(const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  return(cache_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l I n d e x e s F r o m S t r e a m                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualMetacontentFromStream() returns the associated pixel 
+%  channels corresponding with the last call to QueueAuthenticPixelsStream() or
+%  GetVirtualPixelStream().
+%
+%  The format of the GetVirtualMetacontentFromStream() method is:
+%
+%      const void *GetVirtualMetacontentFromStream(const Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+static const void *GetVirtualMetacontentFromStream(
+  const Image *image)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  return(cache_info->metacontent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t V i r t u a l P i x e l S t r e a m                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetVirtualPixelStream() gets pixels from the in-memory or disk pixel cache as
+%  defined by the geometry parameters.   A pointer to the pixels is returned if
+%  the pixels are transferred, otherwise a NULL is returned.  For streams this
+%  method is a no-op.
+%
+%  The format of the GetVirtualPixelStream() method is:
+%
+%      const Quantum *GetVirtualPixelStream(const Image *image,
+%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o virtual_pixel_method: the virtual pixel method.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline MagickBooleanType AcquireStreamPixels(CacheInfo *cache_info,
+  ExceptionInfo *exception)
+{
+  if (cache_info->length != (MagickSizeType) ((size_t) cache_info->length))
+    return(MagickFalse);
+  cache_info->mapped=MagickFalse;
+  cache_info->pixels=(Quantum *) AcquireMagickMemory((size_t)
+    cache_info->length);
+  if (cache_info->pixels == (Quantum *) NULL)
+    {
+      cache_info->mapped=MagickTrue;
+      cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
+        cache_info->length);
+    }
+  if (cache_info->pixels == (Quantum *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",
+        cache_info->filename);
+      return(MagickFalse);
+    }
+  return(MagickTrue);
+}
+
+static const Quantum *GetVirtualPixelStream(const Image *image,
+  const VirtualPixelMethod magick_unused(virtual_pixel_method),const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    number_pixels;
+
+  size_t
+    length;
+
+  /*
+    Validate pixel cache geometry.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if ((x < 0) || (y < 0) ||
+      ((x+(ssize_t) columns) > (ssize_t) image->columns) ||
+      ((y+(ssize_t) rows) > (ssize_t) image->rows) ||
+      (columns == 0) || (rows == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "ImageDoesNotContainTheStreamGeometry","`%s'",image->filename);
+      return((Quantum *) NULL);
+    }
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  /*
+    Pixels are stored in a temporary buffer until they are synced to the cache.
+  */
+  number_pixels=(MagickSizeType) columns*rows;
+  length=(size_t) number_pixels*cache_info->pixel_channels*sizeof(Quantum);
+  if (cache_info->metacontent_extent != 0)
+    length+=number_pixels*cache_info->metacontent_extent;
+  if (cache_info->pixels == (Quantum *) NULL)
+    {
+      cache_info->length=length;
+      status=AcquireStreamPixels(cache_info,exception);
+      if (status == MagickFalse)
+        {
+          cache_info->length=0;
+          return((Quantum *) NULL);
+        }
+    }
+  else
+    if (cache_info->length != length)
+      {
+        RelinquishStreamPixels(cache_info);
+        cache_info->length=length;
+        status=AcquireStreamPixels(cache_info,exception);
+        if (status == MagickFalse)
+          {
+            cache_info->length=0;
+            return((Quantum *) NULL);
+          }
+      }
+  cache_info->metacontent=(void *) NULL;
+  if (cache_info->metacontent_extent != 0)
+    cache_info->metacontent=(void *) (cache_info->pixels+number_pixels*
+      cache_info->pixel_channels);
+  return(cache_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   O p e n S t r e a m                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenStream() opens a stream for writing by the StreamImage() method.
+%
+%  The format of the OpenStream method is:
+%
+%       MagickBooleanType OpenStream(const ImageInfo *image_info,
+%        StreamInfo *stream_info,const char *filename,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o stream_info: the stream info.
+%
+%    o filename: the stream filename.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType OpenStream(const ImageInfo *image_info,
+  StreamInfo *stream_info,const char *filename,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  (void) CopyMagickString(stream_info->stream->filename,filename,MaxTextExtent);
+  status=OpenBlob(image_info,stream_info->stream,WriteBinaryBlobMode,exception);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   Q u e u e A u t h e n t i c P i x e l s S t r e a m                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  QueueAuthenticPixelsStream() allocates an area to store image pixels as
+%  defined by the region rectangle and returns a pointer to the area.  This
+%  area is subsequently transferred from the pixel cache with method
+%  SyncAuthenticPixelsStream().  A pointer to the pixels is returned if the
+%  pixels are transferred, otherwise a NULL is returned.
+%
+%  The format of the QueueAuthenticPixelsStream() method is:
+%
+%      Quantum *QueueAuthenticPixelsStream(Image *image,const ssize_t x,
+%        const ssize_t y,const size_t columns,const size_t rows,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x,y,columns,rows:  These values define the perimeter of a region of
+%      pixels.
+%
+*/
+static Quantum *QueueAuthenticPixelsStream(Image *image,const ssize_t x,
+  const ssize_t y,const size_t columns,const size_t rows,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  MagickSizeType
+    number_pixels;
+
+  size_t
+    length;
+
+  StreamHandler
+    stream_handler;
+
+  /*
+    Validate pixel cache geometry.
+  */
+  assert(image != (Image *) NULL);
+  if ((x < 0) || (y < 0) ||
+      ((x+(ssize_t) columns) > (ssize_t) image->columns) ||
+      ((y+(ssize_t) rows) > (ssize_t) image->rows) ||
+      (columns == 0) || (rows == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "ImageDoesNotContainTheStreamGeometry","`%s'",image->filename);
+      return((Quantum *) NULL);
+    }
+  stream_handler=GetBlobStreamHandler(image);
+  if (stream_handler == (StreamHandler) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "NoStreamHandlerIsDefined","`%s'",image->filename);
+      return((Quantum *) NULL);
+    }
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  if ((image->storage_class != GetPixelCacheStorageClass(image->cache)) ||
+      (image->colorspace != GetPixelCacheColorspace(image->cache)))
+    {
+      if (GetPixelCacheStorageClass(image->cache) == UndefinedClass)
+        (void) stream_handler(image,(const void *) NULL,(size_t)
+          cache_info->columns);
+      cache_info->storage_class=image->storage_class;
+      cache_info->colorspace=image->colorspace;
+      cache_info->columns=image->columns;
+      cache_info->rows=image->rows;
+      image->cache=cache_info;
+    }
+  /*
+    Pixels are stored in a temporary buffer until they are synced to the cache.
+  */
+  cache_info->columns=columns;
+  cache_info->rows=rows;
+  number_pixels=(MagickSizeType) columns*rows;
+  length=(size_t) number_pixels*cache_info->pixel_channels*sizeof(Quantum);
+  if (cache_info->metacontent_extent != 0)
+    length+=number_pixels*cache_info->metacontent_extent;
+  if (cache_info->pixels == (Quantum *) NULL)
+    {
+      cache_info->pixels=(Quantum *) AcquireMagickMemory(length);
+      cache_info->length=(MagickSizeType) length;
+    }
+  else
+    if (cache_info->length < (MagickSizeType) length)
+      {
+        cache_info->pixels=(Quantum *) ResizeMagickMemory(
+          cache_info->pixels,length);
+        cache_info->length=(MagickSizeType) length;
+      }
+  if (cache_info->pixels == (void *) NULL)
+    return((Quantum *) NULL);
+  cache_info->metacontent=(void *) NULL;
+  if (cache_info->metacontent_extent != 0)
+    cache_info->metacontent=(void *) (cache_info->pixels+number_pixels*
+      cache_info->pixel_channels);
+  return(cache_info->pixels);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e a d S t r e a m                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadStream() makes the image pixels available to a user supplied callback
+%  method immediately upon reading a scanline with the ReadImage() method.
+%
+%  The format of the ReadStream() method is:
+%
+%      Image *ReadStream(const ImageInfo *image_info,StreamHandler stream,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o stream: a callback method.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ReadStream(const ImageInfo *image_info,StreamHandler stream,
+  ExceptionInfo *exception)
+{
+  CacheMethods
+    cache_methods;
+
+  Image
+    *image;
+
+  ImageInfo
+    *read_info;
+
+  /*
+    Stream image pixels.
+  */
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  read_info=CloneImageInfo(image_info);
+  read_info->cache=AcquirePixelCache(0);
+  GetPixelCacheMethods(&cache_methods);
+  cache_methods.get_virtual_pixel_handler=GetVirtualPixelStream;
+  cache_methods.get_virtual_metacontent_from_handler=
+    GetVirtualMetacontentFromStream;
+  cache_methods.get_virtual_pixels_handler=GetVirtualPixelsStream;
+  cache_methods.get_authentic_pixels_handler=GetAuthenticPixelsStream;
+  cache_methods.queue_authentic_pixels_handler=QueueAuthenticPixelsStream;
+  cache_methods.sync_authentic_pixels_handler=SyncAuthenticPixelsStream;
+  cache_methods.get_authentic_pixels_from_handler=GetAuthenticPixelsFromStream;
+  cache_methods.get_authentic_metacontent_from_handler=
+    GetAuthenticMetacontentFromStream;
+  cache_methods.get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromStream;
+  cache_methods.get_one_authentic_pixel_from_handler=
+    GetOneAuthenticPixelFromStream;
+  cache_methods.destroy_pixel_handler=DestroyPixelStream;
+  SetPixelCacheMethods(read_info->cache,&cache_methods);
+  read_info->stream=stream;
+  image=ReadImage(read_info,exception);
+  read_info=DestroyImageInfo(read_info);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t S t r e a m I n f o C l i e n t D a t a                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStreamInfoClientData() sets the stream info client data.
+%
+%  The format of the SetStreamInfoClientData method is:
+%
+%      void SetStreamInfoClientData(StreamInfo *stream_info,
+%        const void *client_data)
+%
+%  A description of each parameter follows:
+%
+%    o stream_info: the stream info.
+%
+%    o client_data: the client data.
+%
+*/
+MagickExport void SetStreamInfoClientData(StreamInfo *stream_info,
+  const void *client_data)
+{
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  stream_info->client_data=client_data;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t S t r e a m I n f o M a p                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStreamInfoMap() sets the stream info map member.
+%
+%  The format of the SetStreamInfoMap method is:
+%
+%      void SetStreamInfoMap(StreamInfo *stream_info,const char *map)
+%
+%  A description of each parameter follows:
+%
+%    o stream_info: the stream info.
+%
+%    o map: the map.
+%
+*/
+MagickExport void SetStreamInfoMap(StreamInfo *stream_info,const char *map)
+{
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  (void) CloneString(&stream_info->map,map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S e t S t r e a m I n f o S t o r a g e T y p e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStreamInfoStorageType() sets the stream info storage type member.
+%
+%  The format of the SetStreamInfoStorageType method is:
+%
+%      void SetStreamInfoStorageType(StreamInfo *stream_info,
+%        const StoreageType *storage_type)
+%
+%  A description of each parameter follows:
+%
+%    o stream_info: the stream info.
+%
+%    o storage_type: the storage type.
+%
+*/
+MagickExport void SetStreamInfoStorageType(StreamInfo *stream_info,
+  const StorageType storage_type)
+{
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  stream_info->storage_type=storage_type;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S t r e a m I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StreamImage() streams pixels from an image and writes them in a user
+%  defined format and storage type (e.g. RGBA as 8-bit unsigned char).
+%
+%  The format of the StreamImage() method is:
+%
+%      Image *StreamImage(const ImageInfo *image_info,
+%        StreamInfo *stream_info,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o stream_info: the stream info.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static size_t WriteStreamImage(const Image *image,const void *pixels,
+  const size_t columns)
+{
+  CacheInfo
+    *cache_info;
+
+  RectangleInfo
+    extract_info;
+
+  size_t
+    length,
+    packet_size;
+
+  ssize_t
+    count;
+
+  StreamInfo
+    *stream_info;
+
+  (void) pixels;
+  stream_info=(StreamInfo *) image->client_data;
+  switch (stream_info->storage_type)
+  {
+    default: packet_size=sizeof(char); break;
+    case CharPixel: packet_size=sizeof(char); break;
+    case DoublePixel: packet_size=sizeof(double); break;
+    case FloatPixel: packet_size=sizeof(float); break;
+    case IntegerPixel: packet_size=sizeof(int); break;
+    case LongPixel: packet_size=sizeof(ssize_t); break;
+    case QuantumPixel: packet_size=sizeof(Quantum); break;
+    case ShortPixel: packet_size=sizeof(unsigned short); break;
+  }
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  packet_size*=strlen(stream_info->map);
+  length=packet_size*cache_info->columns*cache_info->rows;
+  if (image != stream_info->image)
+    {
+      ImageInfo
+        *write_info;
+
+      /*
+        Prepare stream for writing.
+      */
+      stream_info->pixels=(unsigned char *) ResizeQuantumMemory(
+        stream_info->pixels,length,sizeof(*stream_info->pixels));
+      if (stream_info->pixels == (unsigned char *) NULL)
+        return(0);
+      stream_info->image=image;
+      write_info=CloneImageInfo(stream_info->image_info);
+      (void) SetImageInfo(write_info,1,stream_info->exception);
+      if (write_info->extract != (char *) NULL)
+        (void) ParseAbsoluteGeometry(write_info->extract,
+          &stream_info->extract_info);
+      stream_info->y=0;
+      write_info=DestroyImageInfo(write_info);
+    }
+  extract_info=stream_info->extract_info;
+  if ((extract_info.width == 0) || (extract_info.height == 0))
+    {
+      /*
+        Write all pixels to stream.
+      */
+      (void) StreamImagePixels(stream_info,image,stream_info->exception);
+      count=WriteBlob(stream_info->stream,length,stream_info->pixels);
+      stream_info->y++;
+      return(count == 0 ? 0 : columns);
+    }
+  if ((stream_info->y < extract_info.y) ||
+      (stream_info->y >= (ssize_t) (extract_info.y+extract_info.height)))
+    {
+      stream_info->y++;
+      return(columns);
+    }
+  /*
+    Write a portion of the pixel row to the stream.
+  */
+  (void) StreamImagePixels(stream_info,image,stream_info->exception);
+  length=packet_size*extract_info.width;
+  count=WriteBlob(stream_info->stream,length,stream_info->pixels+packet_size*
+    extract_info.x);
+  stream_info->y++;
+  return(count == 0 ? 0 : columns);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport Image *StreamImage(const ImageInfo *image_info,
+  StreamInfo *stream_info,ExceptionInfo *exception)
+{
+  Image
+    *image;
+
+  ImageInfo
+    *read_info;
+
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  assert(exception != (ExceptionInfo *) NULL);
+  read_info=CloneImageInfo(image_info);
+  stream_info->image_info=image_info;
+  stream_info->exception=exception;
+  read_info->client_data=(void *) stream_info;
+  image=ReadStream(read_info,&WriteStreamImage,exception);
+  read_info=DestroyImageInfo(read_info);
+  stream_info->quantum_info=AcquireQuantumInfo(image_info,image);
+  if (stream_info->quantum_info == (QuantumInfo *) NULL)
+    image=DestroyImage(image);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S t r e a m I m a g e P i x e l s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StreamImagePixels() extracts pixel data from an image and returns it in the
+%  stream_info->pixels structure in the format as defined by
+%  stream_info->quantum_info->map and stream_info->quantum_info->storage_type.
+%
+%  The format of the StreamImagePixels method is:
+%
+%      MagickBooleanType StreamImagePixels(const StreamInfo *stream_info,
+%        const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o stream_info: the stream info.
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType StreamImagePixels(const StreamInfo *stream_info,
+  const Image *image,ExceptionInfo *exception)
+{
+  QuantumInfo
+    *quantum_info;
+
+  QuantumType
+    *quantum_map;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i,
+    x;
+
+  size_t
+    length;
+
+  assert(stream_info != (StreamInfo *) NULL);
+  assert(stream_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  length=strlen(stream_info->map);
+  quantum_map=(QuantumType *) AcquireQuantumMemory(length,sizeof(*quantum_map));
+  if (quantum_map == (QuantumType *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),
+        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) length; i++)
+  {
+    switch (stream_info->map[i])
+    {
+      case 'A':
+      case 'a':
+      {
+        quantum_map[i]=AlphaQuantum;
+        break;
+      }
+      case 'B':
+      case 'b':
+      {
+        quantum_map[i]=BlueQuantum;
+        break;
+      }
+      case 'C':
+      case 'c':
+      {
+        quantum_map[i]=CyanQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",stream_info->map);
+        return(MagickFalse);
+      }
+      case 'g':
+      case 'G':
+      {
+        quantum_map[i]=GreenQuantum;
+        break;
+      }
+      case 'I':
+      case 'i':
+      {
+        quantum_map[i]=IndexQuantum;
+        break;
+      }
+      case 'K':
+      case 'k':
+      {
+        quantum_map[i]=BlackQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",stream_info->map);
+        return(MagickFalse);
+      }
+      case 'M':
+      case 'm':
+      {
+        quantum_map[i]=MagentaQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",stream_info->map);
+        return(MagickFalse);
+      }
+      case 'o':
+      case 'O':
+      {
+        quantum_map[i]=OpacityQuantum;
+        break;
+      }
+      case 'P':
+      case 'p':
+      {
+        quantum_map[i]=UndefinedQuantum;
+        break;
+      }
+      case 'R':
+      case 'r':
+      {
+        quantum_map[i]=RedQuantum;
+        break;
+      }
+      case 'Y':
+      case 'y':
+      {
+        quantum_map[i]=YellowQuantum;
+        if (image->colorspace == CMYKColorspace)
+          break;
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
+          "ColorSeparatedImageRequired","`%s'",stream_info->map);
+        return(MagickFalse);
+      }
+      default:
+      {
+        quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "UnrecognizedPixelMap","`%s'",stream_info->map);
+        return(MagickFalse);
+      }
+    }
+  }
+  quantum_info=stream_info->quantum_info;
+  switch (stream_info->storage_type)
+  {
+    case CharPixel:
+    {
+      register unsigned char
+        *q;
+
+      q=(unsigned char *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+              break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            *q++=ScaleQuantumToChar((Quantum) 0);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelIntensity(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToChar((Quantum) 0);
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=ScaleQuantumToChar(GetPixelRed(image,p));
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=ScaleQuantumToChar(GetPixelGreen(image,p));
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=ScaleQuantumToChar(GetPixelBlue(image,p));
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=ScaleQuantumToChar(GetPixelAlpha(image,p));
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=ScaleQuantumToChar(GetPixelBlack(image,p));
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=ScaleQuantumToChar(GetPixelIntensity(image,p));
+              break;
+            }
+            default:
+              break;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case DoublePixel:
+    {
+      register double
+        *q;
+
+      q=(double *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelAlpha(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelIntensity(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelAlpha(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(double) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(double) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=(double) ((QuantumScale*GetPixelRed(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=(double) ((QuantumScale*GetPixelGreen(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=(double) ((QuantumScale*GetPixelBlue(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(double) ((QuantumScale*GetPixelAlpha(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=(double) ((QuantumScale*GetPixelAlpha(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=(double) ((QuantumScale*GetPixelBlack(image,p))*
+                  quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(double) ((QuantumScale*GetPixelIntensity(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            default:
+              *q=0;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case FloatPixel:
+    {
+      register float
+        *q;
+
+      q=(float *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*(Quantum) (GetPixelAlpha(image,p)))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelIntensity(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelAlpha(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(float) ((QuantumScale*GetPixelRed(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelGreen(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=(float) ((QuantumScale*GetPixelBlue(image,p))*
+              quantum_info->scale+quantum_info->minimum);
+            *q++=0.0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=(float) ((QuantumScale*GetPixelRed(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=(float) ((QuantumScale*GetPixelGreen(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=(float) ((QuantumScale*GetPixelBlue(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(float) ((QuantumScale*GetPixelAlpha(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=(float) ((QuantumScale*GetPixelAlpha(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=(float) ((QuantumScale*GetPixelBlack(image,p))*
+                  quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(float) ((QuantumScale*GetPixelIntensity(image,p))*
+                quantum_info->scale+quantum_info->minimum);
+              break;
+            }
+            default:
+              *q=0;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case IntegerPixel:
+    {
+      register unsigned int
+        *q;
+
+      q=(unsigned int *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=0U;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(
+              GetPixelIntensity(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong((Quantum)
+              (GetPixelAlpha(image,p)));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=0U;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(GetPixelRed(image,p));
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(GetPixelGreen(image,p));
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(GetPixelBlue(image,p));
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=(unsigned int) ScaleQuantumToLong(GetPixelAlpha(image,p));
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=(unsigned int) ScaleQuantumToLong(GetPixelBlack(image,p));
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(unsigned int)
+                ScaleQuantumToLong(GetPixelIntensity(image,p));
+              break;
+            }
+            default:
+              *q=0;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case LongPixel:
+    {
+      register size_t
+        *q;
+
+      q=(size_t *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=ScaleQuantumToLong((Quantum) (GetPixelAlpha(image,p)));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelIntensity(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToLong((Quantum) (GetPixelAlpha(image,p)));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToLong(GetPixelRed(image,p));
+            *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=ScaleQuantumToLong(GetPixelRed(image,p));
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=ScaleQuantumToLong(GetPixelGreen(image,p));
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=ScaleQuantumToLong(GetPixelBlue(image,p));
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=ScaleQuantumToLong((Quantum) (GetPixelAlpha(image,p)));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=ScaleQuantumToLong(GetPixelAlpha(image,p));
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=ScaleQuantumToLong(GetPixelBlack(image,p));
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=ScaleQuantumToLong(GetPixelIntensity(image,p));
+              break;
+            }
+            default:
+              break;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case QuantumPixel:
+    {
+      register Quantum
+        *q;
+
+      q=(Quantum *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelBlue(image,p);
+            *q++=GetPixelGreen(image,p);
+            *q++=GetPixelRed(image,p);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelBlue(image,p);
+            *q++=GetPixelGreen(image,p);
+            *q++=GetPixelRed(image,p);
+            *q++=(Quantum) (GetPixelAlpha(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelBlue(image,p);
+            *q++=GetPixelGreen(image,p);
+            *q++=GetPixelRed(image,p);
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelIntensity(image,p);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelRed(image,p);
+            *q++=GetPixelGreen(image,p);
+            *q++=GetPixelBlue(image,p);
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelRed(image,p);
+            *q++=GetPixelGreen(image,p);
+            *q++=GetPixelBlue(image,p);
+            *q++=(Quantum) (GetPixelAlpha(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=GetPixelRed(image,p);
+            *q++=GetPixelGreen(image,p);
+            *q++=GetPixelBlue(image,p);
+            *q++=0U;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=(Quantum) 0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=GetPixelRed(image,p);
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=GetPixelGreen(image,p);
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=GetPixelBlue(image,p);
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=(Quantum) (GetPixelAlpha(image,p));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=GetPixelAlpha(image,p);
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=GetPixelBlack(image,p);
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=(GetPixelIntensity(image,p));
+              break;
+            }
+            default:
+              *q=0;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    case ShortPixel:
+    {
+      register unsigned short
+        *q;
+
+      q=(unsigned short *) stream_info->pixels;
+      if (LocaleCompare(stream_info->map,"BGR") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+            *q++=ScaleQuantumToShort((Quantum) (GetPixelAlpha(image,p)));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"BGRP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+            if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"I") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelIntensity(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGB") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+            *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBA") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+            *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToShort((Quantum) (GetPixelAlpha(image,p)));
+            p++;
+          }
+          break;
+        }
+      if (LocaleCompare(stream_info->map,"RGBP") == 0)
+        {
+          p=GetAuthenticPixelQueue(image);
+          if (p == (const Quantum *) NULL)
+            break;
+          for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+          {
+            *q++=ScaleQuantumToShort(GetPixelRed(image,p));
+            *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
+            *q++=0;
+            p++;
+          }
+          break;
+        }
+      p=GetAuthenticPixelQueue(image);
+      if (p == (const Quantum *) NULL)
+        break;
+      for (x=0; x < (ssize_t) GetImageExtent(image); x++)
+      {
+        for (i=0; i < (ssize_t) length; i++)
+        {
+          *q=0;
+          switch (quantum_map[i])
+          {
+            case RedQuantum:
+            case CyanQuantum:
+            {
+              *q=ScaleQuantumToShort(GetPixelRed(image,p));
+              break;
+            }
+            case GreenQuantum:
+            case MagentaQuantum:
+            {
+              *q=ScaleQuantumToShort(GetPixelGreen(image,p));
+              break;
+            }
+            case BlueQuantum:
+            case YellowQuantum:
+            {
+              *q=ScaleQuantumToShort(GetPixelBlue(image,p));
+              break;
+            }
+            case AlphaQuantum:
+            {
+              *q=ScaleQuantumToShort(GetPixelAlpha(image,p));
+              break;
+            }
+            case OpacityQuantum:
+            {
+              *q=ScaleQuantumToShort(GetPixelAlpha(image,p));
+              break;
+            }
+            case BlackQuantum:
+            {
+              if (image->colorspace == CMYKColorspace)
+                *q=ScaleQuantumToShort(GetPixelBlack(image,p));
+              break;
+            }
+            case IndexQuantum:
+            {
+              *q=ScaleQuantumToShort(GetPixelIntensity(image,p));
+              break;
+            }
+            default:
+              break;
+          }
+          q++;
+        }
+        p++;
+      }
+      break;
+    }
+    default:
+    {
+      quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "UnrecognizedPixelMap","`%s'",stream_info->map);
+      break;
+    }
+  }
+  quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S y n c A u t h e n t i c P i x e l s S t r e a m                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncAuthenticPixelsStream() calls the user supplied callback method with
+%  the latest stream of pixels.
+%
+%  The format of the SyncAuthenticPixelsStream method is:
+%
+%      MagickBooleanType SyncAuthenticPixelsStream(Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType SyncAuthenticPixelsStream(Image *image,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  size_t
+    length;
+
+  StreamHandler
+    stream_handler;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  stream_handler=GetBlobStreamHandler(image);
+  if (stream_handler == (StreamHandler) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),StreamError,
+        "NoStreamHandlerIsDefined","`%s'",image->filename);
+      return(MagickFalse);
+    }
+  length=stream_handler(image,cache_info->pixels,(size_t) cache_info->columns);
+  return(length == cache_info->columns ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   W r i t e S t r e a m                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteStream() makes the image pixels available to a user supplied callback
+%  method immediately upon writing pixel data with the WriteImage() method.
+%
+%  The format of the WriteStream() method is:
+%
+%      MagickBooleanType WriteStream(const ImageInfo *image_info,Image *,
+%        StreamHandler stream)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o stream: A callback method.
+%
+*/
+MagickExport MagickBooleanType WriteStream(const ImageInfo *image_info,
+  Image *image,StreamHandler stream)
+{
+  ImageInfo
+    *write_info;
+
+  MagickBooleanType
+    status;
+
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  write_info=CloneImageInfo(image_info);
+  write_info->stream=stream;
+  status=WriteImage(write_info,image);
+  write_info=DestroyImageInfo(write_info);
+  return(status);
+}
diff --git a/MagickCore/stream.h b/MagickCore/stream.h
new file mode 100644
index 0000000..1cc5497
--- /dev/null
+++ b/MagickCore/stream.h
@@ -0,0 +1,38 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image stream methods.
+*/
+#ifndef _MAGICKCORE_STREAM_H
+#define _MAGICKCORE_STREAM_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef size_t
+  (*StreamHandler)(const Image *,const void *,const size_t);
+
+extern MagickExport Image
+  *ReadStream(const ImageInfo *,StreamHandler,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  WriteStream(const ImageInfo *,Image *,StreamHandler);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/string-private.h b/MagickCore/string-private.h
new file mode 100644
index 0000000..b3dd2e1
--- /dev/null
+++ b/MagickCore/string-private.h
@@ -0,0 +1,73 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private string methods.
+*/
+#ifndef _MAGICKCORE_STRING_PRIVATE_H
+#define _MAGICKCORE_STRING_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static inline double SiPrefixToDouble(const char *string,const double interval)
+{
+  char
+    *q;
+
+  double
+    scale,
+    value;
+
+  value=InterpretLocaleValue(string,&q);
+  scale=1000.0;
+  if ((*q != '\0') && (tolower((int) ((unsigned char) *(q+1))) == 'i'))
+    scale=1024.0;
+  switch (tolower((int) ((unsigned char) *q)))
+  {
+    case '%': value*=pow(scale,0)*interval/100.0; break;
+    case 'k': value*=pow(scale,1); break;
+    case 'm': value*=pow(scale,2); break;
+    case 'g': value*=pow(scale,3); break;
+    case 't': value*=pow(scale,4); break;
+    case 'p': value*=pow(scale,5); break;
+    case 'e': value*=pow(scale,6); break;
+    case 'z': value*=pow(scale,7); break;
+    case 'y': value*=pow(scale,8); break;
+    default:  break;
+  }
+  return(value);
+}
+
+static inline int StringToInteger(const char *value)
+{
+  return((int) strtol(value,(char **) NULL,10));
+}
+
+static inline long StringToLong(const char *value)
+{
+  return(strtol(value,(char **) NULL,10));
+}
+
+static inline unsigned long StringToUnsignedLong(const char *value)
+{
+  return(strtoul(value,(char **) NULL,10));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/string.c b/MagickCore/string.c
new file mode 100644
index 0000000..50bd4b0
--- /dev/null
+++ b/MagickCore/string.c
@@ -0,0 +1,2365 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  SSSSS   TTTTT  RRRR   IIIII  N   N   GGGG                  %
+%                  SS        T    R   R    I    NN  N  G                      %
+%                   SSS      T    RRRR     I    N N N  G GGG                  %
+%                     SS     T    R R      I    N  NN  G   G                  %
+%                  SSSSS     T    R  R   IIIII  N   N   GGGG                  %
+%                                                                             %
+%                                                                             %
+%                        MagickCore String Methods                            %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               August 2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/property.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+
+/*
+  Static declarations.
+*/
+#if !defined(MAGICKCORE_HAVE_STRCASECMP) || !defined(MAGICKCORE_HAVE_STRNCASECMP)
+static const unsigned char
+  AsciiMap[] =
+  {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+    0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+    0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
+    0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+    0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+    0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+    0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
+    0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+    0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+    0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
+    0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
+    0xfc, 0xfd, 0xfe, 0xff,
+  };
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e S t r i n g                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireString() allocates memory for a string and copies the source string
+%  to that memory location (and returns it).
+%
+%  The format of the AcquireString method is:
+%
+%      char *AcquireString(const char *source)
+%
+%  A description of each parameter follows:
+%
+%    o source: A character string.
+%
+*/
+MagickExport char *AcquireString(const char *source)
+{
+  char
+    *destination;
+
+  size_t
+    length;
+
+  length=0;
+  if (source != (char *) NULL)
+    length+=strlen(source);
+  if (~length < MaxTextExtent)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  destination=(char *) AcquireQuantumMemory(length+MaxTextExtent,
+    sizeof(*destination));
+  if (destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  *destination='\0';
+  if (source != (char *) NULL)
+    (void) memcpy(destination,source,length*sizeof(*destination));
+  destination[length]='\0';
+  return(destination);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e S t r i n g I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireStringInfo() allocates the StringInfo structure.
+%
+%  The format of the AcquireStringInfo method is:
+%
+%      StringInfo *AcquireStringInfo(const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o length: the string length.
+%
+*/
+MagickExport StringInfo *AcquireStringInfo(const size_t length)
+{
+  StringInfo
+    *string_info;
+
+  string_info=(StringInfo *) AcquireMagickMemory(sizeof(*string_info));
+  if (string_info == (StringInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(string_info,0,sizeof(*string_info));
+  string_info->signature=MagickSignature;
+  string_info->length=length;
+  if (string_info->length != 0)
+    {
+      string_info->datum=(unsigned char *) NULL;
+      if (~string_info->length >= (MaxTextExtent-1))
+        string_info->datum=(unsigned char *) AcquireQuantumMemory(
+          string_info->length+MaxTextExtent,sizeof(*string_info->datum));
+      if (string_info->datum == (unsigned char *) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+    }
+  return(string_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e S t r i n g                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneString() allocates memory for the destination string and copies
+%  the source string to that memory location.
+%
+%  The format of the CloneString method is:
+%
+%      char *CloneString(char **destination,const char *source)
+%
+%  A description of each parameter follows:
+%
+%    o destination:  A pointer to a character string.
+%
+%    o source: A character string.
+%
+*/
+MagickExport char *CloneString(char **destination,const char *source)
+{
+  size_t
+    length;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(destination != (char **) NULL);
+  if (source == (const char *) NULL)
+    {
+      if (*destination != (char *) NULL)
+        *destination=DestroyString(*destination);
+      return(*destination);
+    }
+  if (*destination == (char *) NULL)
+    {
+      *destination=AcquireString(source);
+      return(*destination);
+    }
+  length=strlen(source);
+  if (~length < MaxTextExtent)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  *destination=(char *) ResizeQuantumMemory(*destination,length+MaxTextExtent,
+    sizeof(**destination));
+  if (*destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  if (length != 0)
+    (void) memcpy(*destination,source,length*sizeof(**destination));
+  (*destination)[length]='\0';
+  return(*destination);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C l o n e S t r i n g I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CloneStringInfo() clones a copy of the StringInfo structure.
+%
+%  The format of the CloneStringInfo method is:
+%
+%      StringInfo *CloneStringInfo(const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport StringInfo *CloneStringInfo(const StringInfo *string_info)
+{
+  StringInfo
+    *clone_info;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  clone_info=AcquireStringInfo(string_info->length);
+  if (string_info->length != 0)
+    (void) memcpy(clone_info->datum,string_info->datum,string_info->length+1);
+  return(clone_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o m p a r e S t r i n g I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CompareStringInfo() compares the two datums target and source.  It returns
+%  an integer less than, equal to, or greater than zero if target is found,
+%  respectively, to be less than, to match, or be greater than source.
+%
+%  The format of the CompareStringInfo method is:
+%
+%      int CompareStringInfo(const StringInfo *target,const StringInfo *source)
+%
+%  A description of each parameter follows:
+%
+%    o target: the target string.
+%
+%    o source: the source string.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport int CompareStringInfo(const StringInfo *target,
+  const StringInfo *source)
+{
+  int
+    status;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(target != (StringInfo *) NULL);
+  assert(target->signature == MagickSignature);
+  assert(source != (StringInfo *) NULL);
+  assert(source->signature == MagickSignature);
+  status=memcmp(target->datum,source->datum,MagickMin(target->length,
+    source->length));
+  if (status != 0)
+    return(status);
+  if (target->length == source->length)
+    return(0);
+  return(target->length < source->length ? -1 : 1);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n c a t e n a t e M a g i c k S t r i n g                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConcatenateMagickString() concatenates the source string to the destination
+%  string.  The destination buffer is always null-terminated even if the
+%  string must be truncated.
+%
+%  The format of the ConcatenateMagickString method is:
+%
+%      size_t ConcatenateMagickString(char *destination,const char *source,
+%        const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o destination: the destination string.
+%
+%    o source: the source string.
+%
+%    o length: the length of the destination string.
+%
+*/
+MagickExport size_t ConcatenateMagickString(char *destination,
+  const char *source,const size_t length)
+{
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register size_t
+    i;
+
+  size_t
+    count;
+
+  assert(destination != (char *) NULL);
+  assert(source != (const char *) NULL);
+  assert(length >= 1);
+  p=source;
+  q=destination;
+  i=length;
+  while ((i-- != 0) && (*q != '\0'))
+    q++;
+  count=(size_t) (q-destination);
+  i=length-count;
+  if (i == 0)
+    return(count+strlen(p));
+  while (*p != '\0')
+  {
+    if (i != 1)
+      {
+        *q++=(*p);
+        i--;
+      }
+    p++;
+  }
+  *q='\0';
+  return(count+(p-source));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n c a t e n a t e S t r i n g                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConcatenateString() appends a copy of string source, including the
+%  terminating null character, to the end of string destination.
+%
+%  The format of the ConcatenateString method is:
+%
+%      MagickBooleanType ConcatenateString(char **destination,
+%        const char *source)
+%
+%  A description of each parameter follows:
+%
+%    o destination:  A pointer to a character string.
+%
+%    o source: A character string.
+%
+*/
+MagickExport MagickBooleanType ConcatenateString(char **destination,
+  const char *source)
+{
+  size_t
+    destination_length,
+    length,
+    source_length;
+
+  assert(destination != (char **) NULL);
+  if (source == (const char *) NULL)
+    return(MagickTrue);
+  if (*destination == (char *) NULL)
+    {
+      *destination=AcquireString(source);
+      return(MagickTrue);
+    }
+  destination_length=strlen(*destination);
+  source_length=strlen(source);
+  length=destination_length;
+  if (~length < source_length)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToConcatenateString");
+  length+=source_length;
+  if (~length < MaxTextExtent)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToConcatenateString");
+  *destination=(char *) ResizeQuantumMemory(*destination,length+MaxTextExtent,
+    sizeof(**destination));
+  if (*destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToConcatenateString");
+  if (source_length != 0)
+    (void) memcpy((*destination)+destination_length,source,source_length);
+  (*destination)[length]='\0';
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n c a t e n a t e S t r i n g I n f o                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConcatenateStringInfo() concatenates the source string to the destination
+%  string.
+%
+%  The format of the ConcatenateStringInfo method is:
+%
+%      void ConcatenateStringInfo(StringInfo *string_info,
+%        const StringInfo *source)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+%    o source: the source string.
+%
+*/
+MagickExport void ConcatenateStringInfo(StringInfo *string_info,
+  const StringInfo *source)
+{
+  size_t
+    length;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  assert(source != (const StringInfo *) NULL);
+  length=string_info->length;
+  if (~length < source->length)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToConcatenateString");
+  SetStringInfoLength(string_info,length+source->length);
+  (void) memcpy(string_info->datum+length,source->datum,source->length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n f i g u r e F i l e T o S t r i n g I n f o                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConfigureFileToStringInfo() returns the contents of a configure file as a
+%  string.
+%
+%  The format of the ConfigureFileToStringInfo method is:
+%
+%      StringInfo *ConfigureFileToStringInfo(const char *filename)
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the filename.
+%
+*/
+MagickExport StringInfo *ConfigureFileToStringInfo(const char *filename)
+{
+  char
+    *string;
+
+  int
+    file;
+
+  MagickOffsetType
+    offset;
+
+  size_t
+    length;
+
+  StringInfo
+    *string_info;
+
+  void
+    *map;
+
+  assert(filename != (const char *) NULL);
+  file=open(filename,O_RDONLY | O_BINARY);
+  if (file == -1)
+    return((StringInfo *) NULL);
+  offset=(MagickOffsetType) lseek(file,0,SEEK_END);
+  if ((offset < 0) || (offset != (MagickOffsetType) ((ssize_t) offset)))
+    {
+      file=close(file)-1;
+      return((StringInfo *) NULL);
+    }
+  length=(size_t) offset;
+  string=(char *) NULL;
+  if (~length >= (MaxTextExtent-1))
+    string=(char *) AcquireQuantumMemory(length+MaxTextExtent,sizeof(*string));
+  if (string == (char *) NULL)
+    {
+      file=close(file)-1;
+      return((StringInfo *) NULL);
+    }
+  map=MapBlob(file,ReadMode,0,length);
+  if (map != (void *) NULL)
+    {
+      (void) memcpy(string,map,length);
+      (void) UnmapBlob(map,length);
+    }
+  else
+    {
+      register size_t
+        i;
+
+      ssize_t
+        count;
+
+      (void) lseek(file,0,SEEK_SET);
+      for (i=0; i < length; i+=count)
+      {
+        count=read(file,string+i,(size_t) MagickMin(length-i,(size_t)
+          SSIZE_MAX));
+        if (count <= 0)
+          {
+            count=0;
+            if (errno != EINTR)
+              break;
+          }
+      }
+      if (i < length)
+        {
+          file=close(file)-1;
+          string=DestroyString(string);
+          return((StringInfo *) NULL);
+        }
+    }
+  string[length]='\0';
+  file=close(file)-1;
+  string_info=AcquireStringInfo(0);
+  (void) CopyMagickString(string_info->path,filename,MaxTextExtent);
+  string_info->length=length;
+  string_info->datum=(unsigned char *) string;
+  return(string_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n s t a n t S t r i n g                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConstantString() allocates memory for a string and copies the source string
+%  to that memory location (and returns it).  Use it for strings that you do
+%  do not expect to change over its lifetime.
+%
+%  The format of the ConstantString method is:
+%
+%      char *ConstantString(const char *source)
+%
+%  A description of each parameter follows:
+%
+%    o source: A character string.
+%
+*/
+MagickExport char *ConstantString(const char *source)
+{
+  char
+    *destination;
+
+  size_t
+    length;
+
+  length=0;
+  if (source != (char *) NULL)
+    length+=strlen(source);
+  destination=(char *) NULL;
+  if (~length >= 1UL)
+    destination=(char *) AcquireQuantumMemory(length+1UL,sizeof(*destination));
+  if (destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  *destination='\0';
+  if (source != (char *) NULL)
+    (void) memcpy(destination,source,length*sizeof(*destination));
+  destination[length]='\0';
+  return(destination);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o p y M a g i c k S t r i n g                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CopyMagickString() copies the source string to the destination string.  The
+%  destination buffer is always null-terminated even if the string must be
+%  truncated.  The return value is the minimum of the source string length
+%  or the length parameter.
+%
+%  The format of the CopyMagickString method is:
+%
+%      size_t CopyMagickString(const char *destination,char *source,
+%        const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o destination: the destination string.
+%
+%    o source: the source string.
+%
+%    o length: the length of the destination string.
+%
+*/
+MagickExport size_t CopyMagickString(char *destination,const char *source,
+  const size_t length)
+{
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  register size_t
+    n;
+
+  p=source;
+  q=destination;
+  for (n=length; n > 4; n-=4)
+  {
+    *q=(*p++);
+    if (*q == '\0')
+      return((size_t) (p-source-1));
+    q++;
+    *q=(*p++);
+    if (*q == '\0')
+      return((size_t) (p-source-1));
+    q++;
+    *q=(*p++);
+    if (*q == '\0')
+      return((size_t) (p-source-1));
+    q++;
+    *q=(*p++);
+    if (*q == '\0')
+      return((size_t) (p-source-1));
+    q++;
+  }
+  if (n != 0)
+    for (n--; n != 0; n--)
+    {
+      *q=(*p++);
+      if (*q == '\0')
+        return((size_t) (p-source-1));
+      q++;
+    }
+  if (length != 0)
+    *q='\0';
+  return((size_t) (p-source-1));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y S t r i n g                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyString() destroys memory associated with a string.
+%
+%  The format of the DestroyString method is:
+%
+%      char *DestroyString(char *string)
+%
+%  A description of each parameter follows:
+%
+%    o string: the string.
+%
+*/
+MagickExport char *DestroyString(char *string)
+{
+  return((char *) RelinquishMagickMemory(string));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y S t r i n g I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyStringInfo() destroys memory associated with the StringInfo structure.
+%
+%  The format of the DestroyStringInfo method is:
+%
+%      StringInfo *DestroyStringInfo(StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport StringInfo *DestroyStringInfo(StringInfo *string_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  if (string_info->datum != (unsigned char *) NULL)
+    string_info->datum=(unsigned char *) RelinquishMagickMemory(
+      string_info->datum);
+  string_info->signature=(~MagickSignature);
+  string_info=(StringInfo *) RelinquishMagickMemory(string_info);
+  return(string_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y S t r i n g L i s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyStringList() zeros memory associated with a string list.
+%
+%  The format of the DestroyStringList method is:
+%
+%      char **DestroyStringList(char **list)
+%
+%  A description of each parameter follows:
+%
+%    o list: the string list.
+%
+*/
+MagickExport char **DestroyStringList(char **list)
+{
+  register ssize_t
+    i;
+
+  assert(list != (char **) NULL);
+  for (i=0; list[i] != (char *) NULL; i++)
+    list[i]=DestroyString(list[i]);
+  list=(char **) RelinquishMagickMemory(list);
+  return(list);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E s c a p e S t r i n g                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  EscapeString() allocates memory for a backslash-escaped version of a
+%  source text string, copies the escaped version of the text to that
+%  memory location while adding backslash characters, and returns the
+%  escaped string.
+%
+%  The format of the EscapeString method is:
+%
+%      char *EscapeString(const char *source,const char escape)
+%
+%  A description of each parameter follows:
+%
+%    o allocate_string:  Method EscapeString returns the escaped string.
+%
+%    o source: A character string.
+%
+%    o escape: the quoted string termination character to escape (e.g. '"').
+%
+*/
+MagickExport char *EscapeString(const char *source,const char escape)
+{
+  char
+    *destination;
+
+  register char
+    *q;
+
+  register const char
+    *p;
+
+  size_t
+    length;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(source != (const char *) NULL);
+  length=strlen(source);
+  for (p=source; *p != '\0'; p++)
+    if ((*p == '\\') || (*p == escape))
+      {
+        if (~length < 1)
+          ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
+        length++;
+      }
+  destination=(char *) NULL;
+  if (~length >= (MaxTextExtent-1))
+    destination=(char *) AcquireQuantumMemory(length+MaxTextExtent,
+      sizeof(*destination));
+  if (destination == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
+  *destination='\0';
+  if (source != (char *) NULL)
+    {
+      q=destination;
+      for (p=source; *p != '\0'; p++)
+      {
+        if ((*p == '\\') || (*p == escape))
+          *q++='\\';
+        *q++=(*p);
+      }
+      *q='\0';
+    }
+  return(destination);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F i l e T o S t r i n g                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FileToString() returns the contents of a file as a string.
+%
+%  The format of the FileToString method is:
+%
+%      char *FileToString(const char *filename,const size_t extent,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the filename.
+%
+%    o extent: Maximum length of the string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport char *FileToString(const char *filename,const size_t extent,
+  ExceptionInfo *exception)
+{
+  size_t
+    length;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  return((char *) FileToBlob(filename,extent,&length,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F i l e T o S t r i n g I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FileToStringInfo() returns the contents of a file as a string.
+%
+%  The format of the FileToStringInfo method is:
+%
+%      StringInfo *FileToStringInfo(const char *filename,const size_t extent,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the filename.
+%
+%    o extent: Maximum length of the string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport StringInfo *FileToStringInfo(const char *filename,
+  const size_t extent,ExceptionInfo *exception)
+{
+  StringInfo
+    *string_info;
+
+  assert(filename != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  string_info=AcquireStringInfo(0);
+  (void) CopyMagickString(string_info->path,filename,MaxTextExtent);
+  string_info->datum=FileToBlob(filename,extent,&string_info->length,exception);
+  if (string_info->datum == (unsigned char *) NULL)
+    {
+      string_info=DestroyStringInfo(string_info);
+      return((StringInfo *) NULL);
+    }
+  return(string_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  F o r m a t M a g i c k S i z e                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatMagickSize() converts a size to a human readable format, for example,
+%  14k, 234m, 2.7g, or 3.0t.  Scaling is done by repetitively dividing by
+%  1000.
+%
+%  The format of the FormatMagickSize method is:
+%
+%      ssize_t FormatMagickSize(const MagickSizeType size,char *format)
+%
+%  A description of each parameter follows:
+%
+%    o size:  convert this size to a human readable format.
+%
+%    o bi:  use power of two rather than power of ten.
+%
+%    o format:  human readable format.
+%
+*/
+MagickExport ssize_t FormatMagickSize(const MagickSizeType size,
+  const MagickBooleanType bi,char *format)
+{
+  const char
+    **units;
+
+  double
+    bytes,
+    length;
+
+  register ssize_t
+    i,
+    j;
+
+  ssize_t
+    count;
+
+  static const char
+    *bi_units[] =
+    {
+      "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi", (char *) NULL
+    },
+    *traditional_units[] =
+    {
+      "", "K", "M", "G", "T", "P", "E", "Z", "Y", (char *) NULL
+    };
+
+  bytes=1000.0;
+  units=traditional_units;
+  if (bi != MagickFalse)
+    {
+      bytes=1024.0;
+      units=bi_units;
+    }
+#if defined(_MSC_VER) && (_MSC_VER == 1200)
+  length=(double) ((MagickOffsetType) size);
+#else
+  length=(double) size;
+#endif
+  for (i=0; (length >= bytes) && (units[i+1] != (const char *) NULL); i++)
+    length/=bytes;
+  for (j=2; j < 12; j++)
+  {
+    count=FormatLocaleString(format,MaxTextExtent,"%.*g%sB",(int) (i+j),length,
+      units[i]);
+    if (strchr(format,'+') == (char *) NULL)
+      break;
+  }
+  return(count);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  F o r m a t M a g i c k T i m e                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FormatMagickTime() returns the specified time in the Internet date/time
+%  format and the length of the timestamp.
+%
+%  The format of the FormatMagickTime method is:
+%
+%      ssize_t FormatMagickTime(const time_t time,const size_t length,
+%        char *timestamp)
+%
+%  A description of each parameter follows.
+%
+%   o time:  the time since the Epoch (00:00:00 UTC, January 1, 1970),
+%     measured in seconds.
+%
+%   o length: the maximum length of the string.
+%
+%   o timestamp:  Return the Internet date/time here.
+%
+*/
+MagickExport ssize_t FormatMagickTime(const time_t time,const size_t length,
+  char *timestamp)
+{
+  ssize_t
+    count;
+
+  struct tm
+    gm_time,
+    local_time;
+
+  time_t
+    timezone;
+
+  assert(timestamp != (char *) NULL);
+  (void) ResetMagickMemory(&local_time,0,sizeof(local_time));
+  (void) ResetMagickMemory(&gm_time,0,sizeof(gm_time));
+#if defined(MAGICKCORE_HAVE_LOCALTIME_R)
+  (void) localtime_r(&time,&local_time);
+#else
+  {
+    struct tm
+      *my_time;
+
+    my_time=localtime(&time);
+    if (my_time != (struct tm *) NULL)
+      (void) memcpy(&local_time,my_time,sizeof(local_time));
+  }
+#endif
+#if defined(MAGICKCORE_HAVE_GMTIME_R)
+  (void) gmtime_r(&time,&gm_time);
+#else
+  {
+    struct tm
+      *my_time;
+
+    my_time=gmtime(&time);
+    if (my_time != (struct tm *) NULL)
+      (void) memcpy(&gm_time,my_time,sizeof(gm_time));
+  }
+#endif
+  timezone=(time_t) ((local_time.tm_min-gm_time.tm_min)/60+
+    local_time.tm_hour-gm_time.tm_hour+24*((local_time.tm_year-
+    gm_time.tm_year) != 0 ? (local_time.tm_year-gm_time.tm_year) :
+    (local_time.tm_yday-gm_time.tm_yday)));
+  count=FormatLocaleString(timestamp,length,
+    "%04d-%02d-%02dT%02d:%02d:%02d%+03ld:00",local_time.tm_year+1900,
+    local_time.tm_mon+1,local_time.tm_mday,local_time.tm_hour,
+    local_time.tm_min,local_time.tm_sec,(long) timezone);
+  return(count);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t E n v i r o n m e n t V a l u e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetEnvironmentValue() returns the environment string that matches the
+%  specified name.
+%
+%  The format of the GetEnvironmentValue method is:
+%
+%      char *GetEnvironmentValue(const char *name)
+%
+%  A description of each parameter follows:
+%
+%    o name: the environment name.
+%
+*/
+MagickExport char *GetEnvironmentValue(const char *name)
+{
+  const char
+    *environment;
+
+  environment=getenv(name);
+  if (environment == (const char *) NULL)
+    return((char *) NULL);
+  return(ConstantString(environment));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t S t r i n g I n f o D a t u m                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetStringInfoDatum() returns the datum associated with the string.
+%
+%  The format of the GetStringInfoDatum method is:
+%
+%      unsigned char *GetStringInfoDatum(const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport unsigned char *GetStringInfoDatum(const StringInfo *string_info)
+{
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  return(string_info->datum);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t S t r i n g I n f o L e n g t h                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetStringInfoLength() returns the string length.
+%
+%  The format of the GetStringInfoLength method is:
+%
+%      size_t GetStringInfoLength(const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport size_t GetStringInfoLength(const StringInfo *string_info)
+{
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  return(string_info->length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t S t r i n g I n f o P a t h                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetStringInfoPath() returns the path associated with the string.
+%
+%  The format of the GetStringInfoPath method is:
+%
+%      const char *GetStringInfoPath(const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport const char *GetStringInfoPath(const StringInfo *string_info)
+{
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  return(string_info->path);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L o c a l e C o m p a r e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LocaleCompare() performs a case-insensitive comparison of two strings
+%  byte-by-byte, according to the ordering of the current locale encoding.
+%  LocaleCompare returns an integer greater than, equal to, or less than 0,
+%  if the string pointed to by p is greater than, equal to, or less than the
+%  string pointed to by q respectively.  The sign of a non-zero return value
+%  is determined by the sign of the difference between the values of the first
+%  pair of bytes that differ in the strings being compared.
+%
+%  The format of the LocaleCompare method is:
+%
+%      int LocaleCompare(const char *p,const char *q)
+%
+%  A description of each parameter follows:
+%
+%    o p: A pointer to a character string.
+%
+%    o q: A pointer to a character string to compare to p.
+%
+*/
+MagickExport int LocaleCompare(const char *p,const char *q)
+{
+  if ((p == (char *) NULL) && (q == (char *) NULL))
+    return(0);
+  if (p == (char *) NULL)
+    return(-1);
+  if (q == (char *) NULL)
+    return(1);
+#if defined(MAGICKCORE_HAVE_STRCASECMP)
+  return(strcasecmp(p,q));
+#else
+  {
+    register int
+      c,
+      d;
+
+    for ( ; ; )
+    {
+      c=(int) *((unsigned char *) p);
+      d=(int) *((unsigned char *) q);
+      if ((c == 0) || (AsciiMap[c] != AsciiMap[d]))
+        break;
+      p++;
+      q++;
+    }
+    return(AsciiMap[c]-(int) AsciiMap[d]);
+  }
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L o c a l e L o w e r                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LocaleLower() transforms all of the characters in the supplied
+%  null-terminated string, changing all uppercase letters to lowercase.
+%
+%  The format of the LocaleLower method is:
+%
+%      void LocaleLower(char *string)
+%
+%  A description of each parameter follows:
+%
+%    o string: A pointer to the string to convert to lower-case Locale.
+%
+*/
+MagickExport void LocaleLower(char *string)
+{
+  register char
+    *q;
+
+  assert(string != (char *) NULL);
+  for (q=string; *q != '\0'; q++)
+    *q=(char) tolower((int) *q);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L o c a l e N C o m p a r e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LocaleNCompare() performs a case-insensitive comparison of two
+%  strings byte-by-byte, according to the ordering of the current locale
+%  encoding. LocaleNCompare returns an integer greater than, equal to, or
+%  less than 0, if the string pointed to by p is greater than, equal to, or
+%  less than the string pointed to by q respectively.  The sign of a non-zero
+%  return value is determined by the sign of the difference between the
+%  values of the first pair of bytes that differ in the strings being
+%  compared.  The LocaleNCompare method makes the same comparison as
+%  LocaleCompare but looks at a maximum of n bytes.  Bytes following a
+%  null byte are not compared.
+%
+%  The format of the LocaleNCompare method is:
+%
+%      int LocaleNCompare(const char *p,const char *q,const size_t n)
+%
+%  A description of each parameter follows:
+%
+%    o p: A pointer to a character string.
+%
+%    o q: A pointer to a character string to compare to p.
+%
+%    o length: the number of characters to compare in strings p and q.
+%
+*/
+MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
+{
+  if (p == (char *) NULL)
+    return(-1);
+  if (q == (char *) NULL)
+    return(1);
+#if defined(MAGICKCORE_HAVE_STRNCASECMP)
+  return(strncasecmp(p,q,length));
+#else
+  {
+    register int
+      c,
+      d;
+
+    register size_t
+      i;
+
+    for (i=length; i != 0; i--)
+    {
+      c=(int) *((unsigned char *) p);
+      d=(int) *((unsigned char *) q);
+      if (AsciiMap[c] != AsciiMap[d])
+        return(AsciiMap[c]-(int) AsciiMap[d]);
+      if (c == 0)
+        return(0);
+      p++;
+      q++;
+    }
+    return(0);
+  }
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L o c a l e U p p e r                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LocaleUpper() transforms all of the characters in the supplied
+%  null-terminated string, changing all lowercase letters to uppercase.
+%
+%  The format of the LocaleUpper method is:
+%
+%      void LocaleUpper(char *string)
+%
+%  A description of each parameter follows:
+%
+%    o string: A pointer to the string to convert to upper-case Locale.
+%
+*/
+MagickExport void LocaleUpper(char *string)
+{
+  register char
+    *q;
+
+  assert(string != (char *) NULL);
+  for (q=string; *q != '\0'; q++)
+    *q=(char) toupper((int) *q);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P r i n t S t r i n g I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PrintStringInfo() prints the string.
+%
+%  The format of the PrintStringInfo method is:
+%
+%      void PrintStringInfo(FILE *file,const char *id,
+%        const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o file: the file, typically stdout.
+%
+%    o id: the string id.
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport void PrintStringInfo(FILE *file,const char *id,
+  const StringInfo *string_info)
+{
+  register const char
+    *p;
+
+  register size_t
+    i,
+    j;
+
+  assert(id != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",id);
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  p=(char *) string_info->datum;
+  for (i=0; i < string_info->length; i++)
+  {
+    if (((int) ((unsigned char) *p) < 32) &&
+        (isspace((int) ((unsigned char) *p)) == 0))
+      break;
+    p++;
+  }
+  if (i == string_info->length)
+    {
+      (void) fputs((char *) string_info->datum,file);
+      (void) fputc('\n',file);
+      return;
+    }
+  /*
+    Convert string to a HEX list.
+  */
+  p=(char *) string_info->datum;
+  for (i=0; i < string_info->length; i+=0x14)
+  {
+    (void) FormatLocaleFile(file,"0x%08lx: ",(unsigned long) (0x14*i));
+    for (j=1; j <= MagickMin(string_info->length-i,0x14); j++)
+    {
+      (void) FormatLocaleFile(file,"%02lx",(unsigned long) (*(p+j)) & 0xff);
+      if ((j % 0x04) == 0)
+        (void) fputc(' ',file);
+    }
+    for ( ; j <= 0x14; j++)
+    {
+      (void) fputc(' ',file);
+      (void) fputc(' ',file);
+      if ((j % 0x04) == 0)
+        (void) fputc(' ',file);
+    }
+    (void) fputc(' ',file);
+    for (j=1; j <= MagickMin(string_info->length-i,0x14); j++)
+    {
+      if (isprint((int) ((unsigned char) *p)) != 0)
+        (void) fputc(*p,file);
+      else
+        (void) fputc('-',file);
+      p++;
+    }
+    (void) fputc('\n',file);
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t S t r i n g I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetStringInfo() reset the string to all null bytes.
+%
+%  The format of the ResetStringInfo method is:
+%
+%      void ResetStringInfo(StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport void ResetStringInfo(StringInfo *string_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  (void) ResetMagickMemory(string_info->datum,0,string_info->length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t S t r i n g I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStringInfo() copies the source string to the destination string.
+%
+%  The format of the SetStringInfo method is:
+%
+%      void SetStringInfo(StringInfo *string_info,const StringInfo *source)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+%    o source: the source string.
+%
+*/
+MagickExport void SetStringInfo(StringInfo *string_info,
+  const StringInfo *source)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  assert(source != (StringInfo *) NULL);
+  assert(source->signature == MagickSignature);
+  if (string_info->length == 0)
+    return;
+  (void) ResetMagickMemory(string_info->datum,0,string_info->length);
+  (void) memcpy(string_info->datum,source->datum,MagickMin(string_info->length,
+    source->length));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t S t r i n g I n f o D a t u m                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStringInfoDatum() copies bytes from the source string for the length of
+%  the destination string.
+%
+%  The format of the SetStringInfoDatum method is:
+%
+%      void SetStringInfoDatum(StringInfo *string_info,
+%        const unsigned char *source)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+%    o source: the source string.
+%
+*/
+MagickExport void SetStringInfoDatum(StringInfo *string_info,
+  const unsigned char *source)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  if (string_info->length != 0)
+    (void) memcpy(string_info->datum,source,string_info->length);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t S t r i n g I n f o L e n g t h                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStringInfoLength() set the string length to the specified value.
+%
+%  The format of the SetStringInfoLength method is:
+%
+%      void SetStringInfoLength(StringInfo *string_info,const size_t length)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+%    o length: the string length.
+%
+*/
+MagickExport void SetStringInfoLength(StringInfo *string_info,
+  const size_t length)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  if (~length < MaxTextExtent)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  string_info->length=length;
+  if (string_info->datum == (unsigned char *) NULL)
+    string_info->datum=(unsigned char *) AcquireQuantumMemory(length+
+      MaxTextExtent,sizeof(*string_info->datum));
+  else
+    string_info->datum=(unsigned char *) ResizeQuantumMemory(string_info->datum,
+      length+MaxTextExtent,sizeof(*string_info->datum));
+  if (string_info->datum == (unsigned char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t S t r i n g I n f o D a t u m                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetStringInfoPath() sets the path associated with the string.
+%
+%  The format of the SetStringInfoPath method is:
+%
+%      void SetStringInfoPath(StringInfo *string_info,const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+%    o path: the path.
+%
+*/
+MagickExport void SetStringInfoPath(StringInfo *string_info,const char *path)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  assert(path != (const char *) NULL);
+  (void) CopyMagickString(string_info->path,path,MaxTextExtent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p l i t S t r i n g I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SplitStringInfo() splits a string into two and returns it.
+%
+%  The format of the SplitStringInfo method is:
+%
+%      StringInfo *SplitStringInfo(StringInfo *string_info,const size_t offset)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string info.
+%
+*/
+MagickExport StringInfo *SplitStringInfo(StringInfo *string_info,
+  const size_t offset)
+{
+  StringInfo
+    *split_info;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string_info != (StringInfo *) NULL);
+  assert(string_info->signature == MagickSignature);
+  if (offset > string_info->length)
+    return((StringInfo *) NULL);
+  split_info=AcquireStringInfo(offset);
+  SetStringInfo(split_info,string_info);
+  (void) memmove(string_info->datum,string_info->datum+offset,
+    string_info->length-offset+MaxTextExtent);
+  SetStringInfoLength(string_info,string_info->length-offset);
+  return(split_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i n g I n f o T o S t r i n g                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringInfoToString() converts a string info string to a C string.
+%
+%  The format of the StringInfoToString method is:
+%
+%      char *StringInfoToString(const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string.
+%
+*/
+MagickExport char *StringInfoToString(const StringInfo *string_info)
+{
+  char
+    *string;
+
+  size_t
+    length;
+
+  string=(char *) NULL;
+  length=string_info->length;
+  if (~length >= (MaxTextExtent-1))
+    string=(char *) AcquireQuantumMemory(length+MaxTextExtent,sizeof(*string));
+  if (string == (char *) NULL)
+    return((char *) NULL);
+  (void) memcpy(string,(char *) string_info->datum,length*sizeof(*string));
+  string[length]='\0';
+  return(string);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  S t r i n g T o A r g v                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringToArgv() converts a text string into command line arguments.
+%
+%  The format of the StringToArgv method is:
+%
+%      char **StringToArgv(const char *text,int *argc)
+%
+%  A description of each parameter follows:
+%
+%    o argv:  Method StringToArgv returns the string list unless an error
+%      occurs, otherwise NULL.
+%
+%    o text:  Specifies the string to segment into a list.
+%
+%    o argc:  This integer pointer returns the number of arguments in the
+%      list.
+%
+*/
+MagickExport char **StringToArgv(const char *text,int *argc)
+{
+  char
+    **argv;
+
+  register const char
+    *p,
+    *q;
+
+  register ssize_t
+    i;
+
+  *argc=0;
+  if (text == (char *) NULL)
+    return((char **) NULL);
+  /*
+    Determine the number of arguments.
+  */
+  for (p=text; *p != '\0'; )
+  {
+    while (isspace((int) ((unsigned char) *p)) != 0)
+      p++;
+    if (*p == '\0')
+      break;
+    (*argc)++;
+    if (*p == '"')
+      for (p++; (*p != '"') && (*p != '\0'); p++) ;
+    if (*p == '\'')
+      for (p++; (*p != '\'') && (*p != '\0'); p++) ;
+    while ((isspace((int) ((unsigned char) *p)) == 0) && (*p != '\0'))
+      p++;
+  }
+  (*argc)++;
+  argv=(char **) AcquireQuantumMemory((size_t) (*argc+1UL),sizeof(*argv));
+  if (argv == (char **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToConvertStringToARGV");
+  /*
+    Convert string to an ASCII list.
+  */
+  argv[0]=AcquireString("magick");
+  p=text;
+  for (i=1; i < (ssize_t) *argc; i++)
+  {
+    while (isspace((int) ((unsigned char) *p)) != 0)
+      p++;
+    q=p;
+    if (*q == '"')
+      {
+        p++;
+        for (q++; (*q != '"') && (*q != '\0'); q++) ;
+      }
+    else
+      if (*q == '\'')
+        {
+          p++;
+          for (q++; (*q != '\'') && (*q != '\0'); q++) ;
+        }
+      else
+        while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
+          q++;
+    argv[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
+      sizeof(**argv));
+    if (argv[i] == (char *) NULL)
+      {
+        for (i--; i >= 0; i--)
+          argv[i]=DestroyString(argv[i]);
+        argv=(char **) RelinquishMagickMemory(argv);
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToConvertStringToARGV");
+      }
+    (void) memcpy(argv[i],p,(size_t) (q-p));
+    argv[i][q-p]='\0';
+    p=q;
+    while ((isspace((int) ((unsigned char) *p)) == 0) && (*p != '\0'))
+      p++;
+  }
+  argv[i]=(char *) NULL;
+  return(argv);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i n g I n f o T o H e x S t r i n g                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringInfoToHexString() converts a string info string to a C string.
+%
+%  The format of the StringInfoToHexString method is:
+%
+%      char *StringInfoToHexString(const StringInfo *string_info)
+%
+%  A description of each parameter follows:
+%
+%    o string_info: the string.
+%
+*/
+MagickExport char *StringInfoToHexString(const StringInfo *string_info)
+{
+  char
+    *string;
+
+  register const unsigned char
+    *p;
+
+  register ssize_t
+    i;
+
+  register unsigned char
+    *q;
+
+  size_t
+    length;
+
+  unsigned char
+    hex_digits[16];
+
+  length=string_info->length;
+  if (~length < MaxTextExtent)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  string=(char *) AcquireQuantumMemory(length+MaxTextExtent,2*sizeof(*string));
+  if (string == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  hex_digits[0]='0';
+  hex_digits[1]='1';
+  hex_digits[2]='2';
+  hex_digits[3]='3';
+  hex_digits[4]='4';
+  hex_digits[5]='5';
+  hex_digits[6]='6';
+  hex_digits[7]='7';
+  hex_digits[8]='8';
+  hex_digits[9]='9';
+  hex_digits[10]='a';
+  hex_digits[11]='b';
+  hex_digits[12]='c';
+  hex_digits[13]='d';
+  hex_digits[14]='e';
+  hex_digits[15]='f';
+  p=string_info->datum;
+  q=(unsigned char *) string;
+  for (i=0; i < (ssize_t) string_info->length; i++)
+  {
+    *q++=hex_digits[(*p >> 4) & 0x0f];
+    *q++=hex_digits[*p & 0x0f];
+    p++;
+  }
+  *q='\0';
+  return(string);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i n g T o k e n                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringToken() extracts a token a from the string.
+%
+%  The format of the StringToken method is:
+%
+%      char *StringToken(const char *delimiters,char **string)
+%
+%  A description of each parameter follows:
+%
+%    o delimiters: one or more delimiters.
+%
+%    o string: return the first token in the string.  If none is found, return
+%      NULL.
+%
+*/
+MagickExport char *StringToken(const char *delimiters,char **string)
+{
+  char
+    *q;
+
+  register char
+    *p;
+
+  register const char
+    *r;
+
+  register int
+    c,
+    d;
+
+  p=(*string);
+  if (p == (char *) NULL)
+    return((char *) NULL);
+  for (q=p; ; )
+  {
+    c=(*p++);
+    r=delimiters;
+    do
+    {
+      d=(*r++);
+      if (c == d)
+        {
+          if (c == '\0')
+            p=(char *) NULL;
+          else
+            p[-1]='\0';
+          *string=p;
+          return(q);
+        }
+    } while (d != '\0');
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  S t r i n g T o L i s t                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringToList() converts a text string into a list by segmenting the text
+%  string at each carriage return discovered.  The list is converted to HEX
+%  characters if any control characters are discovered within the text string.
+%
+%  The format of the StringToList method is:
+%
+%      char **StringToList(const char *text)
+%
+%  A description of each parameter follows:
+%
+%    o text:  Specifies the string to segment into a list.
+%
+*/
+MagickExport char **StringToList(const char *text)
+{
+  char
+    **textlist;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    lines;
+
+  if (text == (char *) NULL)
+    return((char **) NULL);
+  for (p=text; *p != '\0'; p++)
+    if (((int) ((unsigned char) *p) < 32) &&
+        (isspace((int) ((unsigned char) *p)) == 0))
+      break;
+  if (*p == '\0')
+    {
+      register const char
+        *q;
+
+      /*
+        Convert string to an ASCII list.
+      */
+      lines=1;
+      for (p=text; *p != '\0'; p++)
+        if (*p == '\n')
+          lines++;
+      textlist=(char **) AcquireQuantumMemory((size_t) lines+1UL,
+        sizeof(*textlist));
+      if (textlist == (char **) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
+      p=text;
+      for (i=0; i < (ssize_t) lines; i++)
+      {
+        for (q=p; *q != '\0'; q++)
+          if ((*q == '\r') || (*q == '\n'))
+            break;
+        textlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
+          sizeof(**textlist));
+        if (textlist[i] == (char *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
+        (void) memcpy(textlist[i],p,(size_t) (q-p));
+        textlist[i][q-p]='\0';
+        if (*q == '\r')
+          q++;
+        p=q+1;
+      }
+    }
+  else
+    {
+      char
+        hex_string[MaxTextExtent];
+
+      register char
+        *q;
+
+      register ssize_t
+        j;
+
+      /*
+        Convert string to a HEX list.
+      */
+      lines=(size_t) (strlen(text)/0x14)+1;
+      textlist=(char **) AcquireQuantumMemory((size_t) lines+1UL,
+        sizeof(*textlist));
+      if (textlist == (char **) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
+      p=text;
+      for (i=0; i < (ssize_t) lines; i++)
+      {
+        textlist[i]=(char *) AcquireQuantumMemory(2UL*MaxTextExtent,
+          sizeof(**textlist));
+        if (textlist[i] == (char *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"UnableToConvertText");
+        (void) FormatLocaleString(textlist[i],MaxTextExtent,"0x%08lx: ",
+          (long) (0x14*i));
+        q=textlist[i]+strlen(textlist[i]);
+        for (j=1; j <= (ssize_t) MagickMin(strlen(p),0x14); j++)
+        {
+          (void) FormatLocaleString(hex_string,MaxTextExtent,"%02x",*(p+j));
+          (void) CopyMagickString(q,hex_string,MaxTextExtent);
+          q+=2;
+          if ((j % 0x04) == 0)
+            *q++=' ';
+        }
+        for ( ; j <= 0x14; j++)
+        {
+          *q++=' ';
+          *q++=' ';
+          if ((j % 0x04) == 0)
+            *q++=' ';
+        }
+        *q++=' ';
+        for (j=1; j <= (ssize_t) MagickMin(strlen(p),0x14); j++)
+        {
+          if (isprint((int) ((unsigned char) *p)) != 0)
+            *q++=(*p);
+          else
+            *q++='-';
+          p++;
+        }
+        *q='\0';
+      }
+    }
+  textlist[i]=(char *) NULL;
+  return(textlist);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i n g T o S t r i n g I n f o                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StringToStringInfo() returns the contents of a file as a string.
+%
+%  The format of the StringToStringInfo method is:
+%
+%      StringInfo *StringToStringInfo(const char *string)
+%
+%  A description of each parameter follows:
+%
+%    o string:  The string.
+%
+*/
+MagickExport StringInfo *StringToStringInfo(const char *string)
+{
+  StringInfo
+    *string_info;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(string != (const char *) NULL);
+  string_info=AcquireStringInfo(strlen(string)+1);
+  SetStringInfoDatum(string_info,(const unsigned char *) string);
+  return(string_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S t r i p S t r i n g                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StripString() strips any whitespace or quotes from the beginning and end of
+%  a string of characters.
+%
+%  The format of the StripString method is:
+%
+%      void StripString(char *message)
+%
+%  A description of each parameter follows:
+%
+%    o message: Specifies an array of characters.
+%
+*/
+MagickExport void StripString(char *message)
+{
+  register char
+    *p,
+    *q;
+
+  size_t
+    length;
+
+  assert(message != (char *) NULL);
+  if (*message == '\0')
+    return;
+  length=strlen(message);
+  p=message;
+  while (isspace((int) ((unsigned char) *p)) != 0)
+    p++;
+  if ((*p == '\'') || (*p == '"'))
+    p++;
+  q=message+length-1;
+  while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
+    q--;
+  if (q > p)
+    if ((*q == '\'') || (*q == '"'))
+      q--;
+  (void) memmove(message,p,(size_t) (q-p+1));
+  message[q-p+1]='\0';
+  for (p=message; *p != '\0'; p++)
+    if (*p == '\n')
+      *p=' ';
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S u b s t i t u t e S t r i n g                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SubstituteString() performs string substitution on a string, replacing the
+%  string with the substituted version. Buffer must be allocated from the heap.
+%  If the string is matched and status, MagickTrue is returned otherwise
+%  MagickFalse.
+%
+%  The format of the SubstituteString method is:
+%
+%      MagickBooleanType SubstituteString(char **string,const char *search,
+%        const char *replace)
+%
+%  A description of each parameter follows:
+%
+%    o string: the string to perform replacements on;  replaced with new
+%      allocation if a replacement is made.
+%
+%    o search: search for this string.
+%
+%    o replace: replace any matches with this string.
+%
+*/
+MagickExport MagickBooleanType SubstituteString(char **string,
+  const char *search,const char *replace)
+{
+  MagickBooleanType
+    status;
+
+  register char
+    *p;
+
+  size_t
+    extent,
+    replace_extent,
+    search_extent;
+
+  ssize_t
+    offset;
+
+  status=MagickFalse;
+  search_extent=0,
+  replace_extent=0;
+  for (p=strchr(*string,*search); p != (char *) NULL; p=strchr(p+1,*search))
+  {
+    if (search_extent == 0)
+      search_extent=strlen(search);
+    if (strncmp(p,search,search_extent) != 0)
+      continue;
+    /*
+      We found a match.
+    */
+    status=MagickTrue;
+    if (replace_extent == 0)
+      replace_extent=strlen(replace);
+    if (replace_extent > search_extent)
+      {
+        /*
+          Make room for the replacement string.
+        */
+        offset=(ssize_t) (p-(*string));
+        extent=strlen(*string)+replace_extent-search_extent+1;
+        *string=(char *) ResizeQuantumMemory(*string,extent+MaxTextExtent,
+          sizeof(*p));
+        if (*string == (char *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+        p=(*string)+offset;
+      }
+    /*
+      Replace string.
+    */
+    if (search_extent != replace_extent)
+      (void) CopyMagickMemory(p+replace_extent,p+search_extent,
+        strlen(p+search_extent)+1);
+    (void) CopyMagickMemory(p,replace,replace_extent);
+    p+=replace_extent-1;
+  }
+  return(status);
+}
diff --git a/MagickCore/string_.h b/MagickCore/string_.h
new file mode 100644
index 0000000..96f6c0b
--- /dev/null
+++ b/MagickCore/string_.h
@@ -0,0 +1,109 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore string methods.
+*/
+#ifndef _MAGICKCORE_STRING_H_
+#define _MAGICKCORE_STRING_H_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <time.h>
+#include "MagickCore/exception.h"
+
+typedef struct _StringInfo
+{
+  char
+    path[MaxTextExtent];
+
+  unsigned char
+    *datum;
+
+  size_t
+    length,
+    signature;
+} StringInfo;
+
+extern MagickExport char
+  *AcquireString(const char *),
+  *CloneString(char **,const char *),
+  *ConstantString(const char *),
+  *DestroyString(char *),
+  **DestroyStringList(char **),
+  *EscapeString(const char *,const char),
+  *FileToString(const char *,const size_t,ExceptionInfo *),
+  *GetEnvironmentValue(const char *),
+  *StringInfoToHexString(const StringInfo *),
+  *StringInfoToString(const StringInfo *),
+  **StringToArgv(const char *,int *),
+  *StringToken(const char *,char **),
+  **StringToList(const char *);
+
+extern MagickExport const char
+  *GetStringInfoPath(const StringInfo *);
+
+extern MagickExport int
+  CompareStringInfo(const StringInfo *,const StringInfo *),
+  LocaleCompare(const char *,const char *),
+  LocaleNCompare(const char *,const char *,const size_t);
+
+extern MagickExport MagickBooleanType
+  ConcatenateString(char **,const char *),
+  SubstituteString(char **,const char *,const char *);
+
+extern MagickExport size_t
+  ConcatenateMagickString(char *,const char *,const size_t)
+    magick_attribute((nonnull)),
+  CopyMagickString(char *,const char *,const size_t)
+    magick_attribute((nonnull)),
+  GetStringInfoLength(const StringInfo *);
+
+extern MagickExport ssize_t
+  FormatMagickSize(const MagickSizeType,const MagickBooleanType,char *),
+  FormatMagickTime(const time_t,const size_t,char *);
+
+extern MagickExport StringInfo
+  *AcquireStringInfo(const size_t),
+  *CloneStringInfo(const StringInfo *),
+  *ConfigureFileToStringInfo(const char *),
+  *DestroyStringInfo(StringInfo *),
+  *FileToStringInfo(const char *,const size_t,ExceptionInfo *),
+  *SplitStringInfo(StringInfo *,const size_t),
+  *StringToStringInfo(const char *);
+
+extern MagickExport unsigned char
+  *GetStringInfoDatum(const StringInfo *);
+
+extern MagickExport void
+  ConcatenateStringInfo(StringInfo *,const StringInfo *)
+    magick_attribute((nonnull)),
+  LocaleLower(char *),
+  LocaleUpper(char *),
+  PrintStringInfo(FILE *file,const char *,const StringInfo *),
+  ResetStringInfo(StringInfo *),
+  SetStringInfo(StringInfo *,const StringInfo *),
+  SetStringInfoDatum(StringInfo *,const unsigned char *),
+  SetStringInfoLength(StringInfo *,const size_t),
+  SetStringInfoPath(StringInfo *,const char *),
+  StripString(char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/studio.h b/MagickCore/studio.h
new file mode 100644
index 0000000..1e9bd8a
--- /dev/null
+++ b/MagickCore/studio.h
@@ -0,0 +1,442 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private application programming interface declarations.
+*/
+#ifndef _MAGICKCORE_STUDIO_H
+#define _MAGICKCORE_STUDIO_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(WIN32) || defined(WIN64)
+#  define MAGICKCORE_WINDOWS_SUPPORT
+#else
+#  define MAGICKCORE_POSIX_SUPPORT
+#endif
+
+#define MAGICKCORE_IMPLEMENTATION  1
+
+#if !defined(_MAGICKCORE_CONFIG_H)
+# define _MAGICKCORE_CONFIG_H
+# if !defined(vms) && !defined(macintosh)
+#  include "MagickCore/magick-config.h"
+# else
+#  include "magick-config.h"
+# endif
+#if defined(MAGICKCORE__FILE_OFFSET_BITS) && !defined(_FILE_OFFSET_BITS)
+# define _FILE_OFFSET_BITS MAGICKCORE__FILE_OFFSET_BITS
+#endif
+#if defined(_magickcore_const) && !defined(const)
+# define const  _magickcore_const
+#endif
+#if defined(_magickcore_inline) && !defined(inline)
+# define inline  _magickcore_inline
+#endif
+#if defined(_magickcore_restrict) && !defined(restrict)
+# define restrict  _magickcore_restrict
+#endif
+# if defined(__cplusplus) || defined(c_plusplus)
+#  undef inline
+# endif
+#endif
+
+#if defined(MAGICKCORE_NAMESPACE_PREFIX)
+# include "MagickCore/methods.h"
+#endif
+
+#if !defined(const)
+#  define STDC
+#endif
+
+#if defined(__BORLANDC__) && defined(_DLL)
+#  pragma message("BCBMagick lib DLL export interface")
+#  define _MAGICKDLL_
+#  define _MAGICKLIB_
+#  define MAGICKCORE_MODULES_SUPPORT
+#  undef MAGICKCORE_BUILD_MODULES
+#endif
+
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__CYGWIN__) && !defined(__MINGW32__)
+# if defined(_MT) && defined(_DLL) && !defined(_MAGICKDLL_) && !defined(_LIB)
+#  define _MAGICKDLL_
+# endif
+# if defined(_MAGICKDLL_)
+#  if defined(_VISUALC_)
+#   pragma warning( disable: 4273 )  /* Disable the dll linkage warnings */
+#  endif
+#  if !defined(_MAGICKLIB_)
+#   define MagickExport  __declspec(dllimport)
+#   if defined(_VISUALC_)
+#    pragma message( "MagickCore lib DLL import interface" )
+#   endif
+#  else
+#   define MagickExport  __declspec(dllexport)
+#   if defined(_VISUALC_)
+#    pragma message( "MagickCore lib DLL export interface" )
+#   endif
+#  endif
+# else
+#  define MagickExport
+#  if defined(_VISUALC_)
+#   pragma message( "MagickCore lib static interface" )
+#  endif
+# endif
+
+# if defined(_DLL) && !defined(_LIB)
+#  define ModuleExport  __declspec(dllexport)
+#  if defined(_VISUALC_)
+#   pragma message( "MagickCore module DLL export interface" )
+#  endif
+# else
+#  define ModuleExport
+#  if defined(_VISUALC_)
+#   pragma message( "MagickCore module static interface" )
+#  endif
+
+# endif
+# define MagickGlobal __declspec(thread)
+# if defined(_VISUALC_)
+#  pragma warning(disable : 4018)
+#  pragma warning(disable : 4068)
+#  pragma warning(disable : 4244)
+#  pragma warning(disable : 4142)
+#  pragma warning(disable : 4800)
+#  pragma warning(disable : 4786)
+#  pragma warning(disable : 4996)
+# endif
+#else
+# define MagickExport
+# define ModuleExport
+# define MagickGlobal
+#endif
+
+#define MagickSignature  0xabacadabUL
+#if !defined(MaxTextExtent)
+# define MaxTextExtent  4096
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#if defined(MAGICKCORE_HAVE_SYS_STAT_H)
+# include <sys/stat.h>
+#endif
+#if defined(MAGICKCORE_STDC_HEADERS)
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if defined(MAGICKCORE_HAVE_STDLIB_H)
+#  include <stdlib.h>
+# endif
+#endif
+#if defined(MAGICKCORE_HAVE_STRING_H)
+# if !defined(STDC_HEADERS) && defined(MAGICKCORE_HAVE_MEMORY_H)
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if defined(MAGICKCORE_HAVE_STRINGS_H)
+# include <strings.h>
+#endif
+#if defined(MAGICKCORE_HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
+#if defined(MAGICKCORE_HAVE_STDINT_H)
+# include <stdint.h>
+#endif
+#if defined(MAGICKCORE_HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) && defined(_DEBUG)
+#define _CRTDBG_MAP_ALLOC
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+# include <direct.h>
+# if !defined(MAGICKCORE_HAVE_STRERROR)
+#  define HAVE_STRERROR
+# endif
+#endif
+
+#include <ctype.h>
+#include <locale.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+#include <signal.h>
+#include <assert.h>
+
+#if defined(MAGICKCORE_HAVE_XLOCALE_H)
+# include <xlocale.h>
+#endif
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+# include <pthread.h>
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+#  define MAGICKCORE_HAVE_WINTHREADS  1
+#include <windows.h>
+#endif
+#if defined(MAGICKCORE_HAVE_SYS_SYSLIMITS_H)
+# include <sys/syslimits.h>
+#endif
+#if defined(MAGICKCORE_HAVE_ARM_LIMITS_H)
+# include <arm/limits.h>
+#endif
+
+#if defined(MAGICKCORE__OPENCL)
+#if defined(MAGICKCORE_HAVE_CL_CL_H)
+#  include <CL/cl.h>
+#endif
+#if defined(MAGICKCORE_HAVE_OPENCL_CL_H)
+#  include <OpenCL/cl.h>
+#endif
+#  define MAGICKCORE_OPENCL_SUPPORT  1
+#endif
+
+#if defined(_OPENMP) && (_OPENMP >= 200203)
+#  include <omp.h>
+#  define MAGICKCORE_OPENMP_SUPPORT  1
+#endif
+
+#if defined(MAGICKCORE_HAVE_PREAD) && defined(MAGICKCORE_HAVE_DECL_PREAD) && !MAGICKCORE_HAVE_DECL_PREAD
+ssize_t pread(int,void *,size_t,off_t);
+#endif
+
+#if defined(MAGICKCORE_HAVE_PWRITE) && defined(MAGICKCORE_HAVE_DECL_PWRITE) && !MAGICKCORE_HAVE_DECL_PWRITE
+ssize_t pwrite(int,const void *,size_t,off_t);
+#endif
+
+#if defined(MAGICKCORE_HAVE_STRLCPY) && defined(MAGICKCORE_HAVE_DECL_STRLCPY) && !MAGICKCORE_HAVE_DECL_STRLCPY
+extern size_t strlcpy(char *,const char *,size_t);
+#endif
+
+#if defined(MAGICKCORE_HAVE_VSNPRINTF) && defined(MAGICKCORE_HAVE_DECL_VSNPRINTF) && !MAGICKCORE_HAVE_DECL_VSNPRINTF
+extern int vsnprintf(char *,size_t,const char *,va_list);
+#endif
+
+#if defined(MAGICKCORE_HAVE___ATTRIBUTE__)
+#  define magick_aligned(x)  __attribute__((aligned(x)))
+#  define magick_attribute  __attribute__
+#  define magick_unused(x)  magick_unused_ ## x __attribute__((unused))
+#else
+#  define magick_aligned(x)  /* nothing */
+#  define magick_attribute(x)  /* nothing */
+#  define magick_unused(x) x
+#endif
+
+#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(MAGICKCORE_POSIX_SUPPORT)
+# include <sys/types.h>
+# include <sys/stat.h>
+# if defined(MAGICKCORE_HAVE_FTIME)
+# include <sys/timeb.h>
+# endif
+# if defined(MAGICKCORE_POSIX_SUPPORT)
+#  if defined(MAGICKCORE_HAVE_SYS_NDIR_H) || defined(MAGICKCORE_HAVE_SYS_DIR_H) || defined(MAGICKCORE_HAVE_NDIR_H)
+#   define dirent direct
+#   define NAMLEN(dirent) (dirent)->d_namlen
+#   if defined(MAGICKCORE_HAVE_SYS_NDIR_H)
+#    include <sys/ndir.h>
+#   endif
+#   if defined(MAGICKCORE_HAVE_SYS_DIR_H)
+#    include <sys/dir.h>
+#   endif
+#   if defined(MAGICKCORE_HAVE_NDIR_H)
+#    include <ndir.h>
+#   endif
+#  else
+#   include <dirent.h>
+#   define NAMLEN(dirent) strlen((dirent)->d_name)
+#  endif
+#  include <sys/wait.h>
+#  include <pwd.h>
+# endif
+# if !defined(S_ISDIR)
+#  define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+# endif
+# if !defined(S_ISREG)
+#  define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+# endif
+# include "MagickCore/magick-type.h"
+# if !defined(MAGICKCORE_WINDOWS_SUPPORT)
+#  include <sys/time.h>
+# if defined(MAGICKCORE_HAVE_SYS_TIMES_H)
+#  include <sys/times.h>
+# endif
+# if defined(MAGICKCORE_HAVE_SYS_RESOURCE_H)
+#  include <sys/resource.h>
+# endif
+#endif
+#else
+# include <types.h>
+# include <stat.h>
+# if defined(macintosh)
+#  if !defined(DISABLE_SIOUX)
+#   include <SIOUX.h>
+#   include <console.h>
+#  endif
+#  include <unix.h>
+# endif
+# include "MagickCore/magick-type.h"
+#endif
+
+#if defined(S_IRUSR) && defined(S_IWUSR)
+# define S_MODE (S_IRUSR | S_IWUSR)
+#elif defined (MAGICKCORE_WINDOWS_SUPPORT)
+# define S_MODE (_S_IREAD | _S_IWRITE)
+#else
+# define S_MODE  0600
+#endif
+
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+# include "MagickCore/nt-base.h"
+#endif
+#if defined(macintosh)
+# include "MagickCore/mac.h"
+#endif
+#if defined(vms)
+# include "MagickCore/vms.h"
+#endif
+
+#undef HAVE_CONFIG_H
+#undef gamma
+#undef index
+#undef pipe
+#undef y1
+
+/*
+  Review these platform specific definitions.
+*/
+#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
+# define DirectorySeparator  "/"
+# define DirectoryListSeparator  ':'
+# define EditorOptions  " -title \"Edit Image Comment\" -e vi"
+# define Exit  exit
+# define IsBasenameSeparator(c)  ((c) == '/' ? MagickTrue : MagickFalse)
+# define X11_PREFERENCES_PATH  "~/."
+# define ProcessPendingEvents(text)
+# define ReadCommandlLine(argc,argv)
+# define SetNotifyHandlers
+#else
+# if defined(vms)
+#  define X11_APPLICATION_PATH  "decw$system_defaults:"
+#  define DirectorySeparator  ""
+#  define DirectoryListSeparator  ';'
+#  define EditorOptions  ""
+#  define Exit  exit
+#  define IsBasenameSeparator(c) \
+  (((c) == ']') || ((c) == ':') || ((c) == '/') ? MagickTrue : MagickFalse)
+#  define MAGICKCORE_LIBRARY_PATH  "sys$login:"
+#  define MAGICKCORE_CODER_PATH  "sys$login:"
+#  define MAGICKCORE_FILTER_PATH  "sys$login:"
+#  define MAGICKCORE_SHARE_PATH  "sys$login:"
+#  define X11_PREFERENCES_PATH  "decw$user_defaults:"
+#  define ProcessPendingEvents(text)
+#  define ReadCommandlLine(argc,argv)
+#  define SetNotifyHandlers
+# endif
+# if defined(__OS2__)
+#   define DirectorySeparator  "\\"
+#   define DirectoryListSeparator  ';'
+# define EditorOptions  " -title \"Edit Image Comment\" -e vi"
+# define Exit  exit
+#  define IsBasenameSeparator(c) \
+  (((c) == '/') || ((c) == '\\') ? MagickTrue : MagickFalse)
+# define PreferencesDefaults  "~\."
+# define ProcessPendingEvents(text)
+# define ReadCommandlLine(argc,argv)
+# define SetNotifyHandlers
+#endif
+# if defined(macintosh)
+#  define X11_APPLICATION_PATH  "/usr/lib/X11/app-defaults/"
+#  define DirectorySeparator  ":"
+#  define DirectoryListSeparator  ';'
+#  define EditorOptions ""
+#  define IsBasenameSeparator(c)  ((c) == ':' ? MagickTrue : MagickFalse)
+#  define MAGICKCORE_LIBRARY_PATH  ""
+#  define MAGICKCORE_CODER_PATH  ""
+#  define MAGICKCORE_FILTER_PATH  ""
+#  define MAGICKCORE_SHARE_PATH  ""
+#  define X11_PREFERENCES_PATH  "~/."
+#  if defined(DISABLE_SIOUX)
+#   define ReadCommandlLine(argc,argv)
+#   define SetNotifyHandlers \
+     SetFatalErrorHandler(MacFatalErrorHandler); \
+     SetErrorHandler(MACErrorHandler); \
+     SetWarningHandler(MACWarningHandler)
+#  else
+#   define ReadCommandlLine(argc,argv) argc=ccommand(argv); puts(MagickVersion);
+#   define SetNotifyHandlers \
+     SetErrorHandler(MACErrorHandler); \
+     SetWarningHandler(MACWarningHandler)
+#  endif
+# endif
+# if defined(MAGICKCORE_WINDOWS_SUPPORT)
+#  define DirectorySeparator  "\\"
+#  define DirectoryListSeparator  ';'
+#  define EditorOptions ""
+#  define IsBasenameSeparator(c) \
+  (((c) == '/') || ((c) == '\\') ? MagickTrue : MagickFalse)
+#  define ProcessPendingEvents(text)
+#  if !defined(X11_PREFERENCES_PATH)
+#    define X11_PREFERENCES_PATH  "~\\."
+#  endif
+#  define ReadCommandlLine(argc,argv)
+#  define SetNotifyHandlers \
+    SetErrorHandler(NTErrorHandler); \
+    SetWarningHandler(NTWarningHandler)
+#  undef sleep
+#  define sleep(seconds)  Sleep(seconds*1000)
+#  if !defined(MAGICKCORE_HAVE_TIFFCONF_H)
+#    define HAVE_TIFFCONF_H
+#  endif
+# endif
+
+#endif
+
+/*
+  Define system symbols if not already defined.
+*/
+#if !defined(STDIN_FILENO)
+#define STDIN_FILENO  0x00
+#endif
+
+#if !defined(O_BINARY)
+#define O_BINARY  0x00
+#endif
+
+#if !defined(PATH_MAX)
+#define PATH_MAX  4096
+#endif
+
+#if defined(MAGICKCORE_LTDL_DELEGATE) || (defined(MAGICKCORE_WINDOWS_SUPPORT) && defined(_DLL) && !defined(_LIB))
+#  define MAGICKCORE_MODULES_SUPPORT
+#endif
+
+#if defined(_MAGICKMOD_)
+# undef MAGICKCORE_BUILD_MODULES
+# define MAGICKCORE_BUILD_MODULES
+#endif
+
+/*
+  Magick defines.
+*/
+#define Swap(x,y) ((x)^=(y), (y)^=(x), (x)^=(y))
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/thread-private.h b/MagickCore/thread-private.h
new file mode 100644
index 0000000..6b726c2
--- /dev/null
+++ b/MagickCore/thread-private.h
@@ -0,0 +1,146 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private methods for internal threading.
+*/
+#ifndef _MAGICKCORE_THREAD_PRIVATE_H
+#define _MAGICKCORE_THREAD_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/thread_.h>
+
+#define omp_throttle(factor)  num_threads(omp_get_max_threads() >> (factor))
+
+#if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR > 10))
+#define MagickCachePrefetch(address,mode,locality) \
+  __builtin_prefetch(address,mode,locality)
+#else
+#define MagickCachePrefetch(address,mode,locality)
+#endif
+
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  typedef pthread_mutex_t MagickMutexType;
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  typedef CRITICAL_SECTION MagickMutexType;
+#else
+  typedef size_t MagickMutexType;
+#endif
+
+static inline MagickThreadType GetMagickThreadId(void)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  return(pthread_self());
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  return(GetCurrentThreadId());
+#else
+  return(getpid());
+#endif
+}
+
+static inline size_t GetMagickThreadSignature(void)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  {
+    union
+    {
+      pthread_t
+        id;
+
+      size_t
+        signature;
+    } magick_thread;
+
+    magick_thread.signature=0UL;
+    magick_thread.id=pthread_self();
+    return(magick_thread.signature);
+  }
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  return((size_t) GetCurrentThreadId());
+#else
+  return((size_t) getpid());
+#endif
+}
+
+static inline MagickBooleanType IsMagickThreadEqual(const MagickThreadType id)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  if (pthread_equal(id,pthread_self()) != 0)
+    return(MagickTrue);
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  if (id == GetCurrentThreadId())
+    return(MagickTrue);
+#else
+  if (id == getpid())
+    return(MagickTrue);
+#endif
+  return(MagickFalse);
+}
+
+/*
+  Lightweight OpenMP methods.
+*/
+static inline size_t GetOpenMPMaximumThreads(void)
+{
+  static size_t
+    maximum_threads = 1;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+  {
+    ssize_t
+      threads;
+
+    threads=omp_get_max_threads();
+    if (threads > (ssize_t) maximum_threads)
+      maximum_threads=threads;
+  }
+#endif
+  return(maximum_threads);
+}
+
+static inline int GetOpenMPThreadId(void)
+{
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+  return(omp_get_thread_num());
+#else
+  return(0);
+#endif
+}
+
+static inline void SetOpenMPMaximumThreads(const int threads)
+{
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+  omp_set_num_threads(threads);
+#else
+  (void) threads;
+#endif
+}
+
+static inline void SetOpenMPNested(const int value)
+{
+#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+  omp_set_nested(value);
+#else
+  (void) value;
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/thread.c b/MagickCore/thread.c
new file mode 100644
index 0000000..b09da48
--- /dev/null
+++ b/MagickCore/thread.c
@@ -0,0 +1,181 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                  TTTTT  H   H  RRRR   EEEEE   AAA   DDDD                    %
+%                    T    H   H  R   R  E      A   A  D   D                   %
+%                    T    HHHHH  RRRR   EEE    AAAAA  D   D                   %
+%                    T    H   H  R R    E      A   A  D   D                   %
+%                    T    H   H  R  R   EEEEE  A   A  DDDD                    %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Thread Methods                           %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                               March  2003                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/thread_.h"
+#include "MagickCore/thread-private.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k C r e a t e T h r e a d K e y                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickCreateThreadKey() creates a thread key and returns it.
+%
+%  The format of the MagickCreateThreadKey method is:
+%
+%      MagickThreadKey MagickCreateThreadKey(MagickThreadKey *key)
+%
+*/
+MagickExport MagickBooleanType MagickCreateThreadKey(MagickThreadKey *key)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  return(pthread_key_create(key,NULL) == 0 ? MagickTrue : MagickFalse);
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  *key=TlsAlloc();
+  return(*key != TLS_OUT_OF_INDEXES ? MagickTrue : MagickFalse);
+#else
+  *key=AcquireMagickMemory(sizeof(key));
+  return(*key != (void *) NULL ? MagickTrue : MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k D e l e t e T h r e a d K e y                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickDeleteThreadKey() deletes a thread key.
+%
+%  The format of the AcquireAESInfo method is:
+%
+%      MagickBooleanType MagickDeleteThreadKey(MagickThreadKey key)
+%
+%  A description of each parameter follows:
+%
+%    o key: the thread key.
+%
+*/
+MagickExport MagickBooleanType MagickDeleteThreadKey(MagickThreadKey key)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  return(pthread_key_delete(key) == 0 ? MagickTrue : MagickFalse);
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  return(TlsFree(key) != 0 ? MagickTrue : MagickFalse);
+#else
+  key=(MagickThreadKey) RelinquishMagickMemory(key);
+  return(MagickTrue);
+#endif
+
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k G e t T h r e a d V a l u e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickGetThreadValue() returns a value associated with the thread key.
+%
+%  The format of the MagickGetThreadValue method is:
+%
+%      void *MagickGetThreadValue(MagickThreadKey key)
+%
+%  A description of each parameter follows:
+%
+%    o key: the thread key.
+%
+*/
+MagickExport void *MagickGetThreadValue(MagickThreadKey key)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  return(pthread_getspecific(key));
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  return(TlsGetValue(key));
+#else
+  return((void *) (*key));
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k S e t T h r e a d V a l u e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickSetThreadValue() associates a value with the thread key.
+%
+%  The format of the MagickSetThreadValue method is:
+%
+%      MagickBooleanType MagickSetThreadValue(MagickThreadKey key,
+%        const void *value)
+%
+%  A description of each parameter follows:
+%
+%    o key: the thread key.
+%
+%    o value: the value
+%
+*/
+MagickExport MagickBooleanType MagickSetThreadValue(MagickThreadKey key,
+  const void *value)
+{
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+  return(pthread_setspecific(key,value) == 0 ? MagickTrue : MagickFalse);
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+  return(TlsSetValue(key,(void *) value) != 0 ? MagickTrue : MagickFalse);
+#else
+  *key=(size_t) value;
+  return(MagickTrue);
+#endif
+}
diff --git a/MagickCore/thread_.h b/MagickCore/thread_.h
new file mode 100644
index 0000000..5db1eeb
--- /dev/null
+++ b/MagickCore/thread_.h
@@ -0,0 +1,53 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private methods for internal threading.
+*/
+#ifndef _MAGICKCORE_THREAD_H
+#define _MAGICKCORE_THREAD_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+typedef pthread_t MagickThreadType;
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+typedef DWORD MagickThreadType;
+#else
+typedef pid_t MagickThreadType;
+#endif
+
+#if defined(MAGICKCORE_THREAD_SUPPORT)
+typedef pthread_key_t MagickThreadKey;
+#elif defined(MAGICKCORE_HAVE_WINTHREADS)
+typedef DWORD MagickThreadKey;
+#else
+typedef size_t *MagickThreadKey;
+#endif
+
+extern MagickExport MagickBooleanType
+  MagickCreateThreadKey(MagickThreadKey *),
+  MagickDeleteThreadKey(MagickThreadKey),
+  MagickSetThreadValue(MagickThreadKey,const void *);
+
+extern MagickExport void
+  *MagickGetThreadValue(MagickThreadKey);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/threshold.c b/MagickCore/threshold.c
new file mode 100644
index 0000000..4b95cc1
--- /dev/null
+++ b/MagickCore/threshold.c
@@ -0,0 +1,2016 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%       TTTTT  H   H  RRRR   EEEEE  SSSSS  H   H   OOO   L      DDDD          %
+%         T    H   H  R   R  E      SS     H   H  O   O  L      D   D         %
+%         T    HHHHH  RRRR   EEE     SSS   HHHHH  O   O  L      D   D         %
+%         T    H   H  R R    E         SS  H   H  O   O  L      D   D         %
+%         T    H   H  R  R   EEEEE  SSSSS  H   H   OOO   LLLLL  DDDD          %
+%                                                                             %
+%                                                                             %
+%                      MagickCore Image Threshold Methods                     %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                 October 1996                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/constitute.h"
+#include "MagickCore/decorate.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/enhance.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/fx.h"
+#include "MagickCore/gem.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/montage.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/random-private.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/segment.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/xml-tree.h"
+
+/*
+  Define declarations.
+*/
+#define ThresholdsFilename  "thresholds.xml"
+
+/*
+  Typedef declarations.
+*/
+struct _ThresholdMap
+{
+  char
+    *map_id,
+    *description;
+
+  size_t
+    width,
+    height;
+
+  ssize_t
+    divisor,
+    *levels;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     A d a p t i v e T h r e s h o l d I m a g e                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AdaptiveThresholdImage() selects an individual threshold for each pixel
+%  based on the range of intensity values in its local neighborhood.  This
+%  allows for thresholding of an image whose global intensity histogram
+%  doesn't contain distinctive peaks.
+%
+%  The format of the AdaptiveThresholdImage method is:
+%
+%      Image *AdaptiveThresholdImage(const Image *image,
+%        const size_t width,const size_t height,
+%        const ssize_t offset,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o width: the width of the local neighborhood.
+%
+%    o height: the height of the local neighborhood.
+%
+%    o offset: the mean offset.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *AdaptiveThresholdImage(const Image *image,
+  const size_t width,const size_t height,const ssize_t offset,
+  ExceptionInfo *exception)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  CacheView
+    *image_view,
+    *threshold_view;
+
+  Image
+    *threshold_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    zero;
+
+  MagickRealType
+    number_pixels;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  threshold_image=CloneImage(image,0,0,MagickTrue,exception);
+  if (threshold_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(threshold_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&threshold_image->exception);
+      threshold_image=DestroyImage(threshold_image);
+      return((Image *) NULL);
+    }
+  /*
+    Local adaptive threshold.
+  */
+  status=MagickTrue;
+  progress=0;
+  GetPixelInfo(image,&zero);
+  number_pixels=(MagickRealType) width*height;
+  image_view=AcquireCacheView(image);
+  threshold_view=AcquireCacheView(threshold_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
+      height/2L,image->columns+width,height,exception);
+    q=GetCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      PixelInfo
+        mean,
+        pixel;
+
+      register const Quantum
+        *r;
+
+      register ssize_t
+        u;
+
+      ssize_t
+        v;
+
+      pixel=zero;
+      mean=zero;
+      r=p;
+      for (v=0; v < (ssize_t) height; v++)
+      {
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          pixel.red+=GetPixelAlpha(image,r+u*GetPixelChannels(image));
+          pixel.green+=GetPixelGreen(image,r+u*GetPixelChannels(image));
+          pixel.blue+=GetPixelBlue(image,r+u*GetPixelChannels(image));
+          if (image->colorspace == CMYKColorspace)
+            pixel.black+=GetPixelBlack(image,r+u*GetPixelChannels(image));
+          pixel.alpha+=GetPixelAlpha(image,r+u*GetPixelChannels(image));
+        }
+        r+=(image->columns+width)*GetPixelChannels(image);
+      }
+      mean.red=(MagickRealType) (pixel.red/number_pixels+offset);
+      mean.green=(MagickRealType) (pixel.green/number_pixels+offset);
+      mean.blue=(MagickRealType) (pixel.blue/number_pixels+offset);
+      mean.black=(MagickRealType) (pixel.black/number_pixels+offset);
+      mean.alpha=(MagickRealType) (pixel.alpha/number_pixels+offset);
+      SetPixelRed(threshold_image,(Quantum) (((MagickRealType)
+        GetPixelRed(threshold_image,q) <= mean.red) ? 0 : QuantumRange),q);
+      SetPixelGreen(threshold_image,(Quantum) (((MagickRealType)
+        GetPixelGreen(threshold_image,q) <= mean.green) ? 0 : QuantumRange),q);
+      SetPixelBlue(threshold_image,(Quantum) (((MagickRealType)
+        GetPixelBlue(threshold_image,q) <= mean.blue) ? 0 : QuantumRange),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(threshold_image,(Quantum) (((MagickRealType)
+          GetPixelBlack(threshold_image,q) <= mean.black) ? 0 : QuantumRange),
+          q);
+      SetPixelAlpha(threshold_image,(Quantum) (((MagickRealType)
+        GetPixelAlpha(threshold_image,q) <= mean.alpha) ? 0 : QuantumRange),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(threshold_image);
+    }
+    sync=SyncCacheViewAuthenticPixels(threshold_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_AdaptiveThresholdImage)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  threshold_view=DestroyCacheView(threshold_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    threshold_image=DestroyImage(threshold_image);
+  return(threshold_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     B i l e v e l I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BilevelImage() changes the value of individual pixels based on the
+%  intensity of each pixel channel.  The result is a high-contrast image.
+%
+%  More precisely each channel value of the image is 'thresholded' so that if
+%  it is equal to or less than the given value it is set to zero, while any
+%  value greater than that give is set to it maximum or QuantumRange.
+%
+%  This function is what is used to implement the "-threshold" operator for
+%  the command line API.
+%
+%  If the default channel setting is given the image is thresholded using just
+%  the gray 'intensity' of the image, rather than the individual channels.
+%
+%  The format of the BilevelImageChannel method is:
+%
+%      MagickBooleanType BilevelImage(Image *image,const double threshold)
+%      MagickBooleanType BilevelImageChannel(Image *image,
+%        const ChannelType channel,const double threshold)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+%    o threshold: define the threshold values.
+%
+%  Aside: You can get the same results as operator using LevelImageChannels()
+%  with the 'threshold' value for both the black_point and the white_point.
+%
+*/
+
+MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold)
+{
+  MagickBooleanType
+    status;
+
+  status=BilevelImageChannel(image,DefaultChannels,threshold);
+  return(status);
+}
+
+MagickExport MagickBooleanType BilevelImageChannel(Image *image,
+  const ChannelType channel,const double threshold)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  /*
+    Bilevel threshold image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    if (channel == DefaultChannels)
+      {
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          SetPixelRed(image,(Quantum) ((MagickRealType)
+            GetPixelIntensity(image,q) <= threshold ? 0 : QuantumRange),q);
+          SetPixelGreen(image,GetPixelRed(image,q),q);
+          SetPixelBlue(image,GetPixelRed(image,q),q);
+          q+=GetPixelChannels(image);
+        }
+      }
+    else
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        if ((channel & RedChannel) != 0)
+          SetPixelRed(image,(Quantum) ((MagickRealType)
+            GetPixelRed(image,q) <= threshold ? 0 : QuantumRange),q);
+        if ((channel & GreenChannel) != 0)
+          SetPixelGreen(image,(Quantum) ((MagickRealType)
+            GetPixelGreen(image,q) <= threshold ? 0 : QuantumRange),q);
+        if ((channel & BlueChannel) != 0)
+          SetPixelBlue(image,(Quantum) ((MagickRealType)
+            GetPixelBlue(image,q) <= threshold ? 0 : QuantumRange),q);
+        if (((channel & BlackChannel) != 0) &&
+            (image->colorspace == CMYKColorspace))
+          SetPixelBlack(image,(Quantum) ((MagickRealType)
+            GetPixelBlack(image,q) <= threshold ? 0 : QuantumRange),q);
+        if ((channel & AlphaChannel) != 0)
+          {
+            if (image->matte == MagickFalse)
+              SetPixelAlpha(image,(Quantum) ((MagickRealType)
+                GetPixelAlpha(image,q) <= threshold ? 0 : QuantumRange),q);
+            else
+              SetPixelAlpha(image,(Quantum) ((MagickRealType)
+                GetPixelAlpha(image,q) >= threshold ? OpaqueAlpha :
+                TransparentAlpha),q);
+          }
+        q+=GetPixelChannels(image);
+      }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_BilevelImageChannel)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     B l a c k T h r e s h o l d I m a g e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  BlackThresholdImage() is like ThresholdImage() but forces all pixels below
+%  the threshold into black while leaving all pixels at or above the threshold
+%  unchanged.
+%
+%  The format of the BlackThresholdImage method is:
+%
+%      MagickBooleanType BlackThresholdImage(Image *image,const char *threshold)
+%      MagickBooleanType BlackThresholdImageChannel(Image *image,
+%        const ChannelType channel,const char *threshold,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel or channels to be thresholded.
+%
+%    o threshold: Define the threshold value.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType BlackThresholdImage(Image *image,
+  const char *threshold)
+{
+  MagickBooleanType
+    status;
+
+  status=BlackThresholdImageChannel(image,DefaultChannels,threshold,
+    &image->exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType BlackThresholdImageChannel(Image *image,
+  const ChannelType channel,const char *thresholds,ExceptionInfo *exception)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  CacheView
+    *image_view;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    threshold;
+
+  MagickStatusType
+    flags;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (thresholds == (const char *) NULL)
+    return(MagickTrue);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  GetPixelInfo(image,&threshold);
+  flags=ParseGeometry(thresholds,&geometry_info);
+  threshold.red=geometry_info.rho;
+  threshold.green=geometry_info.sigma;
+  if ((flags & SigmaValue) == 0)
+    threshold.green=threshold.red;
+  threshold.blue=geometry_info.xi;
+  if ((flags & XiValue) == 0)
+    threshold.blue=threshold.red;
+  threshold.alpha=geometry_info.psi;
+  if ((flags & PsiValue) == 0)
+    threshold.alpha=threshold.red;
+  threshold.black=geometry_info.chi;
+  if ((flags & ChiValue) == 0)
+    threshold.black=threshold.red;
+  if ((flags & PercentValue) != 0)
+    {
+      threshold.red*=(QuantumRange/100.0);
+      threshold.green*=(QuantumRange/100.0);
+      threshold.blue*=(QuantumRange/100.0);
+      threshold.alpha*=(QuantumRange/100.0);
+      threshold.black*=(QuantumRange/100.0);
+    }
+  /*
+    Black threshold image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (channel != DefaultChannels)
+        {
+          if (GetPixelIntensity(image,q) < GetPixelInfoIntensity(&threshold))
+            {
+              SetPixelRed(image,0,q);
+              SetPixelGreen(image,0,q);
+              SetPixelBlue(image,0,q);
+              if (image->colorspace == CMYKColorspace)
+                SetPixelBlack(image,0,q);
+            }
+        }
+      else
+        {
+          if (((channel & RedChannel) != 0) &&
+              ((MagickRealType) GetPixelRed(image,q) < threshold.red))
+            SetPixelRed(image,0,q);
+          if (((channel & GreenChannel) != 0) &&
+              ((MagickRealType) GetPixelGreen(image,q) < threshold.green))
+            SetPixelGreen(image,0,q);
+          if (((channel & BlueChannel) != 0) &&
+              ((MagickRealType) GetPixelBlue(image,q) < threshold.blue))
+            SetPixelBlue(image,0,q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace) &&
+              ((MagickRealType) GetPixelBlack(image,q) < threshold.black))
+            SetPixelBlack(image,0,q);
+          if (((channel & OpacityChannel) != 0) &&
+              ((MagickRealType) GetPixelAlpha(image,q) < threshold.alpha))
+            SetPixelAlpha(image,0,q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_BlackThresholdImageChannel)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     C l a m p I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ClampImage() restricts the color range from 0 to the quantum depth.
+%
+%  The format of the ClampImageChannel method is:
+%
+%      MagickBooleanType ClampImage(Image *image)
+%      MagickBooleanType ClampImageChannel(Image *image,
+%        const ChannelType channel)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel type.
+%
+*/
+
+static inline Quantum ClampToUnsignedQuantum(const Quantum quantum)
+{
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+  if (quantum <= 0)
+    return(0);
+  if (quantum >= QuantumRange)
+    return(QuantumRange);
+  return(quantum);
+#else
+  return(quantum);
+#endif
+}
+
+MagickExport MagickBooleanType ClampImage(Image *image)
+{
+  MagickBooleanType
+    status;
+
+  status=ClampImageChannel(image,DefaultChannels);
+  return(status);
+}
+
+MagickExport MagickBooleanType ClampImageChannel(Image *image,
+  const ChannelType channel)
+{
+#define ClampImageTag  "Clamp/Image"
+
+  CacheView
+    *image_view;
+
+  ExceptionInfo
+    *exception;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (image->storage_class == PseudoClass)
+    {
+      register ssize_t
+        i;
+
+      register PixelPacket
+        *restrict q;
+
+      q=image->colormap;
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        q->red=ClampToUnsignedQuantum(q->red);
+        q->green=ClampToUnsignedQuantum(q->green);
+        q->blue=ClampToUnsignedQuantum(q->blue);
+        q->alpha=ClampToUnsignedQuantum(q->alpha);
+        q++;
+      }
+      return(SyncImage(image));
+    }
+  /*
+    Clamp image.
+  */
+  status=MagickTrue;
+  progress=0;
+  exception=(&image->exception);
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,ClampToUnsignedQuantum(GetPixelRed(image,q)),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,ClampToUnsignedQuantum(GetPixelGreen(image,q)),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,ClampToUnsignedQuantum(GetPixelBlue(image,q)),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,ClampToUnsignedQuantum(GetPixelBlack(image,q)),q);
+      if ((channel & OpacityChannel) != 0)
+        SetPixelAlpha(image,ClampToUnsignedQuantum(GetPixelAlpha(image,q)),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ClampImageChannel)
+#endif
+        proceed=SetImageProgress(image,ClampImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  D e s t r o y T h r e s h o l d M a p                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyThresholdMap() de-allocate the given ThresholdMap
+%
+%  The format of the ListThresholdMaps method is:
+%
+%      ThresholdMap *DestroyThresholdMap(Threshold *map)
+%
+%  A description of each parameter follows.
+%
+%    o map:    Pointer to the Threshold map to destroy
+%
+*/
+MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map)
+{
+  assert(map != (ThresholdMap *) NULL);
+  if (map->map_id != (char *) NULL)
+    map->map_id=DestroyString(map->map_id);
+  if (map->description != (char *) NULL)
+    map->description=DestroyString(map->description);
+  if (map->levels != (ssize_t *) NULL)
+    map->levels=(ssize_t *) RelinquishMagickMemory(map->levels);
+  map=(ThresholdMap *) RelinquishMagickMemory(map);
+  return(map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  G e t T h r e s h o l d M a p F i l e                                      %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetThresholdMapFile() look for a given threshold map name or alias in the
+%  given XML file data, and return the allocated the map when found.
+%
+%  The format of the ListThresholdMaps method is:
+%
+%      ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
+%         const char *map_id,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o xml:  The threshold map list in XML format.
+%
+%    o filename:  The threshold map XML filename.
+%
+%    o map_id:  ID of the map to look for in XML list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ThresholdMap *GetThresholdMapFile(const char *xml,
+  const char *filename,const char *map_id,ExceptionInfo *exception)
+{
+  const char
+    *attr,
+    *content;
+
+  double
+    value;
+
+  ThresholdMap
+     *map;
+
+  XMLTreeInfo
+     *description,
+     *levels,
+     *threshold,
+     *thresholds;
+
+  map = (ThresholdMap *)NULL;
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading threshold map file \"%s\" ...",filename);
+  thresholds=NewXMLTree(xml,exception);
+  if ( thresholds == (XMLTreeInfo *)NULL )
+    return(map);
+
+  for( threshold = GetXMLTreeChild(thresholds,"threshold");
+       threshold != (XMLTreeInfo *)NULL;
+       threshold = GetNextXMLTreeTag(threshold) ) {
+    attr = GetXMLTreeAttribute(threshold, "map");
+    if ( (attr != (char *)NULL) && (LocaleCompare(map_id,attr) == 0) )
+      break;
+    attr = GetXMLTreeAttribute(threshold, "alias");
+    if ( (attr != (char *)NULL) && (LocaleCompare(map_id,attr) == 0) )
+      break;
+  }
+  if ( threshold == (XMLTreeInfo *)NULL ) {
+    return(map);
+  }
+  description = GetXMLTreeChild(threshold,"description");
+  if ( description == (XMLTreeInfo *)NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlMissingElement", "<description>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    return(map);
+  }
+  levels = GetXMLTreeChild(threshold,"levels");
+  if ( levels == (XMLTreeInfo *)NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlMissingElement", "<levels>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    return(map);
+  }
+
+  /* The map has been found -- Allocate a Threshold Map to return */
+  map = (ThresholdMap *)AcquireMagickMemory(sizeof(ThresholdMap));
+  if ( map == (ThresholdMap *)NULL )
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
+  map->map_id = (char *)NULL;
+  map->description = (char *)NULL;
+  map->levels = (ssize_t *) NULL;
+
+  /* Assign Basic Attributes */
+  attr = GetXMLTreeAttribute(threshold, "map");
+  if ( attr != (char *)NULL )
+    map->map_id = ConstantString(attr);
+
+  content = GetXMLTreeContent(description);
+  if ( content != (char *)NULL )
+    map->description = ConstantString(content);
+
+  attr = GetXMLTreeAttribute(levels, "width");
+  if ( attr == (char *)NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlMissingAttribute", "<levels width>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+  map->width = StringToUnsignedLong(attr);
+  if ( map->width == 0 ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+     "XmlInvalidAttribute", "<levels width>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+
+  attr = GetXMLTreeAttribute(levels, "height");
+  if ( attr == (char *)NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlMissingAttribute", "<levels height>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+  map->height = StringToUnsignedLong(attr);
+  if ( map->height == 0 ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlInvalidAttribute", "<levels height>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+
+  attr = GetXMLTreeAttribute(levels, "divisor");
+  if ( attr == (char *)NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlMissingAttribute", "<levels divisor>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+  map->divisor = (ssize_t) StringToLong(attr);
+  if ( map->divisor < 2 ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlInvalidAttribute", "<levels divisor>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+
+  /* Allocate theshold levels array */
+  content = GetXMLTreeContent(levels);
+  if ( content == (char *)NULL ) {
+    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+      "XmlMissingContent", "<levels>, map \"%s\"", map_id);
+    thresholds = DestroyXMLTree(thresholds);
+    map = DestroyThresholdMap(map);
+    return(map);
+  }
+  map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height*
+    sizeof(*map->levels));
+  if ( map->levels == (ssize_t *)NULL )
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
+  { /* parse levels into integer array */
+    ssize_t i;
+    char *p;
+    for( i=0; i< (ssize_t) (map->width*map->height); i++) {
+      map->levels[i] = (ssize_t)strtol(content, &p, 10);
+      if ( p == content ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "XmlInvalidContent", "<level> too few values, map \"%s\"", map_id);
+        thresholds = DestroyXMLTree(thresholds);
+        map = DestroyThresholdMap(map);
+        return(map);
+      }
+      if ( map->levels[i] < 0 || map->levels[i] > map->divisor ) {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"",
+          (double) map->levels[i],map_id);
+        thresholds = DestroyXMLTree(thresholds);
+        map = DestroyThresholdMap(map);
+        return(map);
+      }
+      content = p;
+    }
+    value=(double) strtol(content,&p,10);
+    (void) value;
+    if (p != content)
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "XmlInvalidContent", "<level> too many values, map \"%s\"", map_id);
+       thresholds=DestroyXMLTree(thresholds);
+       map=DestroyThresholdMap(map);
+       return(map);
+     }
+  }
+
+  thresholds = DestroyXMLTree(thresholds);
+  return(map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t T h r e s h o l d M a p                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetThresholdMap() load and search one or more threshold map files for the
+%  a map matching the given name or aliase.
+%
+%  The format of the GetThresholdMap method is:
+%
+%      ThresholdMap *GetThresholdMap(const char *map_id,
+%         ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o map_id:  ID of the map to look for.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport ThresholdMap *GetThresholdMap(const char *map_id,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  ThresholdMap
+    *map;
+
+  map=(ThresholdMap *)NULL;
+  options=GetConfigureOptions(ThresholdsFilename,exception);
+  while (( option=(const StringInfo *) GetNextValueInLinkedList(options) )
+          != (const StringInfo *) NULL && map == (ThresholdMap *)NULL )
+    map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),map_id,exception);
+  options=DestroyConfigureOptions(options);
+  return(map);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  L i s t T h r e s h o l d M a p F i l e                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListThresholdMapFile() lists the threshold maps and their descriptions
+%  in the given XML file data.
+%
+%  The format of the ListThresholdMaps method is:
+%
+%      MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
+%         const char *filename,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to the output FILE.
+%
+%    o xml:  The threshold map list in XML format.
+%
+%    o filename:  The threshold map XML filename.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
+  const char *filename,ExceptionInfo *exception)
+{
+  XMLTreeInfo *thresholds,*threshold,*description;
+  const char *map,*alias,*content;
+
+  assert( xml != (char *)NULL );
+  assert( file != (FILE *)NULL );
+
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading threshold map file \"%s\" ...",filename);
+  thresholds=NewXMLTree(xml,exception);
+  if ( thresholds == (XMLTreeInfo *)NULL )
+    return(MagickFalse);
+
+  (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description");
+  (void) FormatLocaleFile(file,
+    "----------------------------------------------------\n");
+
+  for( threshold = GetXMLTreeChild(thresholds,"threshold");
+       threshold != (XMLTreeInfo *)NULL;
+       threshold = GetNextXMLTreeTag(threshold) )
+  {
+    map = GetXMLTreeAttribute(threshold, "map");
+    if (map == (char *) NULL) {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "XmlMissingAttribute", "<map>");
+      thresholds=DestroyXMLTree(thresholds);
+      return(MagickFalse);
+    }
+    alias = GetXMLTreeAttribute(threshold, "alias");
+    /* alias is optional, no if test needed */
+    description=GetXMLTreeChild(threshold,"description");
+    if ( description == (XMLTreeInfo *)NULL ) {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "XmlMissingElement", "<description>, map \"%s\"", map);
+      thresholds=DestroyXMLTree(thresholds);
+      return(MagickFalse);
+    }
+    content=GetXMLTreeContent(description);
+    if ( content == (char *)NULL ) {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "XmlMissingContent", "<description>, map \"%s\"", map);
+      thresholds=DestroyXMLTree(thresholds);
+      return(MagickFalse);
+    }
+    (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "",
+      content);
+  }
+  thresholds=DestroyXMLTree(thresholds);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t T h r e s h o l d M a p s                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListThresholdMaps() lists the threshold maps and their descriptions
+%  as defined by "threshold.xml" to a file.
+%
+%  The format of the ListThresholdMaps method is:
+%
+%      MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to the output FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListThresholdMaps(FILE *file,
+  ExceptionInfo *exception)
+{
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  status=MagickFalse;
+  if ( file == (FILE *)NULL )
+    file = stdout;
+  options=GetConfigureOptions(ThresholdsFilename,exception);
+
+  (void) FormatLocaleFile(file,
+    "\n   Threshold Maps for Ordered Dither Operations\n");
+  while ( ( option=(const StringInfo *) GetNextValueInLinkedList(options) )
+          != (const StringInfo *) NULL)
+  {
+    (void) FormatLocaleFile(file,"\nPATH: %s\n\n",GetStringInfoPath(option));
+    status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),exception);
+  }
+  options=DestroyConfigureOptions(options);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     O r d e r e d P o s t e r i z e I m a g e                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OrderedPosterizeImage() will perform a ordered dither based on a number
+%  of pre-defined dithering threshold maps, but over multiple intensity
+%  levels, which can be different for different channels, according to the
+%  input argument.
+%
+%  The format of the OrderedPosterizeImage method is:
+%
+%      MagickBooleanType OrderedPosterizeImage(Image *image,
+%        const char *threshold_map,ExceptionInfo *exception)
+%      MagickBooleanType OrderedPosterizeImageChannel(Image *image,
+%        const ChannelType channel,const char *threshold_map,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel or channels to be thresholded.
+%
+%    o threshold_map: A string containing the name of the threshold dither
+%      map to use, followed by zero or more numbers representing the number
+%      of color levels tho dither between.
+%
+%      Any level number less than 2 will be equivalent to 2, and means only
+%      binary dithering will be applied to each color channel.
+%
+%      No numbers also means a 2 level (bitmap) dither will be applied to all
+%      channels, while a single number is the number of levels applied to each
+%      channel in sequence.  More numbers will be applied in turn to each of
+%      the color channels.
+%
+%      For example: "o3x3,6" will generate a 6 level posterization of the
+%      image with a ordered 3x3 diffused pixel dither being applied between
+%      each level. While checker,8,8,4 will produce a 332 colormaped image
+%      with only a single checkerboard hash pattern (50% grey) between each
+%      color level, to basically double the number of color levels with
+%      a bare minimim of dithering.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType OrderedPosterizeImage(Image *image,
+  const char *threshold_map,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=OrderedPosterizeImageChannel(image,DefaultChannels,threshold_map,
+    exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType OrderedPosterizeImageChannel(Image *image,
+  const ChannelType channel,const char *threshold_map,ExceptionInfo *exception)
+{
+#define DitherImageTag  "Dither/Image"
+
+  CacheView
+    *image_view;
+
+  LongPixelPacket
+    levels;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  ThresholdMap
+    *map;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (threshold_map == (const char *) NULL)
+    return(MagickTrue);
+  {
+    char
+      token[MaxTextExtent];
+
+    register const char
+      *p;
+
+    p=(char *)threshold_map;
+    while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
+                    (*p != '\0'))
+      p++;
+    threshold_map=p;
+    while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
+                    (*p != '\0')) {
+      if ((p-threshold_map) >= (MaxTextExtent-1))
+        break;
+      token[p-threshold_map] = *p;
+      p++;
+    }
+    token[p-threshold_map] = '\0';
+    map = GetThresholdMap(token, exception);
+    if ( map == (ThresholdMap *)NULL ) {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+        "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
+      return(MagickFalse);
+    }
+  }
+  /* Set channel levels from extra comma separated arguments
+     Default to 2, the single value given, or individual channel values
+  */
+#if 1
+  { /* parse directly as a comma separated list of integers */
+    char *p;
+
+    p = strchr((char *) threshold_map,',');
+    if ( p != (char *)NULL && isdigit((int) ((unsigned char) *(++p))) )
+      levels.black = (unsigned int) strtoul(p, &p, 10);
+    else
+      levels.black = 2;
+
+    levels.red     = ((channel & RedChannel  )   != 0) ? levels.black : 0;
+    levels.green   = ((channel & GreenChannel)   != 0) ? levels.black : 0;
+    levels.blue    = ((channel & BlueChannel)    != 0) ? levels.black : 0;
+    levels.black   = ((channel & BlackChannel)   != 0 &&
+      (image->colorspace == CMYKColorspace)) ? levels.black : 0;
+    levels.alpha = ((channel & OpacityChannel) != 0) ? levels.black : 0;
+
+    /* if more than a single number, each channel has a separate value */
+    if ( p != (char *) NULL && *p == ',' ) {
+      p=strchr((char *) threshold_map,',');
+      p++;
+      if ((channel & RedChannel) != 0)
+        levels.red = (unsigned int) strtoul(p, &p, 10),   (void)(*p == ',' && p++);
+      if ((channel & GreenChannel) != 0)
+        levels.green = (unsigned int) strtoul(p, &p, 10), (void)(*p == ',' && p++);
+      if ((channel & BlueChannel) != 0)
+        levels.blue = (unsigned int) strtoul(p, &p, 10),  (void)(*p == ',' && p++);
+      if ((channel & BlackChannel) != 0 &&
+          (image->colorspace == CMYKColorspace))
+        levels.black=(unsigned int) strtoul(p, &p, 10), (void)(*p == ',' && p++);
+      if ((channel & OpacityChannel) != 0)
+        levels.alpha = (unsigned int) strtoul(p, &p, 10), (void)(*p == ',' && p++);
+    }
+  }
+#else
+  /* Parse level values as a geometry */
+  /* This difficult!
+   * How to map   GeometryInfo structure elements into
+   * LongPixelPacket structure elements, but according to channel?
+   * Note the channels list may skip elements!!!!
+   * EG  -channel BA  -ordered-dither map,2,3
+   * will need to map  g.rho -> l.blue, and g.sigma -> l.alpha
+   * A simpler way is needed, probably converting geometry to a temporary
+   * array, then using channel to advance the index into ssize_t pixel packet.
+   */
+#endif
+
+#if 0
+printf("DEBUG levels  r=%u g=%u b=%u a=%u i=%u\n",
+     levels.red, levels.green, levels.blue, levels.alpha, levels.index);
+#endif
+
+  { /* Do the posterized ordered dithering of the image */
+    ssize_t
+      d;
+
+    /* d = number of psuedo-level divisions added between color levels */
+    d = map->divisor-1;
+
+    /* reduce levels to levels - 1 */
+    levels.red     = levels.red     ? levels.red-1     : 0;
+    levels.green   = levels.green   ? levels.green-1   : 0;
+    levels.blue    = levels.blue    ? levels.blue-1    : 0;
+    levels.black   = levels.black   ? levels.black-1   : 0;
+    levels.alpha = levels.alpha ? levels.alpha-1 : 0;
+
+    if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+      {
+        InheritException(exception,&image->exception);
+        return(MagickFalse);
+      }
+    status=MagickTrue;
+    progress=0;
+    image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+    for (y=0; y < (ssize_t) image->rows; y++)
+    {
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      if (status == MagickFalse)
+        continue;
+      q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+      if (q == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          continue;
+        }
+      for (x=0; x < (ssize_t) image->columns; x++)
+      {
+        register ssize_t
+          threshold,
+          t,
+          l;
+
+        /*
+          Figure out the dither threshold for this pixel
+          This must be a integer from 1 to map->divisor-1
+        */
+        threshold = map->levels[(x%map->width) +map->width*(y%map->height)];
+
+        /* Dither each channel in the image as appropriate
+          Notes on the integer Math...
+              total number of divisions = (levels-1)*(divisor-1)+1)
+              t1 = this colors psuedo_level =
+                      q->red * total_divisions / (QuantumRange+1)
+              l = posterization level       0..levels
+              t = dither threshold level    0..divisor-1  NB: 0 only on last
+              Each color_level is of size   QuantumRange / (levels-1)
+              NB: All input levels and divisor are already had 1 subtracted
+              Opacity is inverted so 'off' represents transparent.
+        */
+        if (levels.red != 0) {
+          t = (ssize_t) (QuantumScale*GetPixelRed(image,q)*(levels.red*d+1));
+          l = t/d;  t = t-l*d;
+          SetPixelRed(image,RoundToQuantum((MagickRealType)
+            ((l+(t >= threshold))*(MagickRealType) QuantumRange/levels.red)),q);
+        }
+        if (levels.green != 0) {
+          t = (ssize_t) (QuantumScale*GetPixelGreen(image,q)*
+            (levels.green*d+1));
+          l = t/d;  t = t-l*d;
+          SetPixelGreen(image,RoundToQuantum((MagickRealType)
+            ((l+(t >= threshold))*(MagickRealType) QuantumRange/levels.green)),q);
+        }
+        if (levels.blue != 0) {
+          t = (ssize_t) (QuantumScale*GetPixelBlue(image,q)*
+            (levels.blue*d+1));
+          l = t/d;  t = t-l*d;
+          SetPixelBlue(image,RoundToQuantum((MagickRealType)
+            ((l+(t >= threshold))*(MagickRealType) QuantumRange/levels.blue)),q);
+        }
+        if (levels.alpha != 0) {
+          t = (ssize_t) ((1.0-QuantumScale*GetPixelAlpha(image,q))*
+            (levels.alpha*d+1));
+          l = t/d;  t = t-l*d;
+          SetPixelAlpha(image,RoundToQuantum((MagickRealType)
+            ((1.0-l-(t >= threshold))*(MagickRealType) QuantumRange/
+            levels.alpha)),q);
+        }
+        if (levels.black != 0) {
+          t = (ssize_t) (QuantumScale*GetPixelBlack(image,q)*
+            (levels.black*d+1));
+          l = t/d;  t = t-l*d;
+          SetPixelBlack(image,RoundToQuantum((MagickRealType)
+            ((l+(t>=threshold))*(MagickRealType) QuantumRange/levels.black)),q);
+        }
+        q+=GetPixelChannels(image);
+      }
+      if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+        status=MagickFalse;
+      if (image->progress_monitor != (MagickProgressMonitor) NULL)
+        {
+          MagickBooleanType
+            proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_OrderedPosterizeImageChannel)
+#endif
+          proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows);
+          if (proceed == MagickFalse)
+            status=MagickFalse;
+        }
+    }
+    image_view=DestroyCacheView(image_view);
+  }
+  map=DestroyThresholdMap(map);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     R a n d o m T h r e s h o l d I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RandomThresholdImage() changes the value of individual pixels based on the
+%  intensity of each pixel compared to a random threshold.  The result is a
+%  low-contrast, two color image.
+%
+%  The format of the RandomThresholdImage method is:
+%
+%      MagickBooleanType RandomThresholdImageChannel(Image *image,
+%        const char *thresholds,ExceptionInfo *exception)
+%      MagickBooleanType RandomThresholdImageChannel(Image *image,
+%        const ChannelType channel,const char *thresholds,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel or channels to be thresholded.
+%
+%    o thresholds: a geometry string containing low,high thresholds.  If the
+%      string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4
+%      is performed instead.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+MagickExport MagickBooleanType RandomThresholdImage(Image *image,
+  const char *thresholds,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  status=RandomThresholdImageChannel(image,DefaultChannels,thresholds,
+    exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType RandomThresholdImageChannel(Image *image,
+  const ChannelType channel,const char *thresholds,ExceptionInfo *exception)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  CacheView
+    *image_view;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickStatusType
+    flags;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  PixelInfo
+    threshold;
+
+  MagickRealType
+    min_threshold,
+    max_threshold;
+
+  RandomInfo
+    **restrict random_info;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  if (thresholds == (const char *) NULL)
+    return(MagickTrue);
+  GetPixelInfo(image,&threshold);
+  min_threshold=0.0;
+  max_threshold=(MagickRealType) QuantumRange;
+  flags=ParseGeometry(thresholds,&geometry_info);
+  min_threshold=geometry_info.rho;
+  max_threshold=geometry_info.sigma;
+  if ((flags & SigmaValue) == 0)
+    max_threshold=min_threshold;
+  if (strchr(thresholds,'%') != (char *) NULL)
+    {
+      max_threshold*=(MagickRealType) (0.01*QuantumRange);
+      min_threshold*=(MagickRealType) (0.01*QuantumRange);
+    }
+  else
+    if (((max_threshold == min_threshold) || (max_threshold == 1)) &&
+        (min_threshold <= 8))
+      {
+        /*
+          Backward Compatibility -- ordered-dither -- IM v 6.2.9-6.
+        */
+        status=OrderedPosterizeImageChannel(image,channel,thresholds,exception);
+        return(status);
+      }
+  /*
+    Random threshold image.
+  */
+  status=MagickTrue;
+  progress=0;
+  if (channel == CompositeChannels)
+    {
+      if (AcquireImageColormap(image,2) == MagickFalse)
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename);
+      random_info=AcquireRandomInfoThreadSet();
+      image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        const int
+          id = GetOpenMPThreadId();
+
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          MagickRealType
+            intensity;
+
+          Quantum
+            index;
+
+          intensity=(MagickRealType) GetPixelIntensity(image,q);
+          if (intensity < min_threshold)
+            threshold.black=min_threshold;
+          else
+            if (intensity > max_threshold)
+              threshold.black=max_threshold;
+            else
+              threshold.black=(MagickRealType)(QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+          index=(Quantum) (intensity <= threshold.black ? 0 : 1);
+          SetPixelIndex(image,index,q);
+          SetPixelPacket(image,image->colormap+(ssize_t) index,q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+        if (image->progress_monitor != (MagickProgressMonitor) NULL)
+          {
+            MagickBooleanType
+              proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_RandomThresholdImageChannel)
+#endif
+            proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+              image->rows);
+            if (proceed == MagickFalse)
+              status=MagickFalse;
+          }
+      }
+      image_view=DestroyCacheView(image_view);
+      random_info=DestroyRandomInfoThreadSet(random_info);
+      return(status);
+    }
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&image->exception);
+      return(MagickFalse);
+    }
+  random_info=AcquireRandomInfoThreadSet();
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const int
+      id = GetOpenMPThreadId();
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((channel & RedChannel) != 0)
+        {
+          if ((MagickRealType) GetPixelRed(image,q) < min_threshold)
+            threshold.red=min_threshold;
+          else
+            if ((MagickRealType) GetPixelRed(image,q) > max_threshold)
+              threshold.red=max_threshold;
+            else
+              threshold.red=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & GreenChannel) != 0)
+        {
+          if ((MagickRealType) GetPixelGreen(image,q) < min_threshold)
+            threshold.green=min_threshold;
+          else
+            if ((MagickRealType) GetPixelGreen(image,q) > max_threshold)
+              threshold.green=max_threshold;
+            else
+              threshold.green=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & BlueChannel) != 0)
+        {
+          if ((MagickRealType) GetPixelBlue(image,q) < min_threshold)
+            threshold.blue=min_threshold;
+          else
+            if ((MagickRealType) GetPixelBlue(image,q) > max_threshold)
+              threshold.blue=max_threshold;
+            else
+              threshold.blue=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        {
+          if ((MagickRealType) GetPixelBlack(image,q) < min_threshold)
+            threshold.black=min_threshold;
+          else
+            if ((MagickRealType) GetPixelBlack(image,q) > max_threshold)
+              threshold.black=max_threshold;
+            else
+              threshold.black=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & OpacityChannel) != 0)
+        {
+          if ((MagickRealType) GetPixelAlpha(image,q) < min_threshold)
+            threshold.alpha=min_threshold;
+          else
+            if ((MagickRealType) GetPixelAlpha(image,q) > max_threshold)
+              threshold.alpha=max_threshold;
+            else
+              threshold.alpha=(MagickRealType) (QuantumRange*
+                GetPseudoRandomValue(random_info[id]));
+        }
+      if ((channel & RedChannel) != 0)
+        SetPixelRed(image,(Quantum) ((MagickRealType)
+          GetPixelRed(image,q) <= threshold.red ? 0 : QuantumRange),q);
+      if ((channel & GreenChannel) != 0)
+        SetPixelGreen(image,(Quantum) ((MagickRealType)
+          GetPixelGreen(image,q) <= threshold.green ? 0 : QuantumRange),q);
+      if ((channel & BlueChannel) != 0)
+        SetPixelBlue(image,(Quantum) ((MagickRealType)
+          GetPixelBlue(image,q) <= threshold.blue ? 0 : QuantumRange),q);
+      if (((channel & BlackChannel) != 0) &&
+          (image->colorspace == CMYKColorspace))
+        SetPixelBlack(image,(Quantum) ((MagickRealType)
+          GetPixelBlack(image,q) <= threshold.black ? 0 : QuantumRange),q);
+      if ((channel & OpacityChannel) != 0)
+        SetPixelAlpha(image,(Quantum) ((MagickRealType)
+          GetPixelAlpha(image,q) <= threshold.alpha ? 0 : QuantumRange),q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_RandomThresholdImageChannel)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  random_info=DestroyRandomInfoThreadSet(random_info);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%     W h i t e T h r e s h o l d I m a g e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
+%  the threshold into white while leaving all pixels at or below the threshold
+%  unchanged.
+%
+%  The format of the WhiteThresholdImage method is:
+%
+%      MagickBooleanType WhiteThresholdImage(Image *image,const char *threshold)
+%      MagickBooleanType WhiteThresholdImageChannel(Image *image,
+%        const ChannelType channel,const char *threshold,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel: the channel or channels to be thresholded.
+%
+%    o threshold: Define the threshold value.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType WhiteThresholdImage(Image *image,
+  const char *threshold)
+{
+  MagickBooleanType
+    status;
+
+  status=WhiteThresholdImageChannel(image,DefaultChannels,threshold,
+    &image->exception);
+  return(status);
+}
+
+MagickExport MagickBooleanType WhiteThresholdImageChannel(Image *image,
+  const ChannelType channel,const char *thresholds,ExceptionInfo *exception)
+{
+#define ThresholdImageTag  "Threshold/Image"
+
+  CacheView
+    *image_view;
+
+  GeometryInfo
+    geometry_info;
+
+  MagickBooleanType
+    status;
+
+  PixelInfo
+    threshold;
+
+  MagickOffsetType
+    progress;
+
+  MagickStatusType
+    flags;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (thresholds == (const char *) NULL)
+    return(MagickTrue);
+  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  flags=ParseGeometry(thresholds,&geometry_info);
+  GetPixelInfo(image,&threshold);
+  threshold.red=geometry_info.rho;
+  threshold.green=geometry_info.sigma;
+  if ((flags & SigmaValue) == 0)
+    threshold.green=threshold.red;
+  threshold.blue=geometry_info.xi;
+  if ((flags & XiValue) == 0)
+    threshold.blue=threshold.red;
+  threshold.alpha=geometry_info.psi;
+  if ((flags & PsiValue) == 0)
+    threshold.alpha=threshold.red;
+  threshold.black=geometry_info.chi;
+  if ((flags & ChiValue) == 0)
+    threshold.black=threshold.red;
+  if ((flags & PercentValue) != 0)
+    {
+      threshold.red*=(QuantumRange/100.0);
+      threshold.green*=(QuantumRange/100.0);
+      threshold.blue*=(QuantumRange/100.0);
+      threshold.alpha*=(QuantumRange/100.0);
+      threshold.black*=(QuantumRange/100.0);
+    }
+  /*
+    White threshold image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (channel != DefaultChannels)
+        {
+          if (GetPixelIntensity(image,q) > GetPixelInfoIntensity(&threshold))
+            {
+              SetPixelRed(image,QuantumRange,q);
+              SetPixelGreen(image,QuantumRange,q);
+              SetPixelBlue(image,QuantumRange,q);
+              if (image->colorspace == CMYKColorspace)
+                SetPixelBlack(image,QuantumRange,q);
+            }
+        }
+      else
+        {
+          if (((channel & RedChannel) != 0) &&
+              ((MagickRealType) GetPixelRed(image,q) > threshold.red))
+            SetPixelRed(image,QuantumRange,q);
+          if (((channel & GreenChannel) != 0) &&
+              ((MagickRealType) GetPixelGreen(image,q) > threshold.green))
+            SetPixelGreen(image,QuantumRange,q);
+          if (((channel & BlueChannel) != 0) &&
+              ((MagickRealType) GetPixelBlue(image,q) > threshold.blue))
+            SetPixelBlue(image,QuantumRange,q);
+          if (((channel & BlackChannel) != 0) &&
+              (image->colorspace == CMYKColorspace) &&
+              ((MagickRealType) GetPixelBlack(image,q)) > threshold.black)
+            SetPixelBlack(image,QuantumRange,q);
+          if (((channel & OpacityChannel) != 0) &&
+              ((MagickRealType) GetPixelAlpha(image,q) > threshold.alpha))
+            SetPixelAlpha(image,QuantumRange,q);
+        }
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_WhiteThresholdImageChannel)
+#endif
+        proceed=SetImageProgress(image,ThresholdImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
diff --git a/MagickCore/threshold.h b/MagickCore/threshold.h
new file mode 100644
index 0000000..1315248
--- /dev/null
+++ b/MagickCore/threshold.h
@@ -0,0 +1,59 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image threshold methods.
+*/
+#ifndef _MAGICKCORE_THRESHOLD_H
+#define _MAGICKCORE_THRESHOLD_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _ThresholdMap
+  ThresholdMap;
+
+extern MagickExport Image
+  *AdaptiveThresholdImage(const Image *,const size_t,const size_t,const ssize_t,
+    ExceptionInfo *);
+
+extern MagickExport ThresholdMap
+  *DestroyThresholdMap(ThresholdMap *),
+  *GetThresholdMap(const char *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  BilevelImage(Image *,const double),
+  BilevelImageChannel(Image *,const ChannelType,const double),
+  BlackThresholdImage(Image *,const char *),
+  BlackThresholdImageChannel(Image *,const ChannelType,const char *,
+    ExceptionInfo *),
+  ClampImage(Image *),
+  ClampImageChannel(Image *,const ChannelType),
+  ListThresholdMaps(FILE *,ExceptionInfo *),
+  OrderedPosterizeImage(Image *,const char *,ExceptionInfo *),
+  OrderedPosterizeImageChannel(Image *,const ChannelType,const char *,
+    ExceptionInfo *),
+  RandomThresholdImage(Image *,const char *,ExceptionInfo *),
+  RandomThresholdImageChannel(Image *,const ChannelType,const char *,
+    ExceptionInfo *),
+  WhiteThresholdImage(Image *,const char *),
+  WhiteThresholdImageChannel(Image *,const ChannelType,const char *,
+    ExceptionInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/timer.c b/MagickCore/timer.c
new file mode 100644
index 0000000..c42f23b
--- /dev/null
+++ b/MagickCore/timer.c
@@ -0,0 +1,460 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                    TTTTT  IIIII  M   M  EEEEE  RRRR                         %
+%                      T      I    MM MM  E      R   R                        %
+%                      T      I    M M M  EEE    RRRR                         %
+%                      T      I    M   M  E      R R                          %
+%                      T    IIIII  M   M  EEEEE  R  R                         %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Timing Methods                           %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                              January 1993                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Contributed by Bill Radcliffe and Bob Friesenhahn.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/timer.h"
+
+/*
+  Define declarations.
+*/
+#if defined(macintosh)
+#define CLK_TCK  CLOCKS_PER_SEC
+#endif
+#if !defined(CLK_TCK)
+#define CLK_TCK  sysconf(_SC_CLK_TCK)
+#endif
+
+/*
+  Forward declarations.
+*/
+static double
+  UserTime(void);
+
+static void
+  StopTimer(TimerInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e T i m e r I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireTimerInfo() initializes the TimerInfo structure.  It effectively
+%  creates a stopwatch and starts it.
+%
+%  The format of the AcquireTimerInfo method is:
+%
+%      TimerInfo *AcquireTimerInfo(void)
+%
+*/
+MagickExport TimerInfo *AcquireTimerInfo(void)
+{
+  TimerInfo
+    *timer_info;
+
+  timer_info=(TimerInfo *) AcquireMagickMemory(sizeof(*timer_info));
+  if (timer_info == (TimerInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  (void) ResetMagickMemory(timer_info,0,sizeof(*timer_info));
+  timer_info->signature=MagickSignature;
+  GetTimerInfo(timer_info);
+  return(timer_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n t i n u e T i m e r                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ContinueTimer() resumes a stopped stopwatch. The stopwatch continues
+%  counting from the last StartTimer() onwards.
+%
+%  The format of the ContinueTimer method is:
+%
+%      MagickBooleanType ContinueTimer(TimerInfo *time_info)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Time statistics structure.
+%
+*/
+MagickExport MagickBooleanType ContinueTimer(TimerInfo *time_info)
+{
+  assert(time_info != (TimerInfo *) NULL);
+  assert(time_info->signature == MagickSignature);
+  if (time_info->state == UndefinedTimerState)
+    return(MagickFalse);
+  if (time_info->state == StoppedTimerState)
+    {
+      time_info->user.total-=time_info->user.stop-time_info->user.start;
+      time_info->elapsed.total-=time_info->elapsed.stop-
+        time_info->elapsed.start;
+    }
+  time_info->state=RunningTimerState;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y T i m e r I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyTimerInfo() zeros memory associated with the TimerInfo structure.
+%
+%  The format of the DestroyTimerInfo method is:
+%
+%      TimerInfo *DestroyTimerInfo(TimerInfo *timer_info)
+%
+%  A description of each parameter follows:
+%
+%    o timer_info: The cipher context.
+%
+*/
+MagickExport TimerInfo *DestroyTimerInfo(TimerInfo *timer_info)
+{
+  assert(timer_info != (TimerInfo *) NULL);
+  assert(timer_info->signature == MagickSignature);
+  timer_info->signature=(~MagickSignature);
+  timer_info=(TimerInfo *) RelinquishMagickMemory(timer_info);
+  return(timer_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   E l a p s e d T i m e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ElapsedTime() returns the elapsed time (in seconds) since the last call to
+%  StartTimer().
+%
+%  The format of the ElapsedTime method is:
+%
+%      double ElapsedTime()
+%
+*/
+static double ElapsedTime(void)
+{
+#if defined(MAGICKCORE_HAVE_TIMES)
+  struct tms
+    timer;
+
+  return((double) times(&timer)/CLK_TCK);
+#else
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  return(NTElapsedTime());
+#else
+  return((double) clock()/CLK_TCK);
+#endif
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t E l a p s e d T i m e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetElapsedTime() returns the elapsed time (in seconds) passed between the
+%  start and stop events. If the stopwatch is still running, it is stopped
+%  first.
+%
+%  The format of the GetElapsedTime method is:
+%
+%      double GetElapsedTime(TimerInfo *time_info)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Timer statistics structure.
+%
+*/
+MagickExport double GetElapsedTime(TimerInfo *time_info)
+{
+  assert(time_info != (TimerInfo *) NULL);
+  assert(time_info->signature == MagickSignature);
+  if (time_info->state == UndefinedTimerState)
+    return(0.0);
+  if (time_info->state == RunningTimerState)
+    StopTimer(time_info);
+  return(time_info->elapsed.total);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t T i m e r I n f o                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetTimerInfo() initializes the TimerInfo structure.
+%
+%  The format of the GetTimerInfo method is:
+%
+%      void GetTimerInfo(TimerInfo *time_info)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Timer statistics structure.
+%
+*/
+MagickExport void GetTimerInfo(TimerInfo *time_info)
+{
+  /*
+    Create a stopwatch and start it.
+  */
+  assert(time_info != (TimerInfo *) NULL);
+  (void) ResetMagickMemory(time_info,0,sizeof(*time_info));
+  time_info->state=UndefinedTimerState;
+  time_info->signature=MagickSignature;
+  StartTimer(time_info,MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t U s e r T i m e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetUserTime() returns the User time (user and system) by the operating
+%  system (in seconds) between the start and stop events. If the stopwatch is
+%  still running, it is stopped first.
+%
+%  The format of the GetUserTime method is:
+%
+%      double GetUserTime(TimerInfo *time_info)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Timer statistics structure.
+%
+*/
+MagickExport double GetUserTime(TimerInfo *time_info)
+{
+  assert(time_info != (TimerInfo *) NULL);
+  assert(time_info->signature == MagickSignature);
+  if (time_info->state == UndefinedTimerState)
+    return(0.0);
+  if (time_info->state == RunningTimerState)
+    StopTimer(time_info);
+  return(time_info->user.total);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e s e t T i m e r                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ResetTimer() resets the stopwatch.
+%
+%  The format of the ResetTimer method is:
+%
+%      void ResetTimer(TimerInfo *time_info)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Timer statistics structure.
+%
+*/
+MagickExport void ResetTimer(TimerInfo *time_info)
+{
+  assert(time_info != (TimerInfo *) NULL);
+  assert(time_info->signature == MagickSignature);
+  StopTimer(time_info);
+  time_info->elapsed.stop=0.0;
+  time_info->user.stop=0.0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S t a r t T i m e r                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StartTimer() starts the stopwatch.
+%
+%  The format of the StartTimer method is:
+%
+%      void StartTimer(TimerInfo *time_info,const MagickBooleanType reset)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Timer statistics structure.
+%
+%    o  reset: If reset is MagickTrue, then the stopwatch is reset prior to
+%       starting.  If reset is MagickFalse, then timing is continued without
+%       resetting the stopwatch.
+%
+*/
+MagickExport void StartTimer(TimerInfo *time_info,const MagickBooleanType reset)
+{
+  assert(time_info != (TimerInfo *) NULL);
+  assert(time_info->signature == MagickSignature);
+  if (reset != MagickFalse)
+    {
+      /*
+        Reset the stopwatch before starting it.
+      */
+      time_info->user.total=0.0;
+      time_info->elapsed.total=0.0;
+    }
+  if (time_info->state != RunningTimerState)
+    {
+      time_info->elapsed.start=ElapsedTime();
+      time_info->user.start=UserTime();
+    }
+  time_info->state=RunningTimerState;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   S t o p T i m e r                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  StopTimer() stops the stopwatch.
+%
+%  The format of the StopTimer method is:
+%
+%      void StopTimer(TimerInfo *time_info)
+%
+%  A description of each parameter follows.
+%
+%    o  time_info: Timer statistics structure.
+%
+*/
+static void StopTimer(TimerInfo *time_info)
+{
+  assert(time_info != (TimerInfo *) NULL);
+  assert(time_info->signature == MagickSignature);
+  time_info->elapsed.stop=ElapsedTime();
+  time_info->user.stop=UserTime();
+  if (time_info->state == RunningTimerState)
+    {
+      time_info->user.total+=time_info->user.stop-
+        time_info->user.start+MagickEpsilon;
+      time_info->elapsed.total+=time_info->elapsed.stop-
+        time_info->elapsed.start+MagickEpsilon;
+    }
+  time_info->state=StoppedTimerState;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   U s e r T i m e                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  UserTime() returns the total time the process has been scheduled (in
+%  seconds) since the last call to StartTimer().
+%
+%  The format of the UserTime method is:
+%
+%      double UserTime()
+%
+*/
+static double UserTime(void)
+{
+#if defined(MAGICKCORE_HAVE_TIMES)
+  struct tms
+    timer;
+
+  (void) times(&timer);
+  return((double) (timer.tms_utime+timer.tms_stime)/CLK_TCK);
+#else
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  return(NTUserTime());
+#else
+  return((double) clock()/CLK_TCK);
+#endif
+#endif
+}
diff --git a/MagickCore/timer.h b/MagickCore/timer.h
new file mode 100644
index 0000000..ca62334
--- /dev/null
+++ b/MagickCore/timer.h
@@ -0,0 +1,73 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore timer methods.
+*/
+#ifndef _MAGICKCORE_TIMER_H
+#define _MAGICKCORE_TIMER_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedTimerState,
+  StoppedTimerState,
+  RunningTimerState
+} TimerState;
+
+typedef struct _Timer
+{
+  double
+    start,
+    stop,
+    total;
+} Timer;
+
+typedef struct _TimerInfo
+{ 
+  Timer
+    user,
+    elapsed;
+  
+  TimerState
+    state;
+  
+  size_t
+    signature;
+} TimerInfo;
+
+extern MagickExport double
+  GetElapsedTime(TimerInfo *),
+  GetUserTime(TimerInfo *);
+
+extern MagickExport MagickBooleanType
+  ContinueTimer(TimerInfo *);
+
+extern MagickExport TimerInfo
+  *AcquireTimerInfo(void),
+  *DestroyTimerInfo(TimerInfo *);
+
+extern MagickExport void
+  GetTimerInfo(TimerInfo *),
+  ResetTimer(TimerInfo *),
+  StartTimer(TimerInfo *,const MagickBooleanType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/token-private.h b/MagickCore/token-private.h
new file mode 100644
index 0000000..9eb663a
--- /dev/null
+++ b/MagickCore/token-private.h
@@ -0,0 +1,192 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore private token methods.
+*/
+#ifndef _MAGICKCORE_TOKEN_PRIVATE_H
+#define _MAGICKCORE_TOKEN_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#ifndef EILSEQ
+  #define EILSEQ  ENOENT
+#endif
+
+#define MaxMultibyteCodes  6
+
+typedef struct
+{
+  int
+    code_mask,
+    code_value,
+    utf_mask,
+    utf_value;
+} UTFInfo;
+
+static UTFInfo
+  utf_info[MaxMultibyteCodes] =
+  {
+    { 0x80, 0x00, 0x000007f, 0x0000000 },  /* 1 byte sequence */
+    { 0xE0, 0xC0, 0x00007ff, 0x0000080 },  /* 2 byte sequence */
+    { 0xF0, 0xE0, 0x000ffff, 0x0000800 },  /* 3 byte sequence */
+    { 0xF8, 0xF0, 0x01fffff, 0x0010000 },  /* 4 byte sequence */
+    { 0xFC, 0xF8, 0x03fffff, 0x0200000 },  /* 5 byte sequence */
+    { 0xFE, 0xFC, 0x7ffffff, 0x4000000 },  /* 6 byte sequence */
+  };
+
+static inline unsigned char *ConvertLatin1ToUTF8(const unsigned char *content)
+{
+  register const unsigned char
+    *p;
+
+  register unsigned char
+    *q;
+
+  size_t
+    length;
+
+  unsigned char
+    *utf8;
+
+  unsigned int
+    c;
+
+  length=0;
+  for (p=content; *p != '\0'; p++)
+    length+=(*p & 0x80) != 0 ? 2 : 1;
+  utf8=(unsigned char *) NULL;
+  if (~length >= 1)
+    utf8=(unsigned char *) AcquireQuantumMemory(length+1UL,sizeof(*utf8));
+  if (utf8 == (unsigned char *) NULL)
+    return((unsigned char *) NULL);
+  q=utf8;
+  for (p=content; *p != '\0'; p++)
+  {
+    c=(*p);
+    if ((c & 0x80) == 0)
+      *q++=c;
+    else
+      {
+        *q++=0xc0 | ((c >> 6) & 0x3f);
+        *q++=0x80 | (c & 0x3f);
+      }
+  }
+  *q='\0';
+  return(utf8);
+}
+
+static inline int GetNextUTFCode(const char *text,unsigned int *octets)
+{
+  int
+    code;
+
+  register ssize_t
+    i;
+
+  register int
+    c,
+    unicode;
+
+  *octets=1;
+  if (text == (const char *) NULL)
+    {
+      errno=EINVAL;
+      return(-1);
+    }
+  code=(int) (*text++) & 0xff;
+  unicode=code;
+  for (i=0; i < MaxMultibyteCodes; i++)
+  {
+    if ((code & utf_info[i].code_mask) == utf_info[i].code_value)
+      {
+        unicode&=utf_info[i].utf_mask;
+        if (unicode < utf_info[i].utf_value)
+          {
+            errno=EILSEQ;
+            return(-1);
+          }
+        *octets=(unsigned int) (i+1);
+        return(unicode);
+      }
+    c=(int) (*text++ ^ 0x80) & 0xff;
+    if ((c & 0xc0) != 0)
+      {
+        errno=EILSEQ;
+        return(-1);
+      }
+    unicode=(unicode << 6) | c;
+  }
+  errno=EILSEQ;
+  return(-1);
+}
+
+static inline int GetUTFCode(const char *text)
+{
+  unsigned int
+    octets;
+
+  return(GetNextUTFCode(text,&octets));
+}
+
+static inline unsigned int GetUTFOctets(const char *text)
+{
+  unsigned int
+    octets;
+
+  (void) GetNextUTFCode(text,&octets);
+  return(octets);
+}
+
+static inline MagickBooleanType IsUTFSpace(int code)
+{
+  if (((code >= 0x0009) && (code <= 0x000d)) || (code == 0x0020) ||
+      (code == 0x0085) || (code == 0x00a0) || (code == 0x1680) ||
+      (code == 0x180e) || ((code >= 0x2000) && (code <= 0x200a)) ||
+      (code == 0x2028) || (code == 0x2029) || (code == 0x202f) ||
+      (code == 0x205f) || (code == 0x3000))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+static inline MagickBooleanType IsUTFValid(int code)
+{
+  int
+    mask;
+
+  mask=(int) 0x7fffffff;
+  if (((code & ~mask) != 0) && ((code < 0xd800) || (code > 0xdfff)) &&
+      (code != 0xfffe) && (code != 0xffff))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static inline MagickBooleanType IsUTFAscii(int code)
+{
+  int
+    mask;
+
+  mask=(int) 0x7f;
+  if ((code & ~mask) != 0)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/token.c b/MagickCore/token.c
new file mode 100644
index 0000000..cc74f37
--- /dev/null
+++ b/MagickCore/token.c
@@ -0,0 +1,966 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                    TTTTT   OOO   K   K  EEEEE  N   N                        %
+%                      T    O   O  K  K   E      NN  N                        %
+%                      T    O   O  KKK    EEE    N N N                        %
+%                      T    O   O  K  K   E      N  NN                        %
+%                      T     OOO   K   K  EEEEE  N   N                        %
+%                                                                             %
+%                                                                             %
+%                         MagickCore Token Methods                            %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                              January 1993                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token.h"
+#include "MagickCore/token-private.h"
+#include "MagickCore/utility.h"
+
+/*
+  Typedef declaractions.
+*/
+struct _TokenInfo
+{
+  int
+    state;
+
+  MagickStatusType
+    flag;
+
+  ssize_t
+    offset;
+
+  char
+    quote;
+
+  size_t
+    signature;
+};
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e T o k e n I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireTokenInfo() allocates the TokenInfo structure.
+%
+%  The format of the AcquireTokenInfo method is:
+%
+%      TokenInfo *AcquireTokenInfo()
+%
+*/
+MagickExport TokenInfo *AcquireTokenInfo(void)
+{
+  TokenInfo
+    *token_info;
+
+  token_info=(TokenInfo *) AcquireMagickMemory(sizeof(*token_info));
+  if (token_info == (TokenInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  token_info->signature=MagickSignature;
+  return(token_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y T o k e n I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyTokenInfo() deallocates memory associated with an TokenInfo
+%  structure.
+%
+%  The format of the DestroyTokenInfo method is:
+%
+%      TokenInfo *DestroyTokenInfo(TokenInfo *token_info)
+%
+%  A description of each parameter follows:
+%
+%    o token_info: Specifies a pointer to an TokenInfo structure.
+%
+*/
+MagickExport TokenInfo *DestroyTokenInfo(TokenInfo *token_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(token_info != (TokenInfo *) NULL);
+  assert(token_info->signature == MagickSignature);
+  token_info->signature=(~MagickSignature);
+  token_info=(TokenInfo *) RelinquishMagickMemory(token_info);
+  return(token_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t M a g i c k T o k e n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickToken() gets a token from the token stream.  A token is defined as
+%  a sequence of characters delimited by whitespace (e.g. clip-path), a
+%  sequence delimited with quotes (.e.g "Quote me"), or a sequence enclosed in
+%  parenthesis (e.g. rgb(0,0,0)).  GetMagickToken() also recognizes these
+%  separator characters: ':', '=', ',', and ';'.
+%
+%  The format of the GetMagickToken method is:
+%
+%      void GetMagickToken(const char *start,const char **end,char *token)
+%
+%  A description of each parameter follows:
+%
+%    o start: the start of the token sequence.
+%
+%    o end: point to the end of the token sequence.
+%
+%    o token: copy the token to this buffer.
+%
+*/
+MagickExport void GetMagickToken(const char *start,const char **end,char *token)
+{
+  double
+    value;
+
+  register const char
+    *p;
+
+  register ssize_t
+    i;
+
+  assert(start != (const char *) NULL);
+  assert(token != (char *) NULL);
+  i=0;
+  for (p=start; *p != '\0'; )
+  {
+    while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0'))
+      p++;
+    if (*p == '\0')
+      break;
+    switch (*p)
+    {
+      case '"':
+      case '\'':
+      case '`':
+      case '{':
+      {
+        register char
+          escape;
+
+        switch (*p)
+        {
+          case '"': escape='"'; break;
+          case '\'': escape='\''; break;
+          case '`': escape='\''; break;
+          case '{': escape='}'; break;
+          default: escape=(*p); break;
+        }
+        for (p++; *p != '\0'; p++)
+        {
+          if ((*p == '\\') && ((*(p+1) == escape) || (*(p+1) == '\\')))
+            p++;
+          else
+            if (*p == escape)
+              {
+                p++;
+                break;
+              }
+          token[i++]=(*p);
+        }
+        break;
+      }
+      case '/':
+      {
+        token[i++]=(*p++);
+        if ((*p == '>') || (*p == '/'))
+          token[i++]=(*p++);
+        break;
+      }
+      default:
+      {
+        char
+          *q;
+
+        value=InterpretLocaleValue(p,&q);
+        (void) value;
+        if ((p != q) && (*p != ','))
+          {
+            for ( ; (p < q) && (*p != ','); p++)
+              token[i++]=(*p);
+            if (*p == '%')
+              token[i++]=(*p++);
+            break;
+          }
+        if ((*p != '\0') && (isalpha((int) ((unsigned char) *p)) == 0) &&
+            (*p != *DirectorySeparator) && (*p != '#') && (*p != '<'))
+          {
+            token[i++]=(*p++);
+            break;
+          }
+        for ( ; *p != '\0'; p++)
+        {
+          if (((isspace((int) ((unsigned char) *p)) != 0) || (*p == '=') ||
+              (*p == ',') || (*p == ':') || (*p == ';')) && (*(p-1) != '\\'))
+            break;
+          if ((i > 0) && (*p == '<'))
+            break;
+          token[i++]=(*p);
+          if (*p == '>')
+            break;
+          if (*p == '(')
+            for (p++; *p != '\0'; p++)
+            {
+              token[i++]=(*p);
+              if ((*p == ')') && (*(p-1) != '\\'))
+                break;
+            }
+        }
+        break;
+      }
+    }
+    break;
+  }
+  token[i]='\0';
+  if (LocaleNCompare(token,"url(",4) == 0)
+    {
+      ssize_t
+        offset;
+
+      offset=4;
+      if (token[offset] == '#')
+        offset++;
+      i=(ssize_t) strlen(token);
+      (void) CopyMagickString(token,token+offset,MaxTextExtent);
+      token[i-offset-1]='\0';
+    }
+  while (isspace((int) ((unsigned char) *p)) != 0)
+    p++;
+  if (end != (const char **) NULL)
+    *end=(const char *) p;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G l o b E x p r e s s i o n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GlobExpression() returns MagickTrue if the expression matches the pattern.
+%
+%  The format of the GlobExpression function is:
+%
+%      MagickBooleanType GlobExpression(const char *expression,
+%        const char *pattern,const MagickBooleanType case_insensitive)
+%
+%  A description of each parameter follows:
+%
+%    o expression: Specifies a pointer to a text string containing a file name.
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o case_insensitive: set to MagickTrue to ignore the case when matching
+%      an expression.
+%
+*/
+MagickExport MagickBooleanType GlobExpression(const char *expression,
+  const char *pattern,const MagickBooleanType case_insensitive)
+{
+  MagickBooleanType
+    done,
+    match;
+
+  register const char
+    *p;
+
+  /*
+    Return on empty pattern or '*'.
+  */
+  if (pattern == (char *) NULL)
+    return(MagickTrue);
+  if (GetUTFCode(pattern) == 0)
+    return(MagickTrue);
+  if (LocaleCompare(pattern,"*") == 0)
+    return(MagickTrue);
+  p=pattern+strlen(pattern)-1;
+  if ((GetUTFCode(p) == ']') && (strchr(pattern,'[') != (char *) NULL))
+    {
+      ExceptionInfo
+        *exception;
+
+      ImageInfo
+        *image_info;
+
+      /*
+        Determine if pattern is a scene, i.e. img0001.pcd[2].
+      */
+      image_info=AcquireImageInfo();
+      (void) CopyMagickString(image_info->filename,pattern,MaxTextExtent);
+      exception=AcquireExceptionInfo();
+      (void) SetImageInfo(image_info,0,exception);
+      exception=DestroyExceptionInfo(exception);
+      if (LocaleCompare(image_info->filename,pattern) != 0)
+        {
+          image_info=DestroyImageInfo(image_info);
+          return(MagickFalse);
+        }
+      image_info=DestroyImageInfo(image_info);
+    }
+  /*
+    Evaluate glob expression.
+  */
+  done=MagickFalse;
+  while ((GetUTFCode(pattern) != 0) && (done == MagickFalse))
+  {
+    if (GetUTFCode(expression) == 0)
+      if ((GetUTFCode(pattern) != '{') && (GetUTFCode(pattern) != '*'))
+        break;
+    switch (GetUTFCode(pattern))
+    {
+      case '*':
+      {
+        MagickBooleanType
+          status;
+
+        status=MagickFalse;
+        pattern+=GetUTFOctets(pattern);
+        while ((GetUTFCode(expression) != 0) && (status == MagickFalse))
+        {
+          status=GlobExpression(expression,pattern,case_insensitive);
+          expression+=GetUTFOctets(expression);
+        }
+        if (status != MagickFalse)
+          {
+            while (GetUTFCode(expression) != 0)
+              expression+=GetUTFOctets(expression);
+            while (GetUTFCode(pattern) != 0)
+              pattern+=GetUTFOctets(pattern);
+          }
+        break;
+      }
+      case '[':
+      {
+        int
+          c;
+
+        pattern+=GetUTFOctets(pattern);
+        for ( ; ; )
+        {
+          if ((GetUTFCode(pattern) == 0) || (GetUTFCode(pattern) == ']'))
+            {
+              done=MagickTrue;
+              break;
+            }
+          if (GetUTFCode(pattern) == '\\')
+            {
+              pattern+=GetUTFOctets(pattern);
+              if (GetUTFCode(pattern) == 0)
+                {
+                  done=MagickTrue;
+                  break;
+                }
+             }
+          if (GetUTFCode(pattern+GetUTFOctets(pattern)) == '-')
+            {
+              c=GetUTFCode(pattern);
+              pattern+=GetUTFOctets(pattern);
+              pattern+=GetUTFOctets(pattern);
+              if (GetUTFCode(pattern) == ']')
+                {
+                  done=MagickTrue;
+                  break;
+                }
+              if (GetUTFCode(pattern) == '\\')
+                {
+                  pattern+=GetUTFOctets(pattern);
+                  if (GetUTFCode(pattern) == 0)
+                    {
+                      done=MagickTrue;
+                      break;
+                    }
+                }
+              if ((GetUTFCode(expression) < c) ||
+                  (GetUTFCode(expression) > GetUTFCode(pattern)))
+                {
+                  pattern+=GetUTFOctets(pattern);
+                  continue;
+                }
+            }
+          else
+            if (GetUTFCode(pattern) != GetUTFCode(expression))
+              {
+                pattern+=GetUTFOctets(pattern);
+                continue;
+              }
+          pattern+=GetUTFOctets(pattern);
+          while ((GetUTFCode(pattern) != ']') && (GetUTFCode(pattern) != 0))
+          {
+            if ((GetUTFCode(pattern) == '\\') &&
+                (GetUTFCode(pattern+GetUTFOctets(pattern)) > 0))
+              pattern+=GetUTFOctets(pattern);
+            pattern+=GetUTFOctets(pattern);
+          }
+          if (GetUTFCode(pattern) != 0)
+            {
+              pattern+=GetUTFOctets(pattern);
+              expression+=GetUTFOctets(expression);
+            }
+          break;
+        }
+        break;
+      }
+      case '?':
+      {
+        pattern+=GetUTFOctets(pattern);
+        expression+=GetUTFOctets(expression);
+        break;
+      }
+      case '{':
+      {
+        register const char
+          *p;
+
+        pattern+=GetUTFOctets(pattern);
+        while ((GetUTFCode(pattern) != '}') && (GetUTFCode(pattern) != 0))
+        {
+          p=expression;
+          match=MagickTrue;
+          while ((GetUTFCode(p) != 0) && (GetUTFCode(pattern) != 0) &&
+                 (GetUTFCode(pattern) != ',') && (GetUTFCode(pattern) != '}') &&
+                 (match != MagickFalse))
+          {
+            if (GetUTFCode(pattern) == '\\')
+              pattern+=GetUTFOctets(pattern);
+            match=(GetUTFCode(pattern) == GetUTFCode(p)) ? MagickTrue :
+              MagickFalse;
+            p+=GetUTFOctets(p);
+            pattern+=GetUTFOctets(pattern);
+          }
+          if (GetUTFCode(pattern) == 0)
+            {
+              match=MagickFalse;
+              done=MagickTrue;
+              break;
+            }
+          else
+            if (match != MagickFalse)
+              {
+                expression=p;
+                while ((GetUTFCode(pattern) != '}') &&
+                       (GetUTFCode(pattern) != 0))
+                {
+                  pattern+=GetUTFOctets(pattern);
+                  if (GetUTFCode(pattern) == '\\')
+                    {
+                      pattern+=GetUTFOctets(pattern);
+                      if (GetUTFCode(pattern) == '}')
+                        pattern+=GetUTFOctets(pattern);
+                    }
+                }
+              }
+            else
+              {
+                while ((GetUTFCode(pattern) != '}') &&
+                       (GetUTFCode(pattern) != ',') &&
+                       (GetUTFCode(pattern) != 0))
+                {
+                  pattern+=GetUTFOctets(pattern);
+                  if (GetUTFCode(pattern) == '\\')
+                    {
+                      pattern+=GetUTFOctets(pattern);
+                      if ((GetUTFCode(pattern) == '}') ||
+                          (GetUTFCode(pattern) == ','))
+                        pattern+=GetUTFOctets(pattern);
+                    }
+                }
+              }
+            if (GetUTFCode(pattern) != 0)
+              pattern+=GetUTFOctets(pattern);
+          }
+        break;
+      }
+      case '\\':
+      {
+        pattern+=GetUTFOctets(pattern);
+        if (GetUTFCode(pattern) == 0)
+          break;
+      }
+      default:
+      {
+        if (case_insensitive != MagickFalse)
+          {
+            if (tolower((int) GetUTFCode(expression)) !=
+                tolower((int) GetUTFCode(pattern)))
+              {
+                done=MagickTrue;
+                break;
+              }
+          }
+        else
+          if (GetUTFCode(expression) != GetUTFCode(pattern))
+            {
+              done=MagickTrue;
+              break;
+            }
+        expression+=GetUTFOctets(expression);
+        pattern+=GetUTFOctets(pattern);
+      }
+    }
+  }
+  while (GetUTFCode(pattern) == '*')
+    pattern+=GetUTFOctets(pattern);
+  match=(GetUTFCode(expression) == 0) && (GetUTFCode(pattern) == 0) ?
+    MagickTrue : MagickFalse;
+  return(match);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     I s G l o b                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsGlob() returns MagickTrue if the path specification contains a globbing
+%  pattern.
+%
+%  The format of the IsGlob method is:
+%
+%      MagickBooleanType IsGlob(const char *geometry)
+%
+%  A description of each parameter follows:
+%
+%    o path: the path.
+%
+*/
+MagickExport MagickBooleanType IsGlob(const char *path)
+{
+  MagickBooleanType
+    status;
+
+  if (IsPathAccessible(path) != MagickFalse)
+    return(MagickFalse);
+  status=(strchr(path,'*') != (char *) NULL) ||
+    (strchr(path,'?') != (char *) NULL) ||
+    (strchr(path,'{') != (char *) NULL) ||
+    (strchr(path,'}') != (char *) NULL) ||
+    (strchr(path,'[') != (char *) NULL) ||
+    (strchr(path,']') != (char *) NULL) ? MagickTrue : MagickFalse;
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T o k e n i z e r                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Tokenizer() is a generalized, finite state token parser.  It extracts tokens
+%  one at a time from a string of characters.  The characters used for white
+%  space, for break characters, and for quotes can be specified.  Also,
+%  characters in the string can be preceded by a specifiable escape character
+%  which removes any special meaning the character may have.
+%
+%  Here is some terminology:
+%
+%    o token: A single unit of information in the form of a group of
+%      characters.
+%
+%    o white space: Apace that gets ignored (except within quotes or when
+%      escaped), like blanks and tabs. in addition, white space terminates a
+%      non-quoted token.
+%
+%    o break set: One or more characters that separates non-quoted tokens.
+%      Commas are a common break character. The usage of break characters to
+%      signal the end of a token is the same as that of white space, except
+%      multiple break characters with nothing or only white space between
+%      generate a null token for each two break characters together.
+%
+%      For example, if blank is set to be the white space and comma is set to
+%      be the break character, the line
+%
+%        A, B, C ,  , DEF
+%
+%        ... consists of 5 tokens:
+%
+%        1)  "A"
+%        2)  "B"
+%        3)  "C"
+%        4)  "" (the null string)
+%        5)  "DEF"
+%
+%    o Quote character: A character that, when surrounding a group of other
+%      characters, causes the group of characters to be treated as a single
+%      token, no matter how many white spaces or break characters exist in
+%      the group. Also, a token always terminates after the closing quote.
+%      For example, if ' is the quote character, blank is white space, and
+%      comma is the break character, the following string
+%
+%        A, ' B, CD'EF GHI
+%
+%        ... consists of 4 tokens:
+%
+%        1)  "A"
+%        2)  " B, CD" (note the blanks & comma)
+%        3)  "EF"
+%        4)  "GHI"
+%
+%      The quote characters themselves do not appear in the resultant
+%      tokens.  The double quotes are delimiters i use here for
+%      documentation purposes only.
+%
+%    o Escape character: A character which itself is ignored but which
+%      causes the next character to be used as is.  ^ and \ are often used
+%      as escape characters. An escape in the last position of the string
+%      gets treated as a "normal" (i.e., non-quote, non-white, non-break,
+%      and non-escape) character. For example, assume white space, break
+%      character, and quote are the same as in the above examples, and
+%      further, assume that ^ is the escape character. Then, in the string
+%
+%        ABC, ' DEF ^' GH' I ^ J K^ L ^
+%
+%        ... there are 7 tokens:
+%
+%        1)  "ABC"
+%        2)  " DEF ' GH"
+%        3)  "I"
+%        4)  " "     (a lone blank)
+%        5)  "J"
+%        6)  "K L"
+%        7)  "^"     (passed as is at end of line)
+%
+%  The format of the Tokenizer method is:
+%
+%      int Tokenizer(TokenInfo *token_info,const unsigned flag,char *token,
+%        const size_t max_token_length,const char *line,const char *white,
+%        const char *break_set,const char *quote,const char escape,
+%        char *breaker,int *next,char *quoted)
+%
+%  A description of each parameter follows:
+%
+%    o flag: right now, only the low order 3 bits are used.
+%
+%        1 => convert non-quoted tokens to upper case
+%        2 => convert non-quoted tokens to lower case
+%        0 => do not convert non-quoted tokens
+%
+%    o token: a character string containing the returned next token
+%
+%    o max_token_length: the maximum size of "token".  Characters beyond
+%      "max_token_length" are truncated.
+%
+%    o string: the string to be parsed.
+%
+%    o white: a string of the valid white spaces.  example:
+%
+%        char whitesp[]={" \t"};
+%
+%      blank and tab will be valid white space.
+%
+%    o break: a string of the valid break characters. example:
+%
+%        char breakch[]={";,"};
+%
+%      semicolon and comma will be valid break characters.
+%
+%    o quote: a string of the valid quote characters. An example would be
+%
+%        char whitesp[]={"'\"");
+%
+%      (this causes single and double quotes to be valid) Note that a
+%      token starting with one of these characters needs the same quote
+%      character to terminate it.
+%
+%      for example:
+%
+%        "ABC '
+%
+%      is unterminated, but
+%
+%        "DEF" and 'GHI'
+%
+%      are properly terminated.  Note that different quote characters
+%      can appear on the same line; only for a given token do the quote
+%      characters have to be the same.
+%
+%    o escape: the escape character (NOT a string ... only one
+%      allowed). Use zero if none is desired.
+%
+%    o breaker: the break character used to terminate the current
+%      token.  If the token was quoted, this will be the quote used.  If
+%      the token is the last one on the line, this will be zero.
+%
+%    o next: this variable points to the first character of the
+%      next token.  it gets reset by "tokenizer" as it steps through the
+%      string.  Set it to 0 upon initialization, and leave it alone
+%      after that.  You can change it if you want to jump around in the
+%      string or re-parse from the beginning, but be careful.
+%
+%    o quoted: set to True if the token was quoted and MagickFalse
+%      if not.  You may need this information (for example:  in C, a
+%      string with quotes around it is a character string, while one
+%      without is an identifier).
+%
+%    o result: 0 if we haven't reached EOS (end of string), and 1
+%      if we have.
+%
+*/
+
+#define IN_WHITE 0
+#define IN_TOKEN 1
+#define IN_QUOTE 2
+#define IN_OZONE 3
+
+static ssize_t sindex(int c,const char *string)
+{
+  register const char
+    *p;
+
+  for (p=string; *p != '\0'; p++)
+    if (c == (int) (*p))
+      return((ssize_t) (p-string));
+  return(-1);
+}
+
+static void StoreToken(TokenInfo *token_info,char *string,
+  size_t max_token_length,int c)
+{
+  register ssize_t
+    i;
+
+  if ((token_info->offset < 0) ||
+      ((size_t) token_info->offset >= (max_token_length-1)))
+    return;
+  i=token_info->offset++;
+  string[i]=(char) c;
+  if (token_info->state == IN_QUOTE)
+    return;
+  switch (token_info->flag & 0x03)
+  {
+    case 1:
+    {
+      string[i]=(char) toupper(c);
+      break;
+    }
+    case 2:
+    {
+      string[i]=(char) tolower(c);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+MagickExport int Tokenizer(TokenInfo *token_info,const unsigned flag,
+  char *token,const size_t max_token_length,const char *line,const char *white,
+  const char *break_set,const char *quote,const char escape,char *breaker,
+  int *next,char *quoted)
+{
+  int
+    c;
+
+  register ssize_t
+    i;
+
+  *breaker='\0';
+  *quoted='\0';
+  if (line[*next] == '\0')
+    return(1);
+  token_info->state=IN_WHITE;
+  token_info->quote=(char) MagickFalse;
+  token_info->flag=flag;
+  for (token_info->offset=0; (int) line[*next] != 0; (*next)++)
+  {
+    c=(int) line[*next];
+    i=sindex(c,break_set);
+    if (i >= 0)
+      {
+        switch (token_info->state)
+        {
+          case IN_WHITE:
+          case IN_TOKEN:
+          case IN_OZONE:
+          {
+            (*next)++;
+            *breaker=break_set[i];
+            token[token_info->offset]='\0';
+            return(0);
+          }
+          case IN_QUOTE:
+          {
+            StoreToken(token_info,token,max_token_length,c);
+            break;
+          }
+        }
+        continue;
+      }
+    i=sindex(c,quote);
+    if (i >= 0)
+      {
+        switch (token_info->state)
+        {
+          case IN_WHITE:
+          {
+            token_info->state=IN_QUOTE;
+            token_info->quote=quote[i];
+            *quoted=(char) MagickTrue;
+            break;
+          }
+          case IN_QUOTE:
+          {
+            if (quote[i] != token_info->quote)
+              StoreToken(token_info,token,max_token_length,c);
+            else
+              {
+                token_info->state=IN_OZONE;
+                token_info->quote='\0';
+              }
+            break;
+          }
+          case IN_TOKEN:
+          case IN_OZONE:
+          {
+            *breaker=(char) c;
+            token[token_info->offset]='\0';
+            return(0);
+          }
+        }
+        continue;
+      }
+    i=sindex(c,white);
+    if (i >= 0)
+      {
+        switch (token_info->state)
+        {
+          case IN_WHITE:
+          case IN_OZONE:
+            break;
+          case IN_TOKEN:
+          {
+            token_info->state=IN_OZONE;
+            break;
+          }
+          case IN_QUOTE:
+          {
+            StoreToken(token_info,token,max_token_length,c);
+            break;
+          }
+        }
+        continue;
+      }
+    if (c == (int) escape)
+      {
+        if (line[(*next)+1] == '\0')
+          {
+            *breaker='\0';
+            StoreToken(token_info,token,max_token_length,c);
+            (*next)++;
+            token[token_info->offset]='\0';
+            return(0);
+          }
+        switch (token_info->state)
+        {
+          case IN_WHITE:
+          {
+            (*next)--;
+            token_info->state=IN_TOKEN;
+            break;
+          }
+          case IN_TOKEN:
+          case IN_QUOTE:
+          {
+            (*next)++;
+            c=(int) line[*next];
+            StoreToken(token_info,token,max_token_length,c);
+            break;
+          }
+          case IN_OZONE:
+          {
+            token[token_info->offset]='\0';
+            return(0);
+          }
+        }
+        continue;
+      }
+    switch (token_info->state)
+    {
+      case IN_WHITE:
+        token_info->state=IN_TOKEN;
+      case IN_TOKEN:
+      case IN_QUOTE:
+      {
+        StoreToken(token_info,token,max_token_length,c);
+        break;
+      }
+      case IN_OZONE:
+      {
+        token[token_info->offset]='\0';
+        return(0);
+      }
+    }
+  }
+  token[token_info->offset]='\0';
+  return(0);
+}
diff --git a/MagickCore/token.h b/MagickCore/token.h
new file mode 100644
index 0000000..2e5ef35
--- /dev/null
+++ b/MagickCore/token.h
@@ -0,0 +1,50 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore token methods.
+*/
+#ifndef _MAGICKCORE_TOKEN_H
+#define _MAGICKCORE_TOKEN_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+  Typedef declarations.
+*/
+typedef struct _TokenInfo
+  TokenInfo;
+
+extern MagickExport int
+  Tokenizer(TokenInfo *,const unsigned int,char *,const size_t,const char *,
+    const char *,const char *,const char *,const char,char *,int *,char *);
+
+extern MagickExport MagickBooleanType
+  GlobExpression(const char *,const char *,const MagickBooleanType),
+  IsGlob(const char *);
+
+extern MagickExport TokenInfo
+  *AcquireTokenInfo(void),
+  *DestroyTokenInfo(TokenInfo *);
+
+extern MagickExport void
+  GetMagickToken(const char *,const char **,char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/transform.c b/MagickCore/transform.c
new file mode 100644
index 0000000..1dce2d7
--- /dev/null
+++ b/MagickCore/transform.c
@@ -0,0 +1,2413 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%       TTTTT  RRRR    AAA   N   N  SSSSS  FFFFF   OOO   RRRR   M   M         %
+%         T    R   R  A   A  NN  N  SS     F      O   O  R   R  MM MM         %
+%         T    RRRR   AAAAA  N N N   SSS   FFF    O   O  RRRR   M M M         %
+%         T    R R    A   A  N  NN     SS  F      O   O  R R    M   M         %
+%         T    R  R   A   A  N   N  SSSSS  F       OOO   R  R   M   M         %
+%                                                                             %
+%                                                                             %
+%                    MagickCore Image Transform Methods                       %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 July 1992                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/cache-view.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/effect.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/image.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/layer.h"
+#include "MagickCore/list.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/thread-private.h"
+#include "MagickCore/transform.h"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C h o p I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ChopImage() removes a region of an image and collapses the image to occupy
+%  the removed portion.
+%
+%  The format of the ChopImage method is:
+%
+%      Image *ChopImage(const Image *image,const RectangleInfo *chop_info)
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o chop_info: Define the region of the image to chop.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ChopImage(const Image *image,const RectangleInfo *chop_info,
+  ExceptionInfo *exception)
+{
+#define ChopImageTag  "Chop/Image"
+
+  CacheView
+    *chop_view,
+    *image_view;
+
+  Image
+    *chop_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    extent;
+
+  ssize_t
+    y;
+
+  /*
+    Check chop geometry.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  assert(chop_info != (RectangleInfo *) NULL);
+  if (((chop_info->x+(ssize_t) chop_info->width) < 0) ||
+      ((chop_info->y+(ssize_t) chop_info->height) < 0) ||
+      (chop_info->x > (ssize_t) image->columns) ||
+      (chop_info->y > (ssize_t) image->rows))
+    ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
+  extent=(*chop_info);
+  if ((extent.x+(ssize_t) extent.width) > (ssize_t) image->columns)
+    extent.width=(size_t) ((ssize_t) image->columns-extent.x);
+  if ((extent.y+(ssize_t) extent.height) > (ssize_t) image->rows)
+    extent.height=(size_t) ((ssize_t) image->rows-extent.y);
+  if (extent.x < 0)
+    {
+      extent.width-=(size_t) (-extent.x);
+      extent.x=0;
+    }
+  if (extent.y < 0)
+    {
+      extent.height-=(size_t) (-extent.y);
+      extent.y=0;
+    }
+  chop_image=CloneImage(image,image->columns-extent.width,image->rows-
+    extent.height,MagickTrue,exception);
+  if (chop_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Extract chop image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  chop_view=AcquireCacheView(chop_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) extent.y; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(chop_view,0,y,chop_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
+        {
+          SetPixelRed(chop_image,GetPixelRed(image,p),q);
+          SetPixelGreen(chop_image,GetPixelGreen(image,p),q);
+          SetPixelBlue(chop_image,GetPixelBlue(image,p),q);
+          if (image->colorspace == CMYKColorspace)
+            SetPixelBlack(chop_image,GetPixelBlack(image,p),q);
+          q+=GetPixelChannels(chop_image);
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ChopImage)
+#endif
+        proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  /*
+    Extract chop image.
+  */
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) (image->rows-(extent.y+extent.height)); y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,extent.y+extent.height+y,
+      image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(chop_view,0,extent.y+y,chop_image->columns,
+      1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if ((x < extent.x) || (x >= (ssize_t) (extent.x+extent.width)))
+        {
+          SetPixelRed(chop_image,GetPixelRed(image,p),q);
+          SetPixelGreen(chop_image,GetPixelGreen(image,p),q);
+          SetPixelBlue(chop_image,GetPixelBlue(image,p),q);
+          p+=GetPixelChannels(image);
+          q+=GetPixelChannels(chop_image);
+        }
+      p+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(chop_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ChopImage)
+#endif
+        proceed=SetImageProgress(image,ChopImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  chop_view=DestroyCacheView(chop_view);
+  image_view=DestroyCacheView(image_view);
+  chop_image->type=image->type;
+  return(chop_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     C o n s o l i d a t e C M Y K I m a g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConsolidateCMYKImage() consolidates separate C, M, Y, and K planes into a
+%  single image.
+%
+%  The format of the ConsolidateCMYKImage method is:
+%
+%      Image *ConsolidateCMYKImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image sequence.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ConsolidateCMYKImages(const Image *images,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *cmyk_view,
+    *image_view;
+
+  Image
+    *cmyk_image,
+    *cmyk_images;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    y;
+
+  /*
+    Consolidate separate C, M, Y, and K planes into a single image.
+  */
+  assert(images != (Image *) NULL);
+  assert(images->signature == MagickSignature);
+  if (images->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  cmyk_images=NewImageList();
+  for (i=0; i < (ssize_t) GetImageListLength(images); i+=4)
+  {
+    cmyk_image=CloneImage(images,images->columns,images->rows,MagickTrue,
+      exception);
+    if (cmyk_image == (Image *) NULL)
+      break;
+    if (SetImageStorageClass(cmyk_image,DirectClass) == MagickFalse)
+      break;
+    (void) SetImageColorspace(cmyk_image,CMYKColorspace);
+    image_view=AcquireCacheView(images);
+    cmyk_view=AcquireCacheView(cmyk_image);
+    for (y=0; y < (ssize_t) images->rows; y++)
+    {
+      register const Quantum
+        *restrict p;
+
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
+      q=QueueCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
+        exception);
+      if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+        break;
+      for (x=0; x < (ssize_t) images->columns; x++)
+      {
+        SetPixelRed(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
+        p+=GetPixelChannels(images);
+        q+=GetPixelChannels(cmyk_image);
+      }
+      if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
+        break;
+    }
+    cmyk_view=DestroyCacheView(cmyk_view);
+    image_view=DestroyCacheView(image_view);
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+    image_view=AcquireCacheView(images);
+    cmyk_view=AcquireCacheView(cmyk_image);
+    for (y=0; y < (ssize_t) images->rows; y++)
+    {
+      register const Quantum
+        *restrict p;
+
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
+      q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
+        exception);
+      if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+        break;
+      for (x=0; x < (ssize_t) images->columns; x++)
+      {
+        SetPixelGreen(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
+        p+=GetPixelChannels(images);
+        q+=GetPixelChannels(cmyk_image);
+      }
+      if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
+        break;
+    }
+    cmyk_view=DestroyCacheView(cmyk_view);
+    image_view=DestroyCacheView(image_view);
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+    image_view=AcquireCacheView(images);
+    cmyk_view=AcquireCacheView(cmyk_image);
+    for (y=0; y < (ssize_t) images->rows; y++)
+    {
+      register const Quantum
+        *restrict p;
+
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
+      q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
+        exception);
+      if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+        break;
+      for (x=0; x < (ssize_t) images->columns; x++)
+      {
+        SetPixelBlue(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
+        p+=GetPixelChannels(images);
+        q+=GetPixelChannels(cmyk_image);
+      }
+      if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
+        break;
+    }
+    cmyk_view=DestroyCacheView(cmyk_view);
+    image_view=DestroyCacheView(image_view);
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+    image_view=AcquireCacheView(images);
+    cmyk_view=AcquireCacheView(cmyk_image);
+    for (y=0; y < (ssize_t) images->rows; y++)
+    {
+      register const Quantum
+        *restrict p;
+
+      register ssize_t
+        x;
+
+      register Quantum
+        *restrict q;
+
+      p=GetCacheViewVirtualPixels(image_view,0,y,images->columns,1,exception);
+      q=GetCacheViewAuthenticPixels(cmyk_view,0,y,cmyk_image->columns,1,
+        exception);
+      if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+        break;
+      for (x=0; x < (ssize_t) images->columns; x++)
+      {
+        SetPixelBlack(cmyk_image,QuantumRange-GetPixelIntensity(images,p),q);
+        p+=GetPixelChannels(images);
+        q+=GetPixelChannels(cmyk_image);
+      }
+      if (SyncCacheViewAuthenticPixels(cmyk_view,exception) == MagickFalse)
+        break;
+    }
+    cmyk_view=DestroyCacheView(cmyk_view);
+    image_view=DestroyCacheView(image_view);
+    AppendImageToList(&cmyk_images,cmyk_image);
+    images=GetNextImageInList(images);
+    if (images == (Image *) NULL)
+      break;
+  }
+  return(cmyk_images);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C r o p I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CropImage() extracts a region of the image starting at the offset defined
+%  by geometry.  Region must be fully defined, and no special handling of
+%  geometry flags is performed.
+%
+%  The format of the CropImage method is:
+%
+%      Image *CropImage(const Image *image,const RectangleInfo *geometry,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o geometry: Define the region of the image to crop with members
+%      x, y, width, and height.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *CropImage(const Image *image,const RectangleInfo *geometry,
+  ExceptionInfo *exception)
+{
+#define CropImageTag  "Crop/Image"
+
+  CacheView
+    *crop_view,
+    *image_view;
+
+  Image
+    *crop_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    bounding_box,
+    page;
+
+  ssize_t
+    y;
+
+  /*
+    Check crop geometry.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(geometry != (const RectangleInfo *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  bounding_box=image->page;
+  if ((bounding_box.width == 0) || (bounding_box.height == 0))
+    {
+      bounding_box.width=image->columns;
+      bounding_box.height=image->rows;
+    }
+  page=(*geometry);
+  if (page.width == 0)
+    page.width=bounding_box.width;
+  if (page.height == 0)
+    page.height=bounding_box.height;
+  if (((bounding_box.x-page.x) >= (ssize_t) page.width) ||
+      ((bounding_box.y-page.y) >= (ssize_t) page.height) ||
+      ((page.x-bounding_box.x) > (ssize_t) image->columns) ||
+      ((page.y-bounding_box.y) > (ssize_t) image->rows))
+    {
+      /*
+        Crop is not within virtual canvas, return 1 pixel transparent image.
+      */
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "GeometryDoesNotContainImage","`%s'",image->filename);
+      crop_image=CloneImage(image,1,1,MagickTrue,exception);
+      if (crop_image == (Image *) NULL)
+        return((Image *) NULL);
+      crop_image->background_color.alpha=(Quantum) TransparentAlpha;
+      (void) SetImageBackgroundColor(crop_image);
+      crop_image->page=bounding_box;
+      crop_image->page.x=(-1);
+      crop_image->page.y=(-1);
+      if (crop_image->dispose == BackgroundDispose)
+        crop_image->dispose=NoneDispose;
+      return(crop_image);
+    }
+  if ((page.x < 0) && (bounding_box.x >= 0))
+    {
+      page.width+=page.x-bounding_box.x;
+      page.x=0;
+    }
+  else
+    {
+      page.width-=bounding_box.x-page.x;
+      page.x-=bounding_box.x;
+      if (page.x < 0)
+        page.x=0;
+    }
+  if ((page.y < 0) && (bounding_box.y >= 0))
+    {
+      page.height+=page.y-bounding_box.y;
+      page.y=0;
+    }
+  else
+    {
+      page.height-=bounding_box.y-page.y;
+      page.y-=bounding_box.y;
+      if (page.y < 0)
+        page.y=0;
+    }
+  if ((size_t) (page.x+page.width) > image->columns)
+    page.width=image->columns-page.x;
+  if ((geometry->width != 0) && (page.width > geometry->width))
+    page.width=geometry->width;
+  if ((size_t) (page.y+page.height) > image->rows)
+    page.height=image->rows-page.y;
+  if ((geometry->height != 0) && (page.height > geometry->height))
+    page.height=geometry->height;
+  bounding_box.x+=page.x;
+  bounding_box.y+=page.y;
+  if ((page.width == 0) || (page.height == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "GeometryDoesNotContainImage","`%s'",image->filename);
+      return((Image *) NULL);
+    }
+  /*
+    Initialize crop image attributes.
+  */
+  crop_image=CloneImage(image,page.width,page.height,MagickTrue,exception);
+  if (crop_image == (Image *) NULL)
+    return((Image *) NULL);
+  crop_image->page.width=image->page.width;
+  crop_image->page.height=image->page.height;
+  if (((ssize_t) (bounding_box.x+bounding_box.width) > (ssize_t) image->page.width) ||
+      ((ssize_t) (bounding_box.y+bounding_box.height) > (ssize_t) image->page.height))
+    {
+      crop_image->page.width=bounding_box.width;
+      crop_image->page.height=bounding_box.height;
+    }
+  crop_image->page.x=bounding_box.x;
+  crop_image->page.y=bounding_box.y;
+  /*
+    Crop image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  crop_view=AcquireCacheView(crop_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) crop_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register size_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,page.x,page.y+y,crop_image->columns,
+      1,exception);
+    q=QueueCacheViewAuthenticPixels(crop_view,0,y,crop_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) crop_image->columns; x++)
+    {
+      SetPixelRed(crop_image,GetPixelRed(image,p),q);
+      SetPixelGreen(crop_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(crop_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(crop_image,GetPixelBlack(image,p),q);
+      SetPixelAlpha(crop_image,GetPixelAlpha(image,p),q);
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(crop_image,GetPixelIndex(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(crop_image);
+    }
+    if (SyncCacheViewAuthenticPixels(crop_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_CropImage)
+#endif
+        proceed=SetImageProgress(image,CropImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  crop_view=DestroyCacheView(crop_view);
+  image_view=DestroyCacheView(image_view);
+  crop_image->type=image->type;
+  if (status == MagickFalse)
+    crop_image=DestroyImage(crop_image);
+  return(crop_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C r o p I m a g e T o T i l e s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CropImageToTiles() will crop a single image, into a possible list of tiles.
+%  This may include a single sub-region of the image.  This basically applies
+%  all the normal geometry flags for Crop.
+%
+%      Image *CropImageToTiles(const Image *image,const RectangleInfo
+%         *crop_geometry, ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image The transformed image is returned as this parameter.
+%
+%    o crop_geometry: A crop geometry string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static inline ssize_t MagickRound(MagickRealType x)
+{
+  /*
+    Round the fraction to nearest integer.
+  */
+  if (x >= 0.0)
+    return((ssize_t) (x+0.5));
+  return((ssize_t) (x-0.5));
+}
+
+MagickExport Image *CropImageToTiles(const Image *image,
+  const char *crop_geometry, ExceptionInfo *exception)
+{
+  Image
+    *next,
+    *crop_image;
+
+  MagickStatusType
+    flags;
+
+  RectangleInfo
+    geometry;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+
+  crop_image=NewImageList();
+  next=NewImageList();
+  flags=ParseGravityGeometry(image,crop_geometry,&geometry,exception);
+
+  if ((flags & AreaValue) != 0)
+    {
+      /*
+      MagickBooleanType
+        proceed;
+
+      MagickProgressMonitor
+        progress_monitor;
+
+      MagickOffsetType
+        i;
+
+      MagickSizeType
+        number_images;
+      */
+      size_t
+        height,
+        width;
+
+      PointInfo
+        delta,
+        offset;
+
+      RectangleInfo
+        crop;
+
+      /*
+        Crop into NxM tiles (@ flag)
+      */
+      width=image->columns;
+      height=image->rows;
+      if (geometry.width == 0)
+        geometry.width=1;
+      if (geometry.height == 0)
+        geometry.height=1;
+      if ((flags & AspectValue) == 0)
+        {
+          width-=(geometry.x < 0 ? -1 : 1)*geometry.x;
+          height-=(geometry.y < 0 ? -1 : 1)*geometry.y;
+        }
+      else
+        {
+          width+=(geometry.x < 0 ? -1 : 1)*geometry.x;
+          height+=(geometry.y < 0 ? -1 : 1)*geometry.y;
+        }
+      delta.x=(double) width/geometry.width;
+      delta.y=(double) height/geometry.height;
+      /*proceed=MagickTrue;
+      i=0;
+      number_images=geometry.width*geometry.height;*/
+      for (offset.y=0; offset.y < (double) height; )
+      {
+        if ((flags & AspectValue) == 0)
+          {
+            crop.y=(ssize_t) MagickRound((MagickRealType)
+              (offset.y-(geometry.y > 0 ? 0 : geometry.y)));
+            offset.y+=delta.y;   /* increment now to find width */
+            crop.height=(size_t) MagickRound((MagickRealType)
+              (offset.y+(geometry.y < 0 ? 0 : geometry.y)));
+          }
+        else
+          {
+            crop.y=(ssize_t) MagickRound((MagickRealType)
+              (offset.y-(geometry.y > 0 ? geometry.y : 0)));
+            offset.y+=delta.y;  /* increment now to find width */
+            crop.height=(size_t) MagickRound((MagickRealType)
+              (offset.y+(geometry.y < 0 ? geometry.y : 0)));
+          }
+        crop.height-=crop.y;
+        crop.y+=image->page.y;
+        for (offset.x=0; offset.x < (double) width; )
+        {
+          /*progress_monitor=SetImageProgressMonitor(image,
+            (MagickProgressMonitor) NULL,image->client_data);*/
+          if ((flags & AspectValue) == 0)
+            {
+              crop.x=(ssize_t) MagickRound((MagickRealType)
+                (offset.x-(geometry.x > 0 ? 0 : geometry.x)));
+              offset.x+=+delta.x;  /* increment now to find height*/
+              crop.width=(size_t) MagickRound((MagickRealType)
+                (offset.x+(geometry.x < 0 ? 0 : geometry.x)));
+            }
+          else
+            {
+              crop.x=(ssize_t) MagickRound((MagickRealType) (offset.x-
+                (geometry.x > 0 ? geometry.x : 0)));
+              offset.x+=+delta.x;  /* increment now to find height */
+              crop.width=(size_t) MagickRound((MagickRealType)
+                (offset.x+(geometry.x < 0 ? geometry.x : 0)));
+            }
+          crop.width-=crop.x;
+          crop.x+=image->page.x;
+          next=CropImage(image,&crop,exception);
+          /*(void) SetImageProgressMonitor(image,progress_monitor,
+            image->client_data);
+          proceed=SetImageProgress(image,CropImageTag,i++,number_images);
+          if (proceed == MagickFalse)
+            break;
+          */
+          if (next == (Image *) NULL)
+            break;
+          /*(void) SetImageProgressMonitor(next,progress_monitor,
+            next->client_data);*/
+          AppendImageToList(&crop_image,next);
+        }
+        if (next == (Image *) NULL)
+          break;
+        /*if (proceed == MagickFalse)
+          break;*/
+      }
+      return(crop_image);
+    }
+
+  if (((geometry.width == 0) && (geometry.height == 0)) ||
+      ((flags & XValue) != 0) || ((flags & YValue) != 0))
+    {
+      /*
+        Crop a single region at +X+Y.
+      */
+      crop_image=CropImage(image,&geometry,exception);
+      if ((crop_image != (Image *) NULL) && ((flags & AspectValue) != 0))
+        {
+          crop_image->page.width=geometry.width;
+          crop_image->page.height=geometry.height;
+          crop_image->page.x-=geometry.x;
+          crop_image->page.y-=geometry.y;
+        }
+      return(crop_image);
+     }
+
+  if ((image->columns > geometry.width) ||
+      (image->rows > geometry.height))
+    {
+      /*
+      MagickBooleanType
+        proceed;
+
+      MagickProgressMonitor
+        progress_monitor;
+
+      MagickOffsetType
+        i;
+
+      MagickSizeType
+        number_images;
+      */
+      size_t
+        height,
+        width;
+
+      ssize_t
+        x,
+        y;
+
+      RectangleInfo
+        page;
+
+      /*
+        Crop into tiles of fixed size WxH.
+      */
+      page=image->page;
+      if (page.width == 0)
+        page.width=image->columns;
+      if (page.height == 0)
+        page.height=image->rows;
+      width=geometry.width;
+      if (width == 0)
+        width=page.width;
+      height=geometry.height;
+      if (height == 0)
+        height=page.height;
+      next=NewImageList();
+      /*proceed=MagickTrue;
+      i=0;
+      number_images=0;
+      for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
+        for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
+          number_images++;
+      */
+      for (y=0; y < (ssize_t) page.height; y+=(ssize_t) height)
+      {
+        for (x=0; x < (ssize_t) page.width; x+=(ssize_t) width)
+        {
+          /*progress_monitor=SetImageProgressMonitor(image,
+            (MagickProgressMonitor) NULL,image->client_data);*/
+          geometry.width=width;
+          geometry.height=height;
+          geometry.x=x;
+          geometry.y=y;
+          next=CropImage(image,&geometry,exception);
+          /*(void) SetImageProgressMonitor(image,progress_monitor,
+            image->client_data);
+          proceed=SetImageProgress(image,CropImageTag,i++,number_images);
+          if (proceed == MagickFalse)
+            break;
+          */
+          if (next == (Image *) NULL)
+            break;
+          /*(void) SetImageProgressMonitor(next,progress_monitor,
+            next->client_data);*/
+          AppendImageToList(&crop_image,next);
+        }
+        if (next == (Image *) NULL)
+          break;
+        /*if (proceed == MagickFalse)
+          break;*/
+
+      }
+      return(crop_image);
+    }
+  /*
+    Action of crop results in no change in image!
+    This is not an error so return a clone of the image!
+  */
+  return(CloneImage(image,0,0,MagickTrue,exception));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x c e r p t I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExcerptImage() returns a excerpt of the image as defined by the geometry.
+%
+%  The format of the ExcerptImage method is:
+%
+%      Image *ExcerptImage(const Image *image,const RectangleInfo *geometry,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o geometry: Define the region of the image to extend with members
+%      x, y, width, and height.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ExcerptImage(const Image *image,
+  const RectangleInfo *geometry,ExceptionInfo *exception)
+{
+#define ExcerptImageTag  "Excerpt/Image"
+
+  CacheView
+    *excerpt_view,
+    *image_view;
+
+  Image
+    *excerpt_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate excerpt image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(geometry != (const RectangleInfo *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  excerpt_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
+    exception);
+  if (excerpt_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Excerpt each row.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  excerpt_view=AcquireCacheView(excerpt_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) excerpt_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,geometry->x,geometry->y+y,
+      geometry->width,1,exception);
+    q=GetCacheViewAuthenticPixels(excerpt_view,0,y,excerpt_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) excerpt_image->columns; x++)
+    {
+      SetPixelRed(excerpt_image,GetPixelRed(image,p),q);
+      SetPixelGreen(excerpt_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(excerpt_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(excerpt_image,GetPixelBlack(image,p),q);
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(excerpt_image,GetPixelIndex(image,p),q);
+      SetPixelAlpha(excerpt_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(excerpt_image);
+    }
+    if (SyncCacheViewAuthenticPixels(excerpt_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_ExcerptImage)
+#endif
+        proceed=SetImageProgress(image,ExcerptImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  excerpt_view=DestroyCacheView(excerpt_view);
+  image_view=DestroyCacheView(image_view);
+  excerpt_image->type=image->type;
+  if (status == MagickFalse)
+    excerpt_image=DestroyImage(excerpt_image);
+  return(excerpt_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x t e n t I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExtentImage() extends the image as defined by the geometry, gravity, and
+%  image background color.  Set the (x,y) offset of the geometry to move the
+%  original image relative to the extended image.
+%
+%  The format of the ExtentImage method is:
+%
+%      Image *ExtentImage(const Image *image,const RectangleInfo *geometry,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o geometry: Define the region of the image to extend with members
+%      x, y, width, and height.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ExtentImage(const Image *image,
+  const RectangleInfo *geometry,ExceptionInfo *exception)
+{
+  Image
+    *extent_image;
+
+  /*
+    Allocate extent image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(geometry != (const RectangleInfo *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  extent_image=CloneImage(image,geometry->width,geometry->height,MagickTrue,
+    exception);
+  if (extent_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(extent_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&extent_image->exception);
+      extent_image=DestroyImage(extent_image);
+      return((Image *) NULL);
+    }
+  if (extent_image->background_color.alpha != OpaqueAlpha)
+    extent_image->matte=MagickTrue;
+  (void) SetImageBackgroundColor(extent_image);
+  (void) CompositeImage(extent_image,image->compose,image,-geometry->x,
+    -geometry->y);
+  return(extent_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F l i p I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FlipImage() creates a vertical mirror image by reflecting the pixels
+%  around the central x-axis.
+%
+%  The format of the FlipImage method is:
+%
+%      Image *FlipImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *FlipImage(const Image *image,ExceptionInfo *exception)
+{
+#define FlipImageTag  "Flip/Image"
+
+  CacheView
+    *flip_view,
+    *image_view;
+
+  Image
+    *flip_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    page;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  flip_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (flip_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Flip image.
+  */
+  status=MagickTrue;
+  progress=0;
+  page=image->page;
+  image_view=AcquireCacheView(image);
+  flip_view=AcquireCacheView(flip_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) flip_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(flip_view,0,(ssize_t) (flip_image->rows-y-
+      1),flip_image->columns,1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) flip_image->columns; x++)
+    {
+      SetPixelRed(flip_image,GetPixelRed(image,p),q);
+      SetPixelGreen(flip_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(flip_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(flip_image,GetPixelBlack(image,p),q);
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(flip_image,GetPixelIndex(image,p),q);
+      SetPixelAlpha(flip_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(flip_image);
+    }
+    if (SyncCacheViewAuthenticPixels(flip_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_FlipImage)
+#endif
+        proceed=SetImageProgress(image,FlipImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  flip_view=DestroyCacheView(flip_view);
+  image_view=DestroyCacheView(image_view);
+  flip_image->type=image->type;
+  if (page.height != 0)
+    page.y=(ssize_t) (page.height-flip_image->rows-page.y);
+  flip_image->page=page;
+  if (status == MagickFalse)
+    flip_image=DestroyImage(flip_image);
+  return(flip_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   F l o p I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  FlopImage() creates a horizontal mirror image by reflecting the pixels
+%  around the central y-axis.
+%
+%  The format of the FlopImage method is:
+%
+%      Image *FlopImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *FlopImage(const Image *image,ExceptionInfo *exception)
+{
+#define FlopImageTag  "Flop/Image"
+
+  CacheView
+    *flop_view,
+    *image_view;
+
+  Image
+    *flop_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    page;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  flop_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (flop_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Flop each row.
+  */
+  status=MagickTrue;
+  progress=0;
+  page=image->page;
+  image_view=AcquireCacheView(image);
+  flop_view=AcquireCacheView(flop_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+#endif
+  for (y=0; y < (ssize_t) flop_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(flop_view,0,y,flop_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    q+=GetPixelChannels(flop_image)*flop_image->columns;
+    for (x=0; x < (ssize_t) flop_image->columns; x++)
+    {
+      q-=GetPixelChannels(flop_image);
+      SetPixelRed(flop_image,GetPixelRed(image,p),q);
+      SetPixelGreen(flop_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(flop_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(flop_image,GetPixelBlack(image,p),q);
+      SetPixelAlpha(flop_image,GetPixelAlpha(image,p),q);
+      if (image->storage_class == PseudoClass)
+        SetPixelIndex(flop_image,GetPixelIndex(image,p),q);
+      p+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(flop_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_FlopImage)
+#endif
+        proceed=SetImageProgress(image,FlopImageTag,progress++,image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  flop_view=DestroyCacheView(flop_view);
+  image_view=DestroyCacheView(image_view);
+  flop_image->type=image->type;
+  if (page.width != 0)
+    page.x=(ssize_t) (page.width-flop_image->columns-page.x);
+  flop_image->page=page;
+  if (status == MagickFalse)
+    flop_image=DestroyImage(flop_image);
+  return(flop_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R o l l I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  RollImage() offsets an image as defined by x_offset and y_offset.
+%
+%  The format of the RollImage method is:
+%
+%      Image *RollImage(const Image *image,const ssize_t x_offset,
+%        const ssize_t y_offset,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o x_offset: the number of columns to roll in the horizontal direction.
+%
+%    o y_offset: the number of rows to roll in the vertical direction.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline MagickBooleanType CopyImageRegion(Image *destination,
+  const Image *source,const size_t columns,const size_t rows,
+  const ssize_t sx,const ssize_t sy,const ssize_t dx,const ssize_t dy,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *source_view,
+    *destination_view;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  status=MagickTrue;
+  source_view=AcquireCacheView(source);
+  destination_view=AcquireCacheView(destination);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    /*
+      Transfer scanline.
+    */
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(source_view,sx,sy+y,columns,1,exception);
+    q=GetCacheViewAuthenticPixels(destination_view,dx,dy+y,columns,1,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) columns; x++)
+    {
+      SetPixelRed(destination,GetPixelRed(source,p),q);
+      SetPixelGreen(destination,GetPixelGreen(source,p),q);
+      SetPixelBlue(destination,GetPixelBlue(source,p),q);
+      if (destination->colorspace == CMYKColorspace)
+        SetPixelBlack(destination,GetPixelBlack(source,p),q);
+      SetPixelAlpha(destination,GetPixelAlpha(source,p),q);
+      p+=GetPixelChannels(source);
+      q+=GetPixelChannels(destination);
+    }
+    sync=SyncCacheViewAuthenticPixels(destination_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+  }
+  destination_view=DestroyCacheView(destination_view);
+  source_view=DestroyCacheView(source_view);
+  return(status);
+}
+
+MagickExport Image *RollImage(const Image *image,const ssize_t x_offset,
+  const ssize_t y_offset,ExceptionInfo *exception)
+{
+#define RollImageTag  "Roll/Image"
+
+  Image
+    *roll_image;
+
+  MagickStatusType
+    status;
+
+  RectangleInfo
+    offset;
+
+  /*
+    Initialize roll image attributes.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  roll_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
+  if (roll_image == (Image *) NULL)
+    return((Image *) NULL);
+  offset.x=x_offset;
+  offset.y=y_offset;
+  while (offset.x < 0)
+    offset.x+=(ssize_t) image->columns;
+  while (offset.x >= (ssize_t) image->columns)
+    offset.x-=(ssize_t) image->columns;
+  while (offset.y < 0)
+    offset.y+=(ssize_t) image->rows;
+  while (offset.y >= (ssize_t) image->rows)
+    offset.y-=(ssize_t) image->rows;
+  /*
+    Roll image.
+  */
+  status=CopyImageRegion(roll_image,image,(size_t) offset.x,
+    (size_t) offset.y,(ssize_t) image->columns-offset.x,(ssize_t) image->rows-
+    offset.y,0,0,exception);
+  (void) SetImageProgress(image,RollImageTag,0,3);
+  status|=CopyImageRegion(roll_image,image,image->columns-offset.x,
+    (size_t) offset.y,0,(ssize_t) image->rows-offset.y,offset.x,0,
+    exception);
+  (void) SetImageProgress(image,RollImageTag,1,3);
+  status|=CopyImageRegion(roll_image,image,(size_t) offset.x,image->rows-
+    offset.y,(ssize_t) image->columns-offset.x,0,0,offset.y,exception);
+  (void) SetImageProgress(image,RollImageTag,2,3);
+  status|=CopyImageRegion(roll_image,image,image->columns-offset.x,image->rows-
+    offset.y,0,0,offset.x,offset.y,exception);
+  (void) SetImageProgress(image,RollImageTag,3,3);
+  roll_image->type=image->type;
+  if (status == MagickFalse)
+    roll_image=DestroyImage(roll_image);
+  return(roll_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S h a v e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShaveImage() shaves pixels from the image edges.  It allocates the memory
+%  necessary for the new Image structure and returns a pointer to the new
+%  image.
+%
+%  The format of the ShaveImage method is:
+%
+%      Image *ShaveImage(const Image *image,const RectangleInfo *shave_info,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o shave_image: Method ShaveImage returns a pointer to the shaved
+%      image.  A null image is returned if there is a memory shortage or
+%      if the image width or height is zero.
+%
+%    o image: the image.
+%
+%    o shave_info: Specifies a pointer to a RectangleInfo which defines the
+%      region of the image to crop.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ShaveImage(const Image *image,
+  const RectangleInfo *shave_info,ExceptionInfo *exception)
+{
+  Image
+    *shave_image;
+
+  RectangleInfo
+    geometry;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  if (((2*shave_info->width) >= image->columns) ||
+      ((2*shave_info->height) >= image->rows))
+    ThrowImageException(OptionWarning,"GeometryDoesNotContainImage");
+  SetGeometry(image,&geometry);
+  geometry.width-=2*shave_info->width;
+  geometry.height-=2*shave_info->height;
+  geometry.x=(ssize_t) shave_info->width+image->page.x;
+  geometry.y=(ssize_t) shave_info->height+image->page.y;
+  shave_image=CropImage(image,&geometry,exception);
+  if (shave_image == (Image *) NULL)
+    return((Image *) NULL);
+  shave_image->page.width-=2*shave_info->width;
+  shave_image->page.height-=2*shave_info->height;
+  shave_image->page.x-=(ssize_t) shave_info->width;
+  shave_image->page.y-=(ssize_t) shave_info->height;
+  return(shave_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S p l i c e I m a g e                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SpliceImage() splices a solid color into the image as defined by the
+%  geometry.
+%
+%  The format of the SpliceImage method is:
+%
+%      Image *SpliceImage(const Image *image,const RectangleInfo *geometry,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o geometry: Define the region of the image to splice with members
+%      x, y, width, and height.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *SpliceImage(const Image *image,
+  const RectangleInfo *geometry,ExceptionInfo *exception)
+{
+#define SpliceImageTag  "Splice/Image"
+
+  CacheView
+    *image_view,
+    *splice_view;
+
+  Image
+    *splice_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    splice_geometry;
+
+  ssize_t
+    y;
+
+  /*
+    Allocate splice image.
+  */
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(geometry != (const RectangleInfo *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  splice_geometry=(*geometry);
+  splice_image=CloneImage(image,image->columns+splice_geometry.width,
+    image->rows+splice_geometry.height,MagickTrue,exception);
+  if (splice_image == (Image *) NULL)
+    return((Image *) NULL);
+  if (SetImageStorageClass(splice_image,DirectClass) == MagickFalse)
+    {
+      InheritException(exception,&splice_image->exception);
+      splice_image=DestroyImage(splice_image);
+      return((Image *) NULL);
+    }
+  (void) SetImageBackgroundColor(splice_image);
+  /*
+    Respect image geometry.
+  */
+  switch (image->gravity)
+  {
+    default:
+    case UndefinedGravity:
+    case NorthWestGravity:
+      break;
+    case NorthGravity:
+    {
+      splice_geometry.x+=(ssize_t) splice_geometry.width/2;
+      break;
+    }
+    case NorthEastGravity:
+    {
+      splice_geometry.x+=(ssize_t) splice_geometry.width;
+      break;
+    }
+    case WestGravity:
+    {
+      splice_geometry.y+=(ssize_t) splice_geometry.width/2;
+      break;
+    }
+    case StaticGravity:
+    case CenterGravity:
+    {
+      splice_geometry.x+=(ssize_t) splice_geometry.width/2;
+      splice_geometry.y+=(ssize_t) splice_geometry.height/2;
+      break;
+    }
+    case EastGravity:
+    {
+      splice_geometry.x+=(ssize_t) splice_geometry.width;
+      splice_geometry.y+=(ssize_t) splice_geometry.height/2;
+      break;
+    }
+    case SouthWestGravity:
+    {
+      splice_geometry.y+=(ssize_t) splice_geometry.height;
+      break;
+    }
+    case SouthGravity:
+    {
+      splice_geometry.x+=(ssize_t) splice_geometry.width/2;
+      splice_geometry.y+=(ssize_t) splice_geometry.height;
+      break;
+    }
+    case SouthEastGravity:
+    {
+      splice_geometry.x+=(ssize_t) splice_geometry.width;
+      splice_geometry.y+=(ssize_t) splice_geometry.height;
+      break;
+    }
+  }
+  /*
+    Splice image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  splice_view=AcquireCacheView(splice_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) splice_geometry.y; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < splice_geometry.x; x++)
+    {
+      SetPixelRed(splice_image,GetPixelRed(image,p),q);
+      SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
+      SetPixelAlpha(splice_image,OpaqueAlpha,q);
+      if (image->matte != MagickFalse)
+        SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(splice_image);
+    }
+    for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
+      q+=GetPixelChannels(splice_image);
+    for ( ; x < (ssize_t) splice_image->columns; x++)
+    {
+      SetPixelRed(splice_image,GetPixelRed(image,p),q);
+      SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
+      SetPixelAlpha(splice_image,OpaqueAlpha,q);
+      if (image->matte != MagickFalse)
+        SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(splice_image);
+    }
+    if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransposeImage)
+#endif
+        proceed=SetImageProgress(image,SpliceImageTag,progress++,
+          splice_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=(ssize_t) (splice_geometry.y+splice_geometry.height);
+       y < (ssize_t) splice_image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y-(ssize_t) splice_geometry.height,
+      image->columns,1,exception);
+    if ((y < 0) || (y >= (ssize_t) splice_image->rows))
+      continue;
+    q=QueueCacheViewAuthenticPixels(splice_view,0,y,splice_image->columns,1,
+      exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < splice_geometry.x; x++)
+    {
+      SetPixelRed(splice_image,GetPixelRed(image,p),q);
+      SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
+      SetPixelAlpha(splice_image,OpaqueAlpha,q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
+      if (image->matte != MagickFalse)
+        SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(splice_image);
+    }
+    for ( ; x < (ssize_t) (splice_geometry.x+splice_geometry.width); x++)
+      q+=GetPixelChannels(splice_image);
+    for ( ; x < (ssize_t) splice_image->columns; x++)
+    {
+      SetPixelRed(splice_image,GetPixelRed(image,p),q);
+      SetPixelGreen(splice_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(splice_image,GetPixelBlue(image,p),q);
+      SetPixelAlpha(splice_image,OpaqueAlpha,q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(splice_image,GetPixelBlack(image,p),q);
+      if (image->matte != MagickFalse)
+        SetPixelAlpha(splice_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(splice_image);
+    }
+    if (SyncCacheViewAuthenticPixels(splice_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransposeImage)
+#endif
+        proceed=SetImageProgress(image,SpliceImageTag,progress++,
+          splice_image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  splice_view=DestroyCacheView(splice_view);
+  image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    splice_image=DestroyImage(splice_image);
+  return(splice_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s f o r m I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformImage() is a convenience method that behaves like ResizeImage() or
+%  CropImage() but accepts scaling and/or cropping information as a region
+%  geometry specification.  If the operation fails, the original image handle
+%  is left as is.
+%
+%  This should only be used for single images.
+%
+%  The format of the TransformImage method is:
+%
+%      MagickBooleanType TransformImage(Image **image,const char *crop_geometry,
+%        const char *image_geometry)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image The transformed image is returned as this parameter.
+%
+%    o crop_geometry: A crop geometry string.  This geometry defines a
+%      subregion of the image to crop.
+%
+%    o image_geometry: An image geometry string.  This geometry defines the
+%      final size of the image.
+%
+*/
+/*
+  DANGER: This function destroys what it assumes to be a single image list.
+  If the input image is part of a larger list, all other images in that list
+  will be simply 'lost', not destroyed.
+
+  Also if the crop generates a list of images only the first image is resized.
+  And finally if the crop succeeds and the resize failed, you will get a
+  cropped image, as well as a 'false' or 'failed' report.
+
+  This function and should probably be depreciated in favor of direct calls
+  to CropImageToTiles() or ResizeImage(), as appropriate.
+
+*/
+MagickExport MagickBooleanType TransformImage(Image **image,
+  const char *crop_geometry,const char *image_geometry)
+{
+  Image
+    *resize_image,
+    *transform_image;
+
+  MagickStatusType
+    flags;
+
+  RectangleInfo
+    geometry;
+
+  assert(image != (Image **) NULL);
+  assert((*image)->signature == MagickSignature);
+  if ((*image)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
+  transform_image=(*image);
+  if (crop_geometry != (const char *) NULL)
+    {
+      Image
+        *crop_image;
+
+      /*
+        Crop image to a user specified size.
+      */
+      crop_image=CropImageToTiles(*image,crop_geometry,&(*image)->exception);
+      if (crop_image == (Image *) NULL)
+        transform_image=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
+      else
+        {
+          transform_image=DestroyImage(transform_image);
+          transform_image=GetFirstImageInList(crop_image);
+        }
+      *image=transform_image;
+    }
+  if (image_geometry == (const char *) NULL)
+    return(MagickTrue);
+
+  /*
+    Scale image to a user specified size.
+  */
+  flags=ParseRegionGeometry(transform_image,image_geometry,&geometry,
+    &(*image)->exception);
+  (void) flags;
+  if ((transform_image->columns == geometry.width) &&
+      (transform_image->rows == geometry.height))
+    return(MagickTrue);
+  resize_image=ResizeImage(transform_image,geometry.width,geometry.height,
+    transform_image->filter,transform_image->blur,&(*image)->exception);
+  if (resize_image == (Image *) NULL)
+    return(MagickFalse);
+  transform_image=DestroyImage(transform_image);
+  transform_image=resize_image;
+  *image=transform_image;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s f o r m I m a g e s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransformImages() calls TransformImage() on each image of a sequence.
+%
+%  The format of the TransformImage method is:
+%
+%      MagickBooleanType TransformImages(Image **image,
+%        const char *crop_geometry,const char *image_geometry)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image The transformed image is returned as this parameter.
+%
+%    o crop_geometry: A crop geometry string.  This geometry defines a
+%      subregion of the image to crop.
+%
+%    o image_geometry: An image geometry string.  This geometry defines the
+%      final size of the image.
+%
+*/
+MagickExport MagickBooleanType TransformImages(Image **images,
+  const char *crop_geometry,const char *image_geometry)
+{
+  Image
+    *image,
+    **image_list,
+    *transform_images;
+
+  MagickStatusType
+    status;
+
+  register ssize_t
+    i;
+
+  assert(images != (Image **) NULL);
+  assert((*images)->signature == MagickSignature);
+  if ((*images)->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      (*images)->filename);
+  image_list=ImageListToArray(*images,&(*images)->exception);
+  if (image_list == (Image **) NULL)
+    return(MagickFalse);
+  status=MagickTrue;
+  transform_images=NewImageList();
+  for (i=0; image_list[i] != (Image *) NULL; i++)
+  {
+    image=image_list[i];
+    status|=TransformImage(&image,crop_geometry,image_geometry);
+    AppendImageToList(&transform_images,image);
+  }
+  *images=transform_images;
+  image_list=(Image **) RelinquishMagickMemory(image_list);
+  return(status != 0 ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s p o s e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransposeImage() creates a horizontal mirror image by reflecting the pixels
+%  around the central y-axis while rotating them by 90 degrees.
+%
+%  The format of the TransposeImage method is:
+%
+%      Image *TransposeImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *TransposeImage(const Image *image,ExceptionInfo *exception)
+{
+#define TransposeImageTag  "Transpose/Image"
+
+  CacheView
+    *image_view,
+    *transpose_view;
+
+  Image
+    *transpose_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    page;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  transpose_image=CloneImage(image,image->rows,image->columns,MagickTrue,
+    exception);
+  if (transpose_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Transpose image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  transpose_view=AcquireCacheView(transpose_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register const Quantum
+      *restrict p;
+
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-y-1,
+      image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(transpose_view,(ssize_t) (image->rows-y-1),
+      0,1,transpose_image->rows,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelRed(transpose_image,GetPixelRed(image,p),q);
+      SetPixelGreen(transpose_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(transpose_image,GetPixelBlue(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(transpose_image,GetPixelBlack(image,p),q);
+      SetPixelAlpha(transpose_image,GetPixelAlpha(image,p),q);
+      p+=GetPixelChannels(image);
+      q+=GetPixelChannels(transpose_image);
+    }
+    if (SyncCacheViewAuthenticPixels(transpose_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransposeImage)
+#endif
+        proceed=SetImageProgress(image,TransposeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  transpose_view=DestroyCacheView(transpose_view);
+  image_view=DestroyCacheView(image_view);
+  transpose_image->type=image->type;
+  page=transpose_image->page;
+  Swap(page.width,page.height);
+  Swap(page.x,page.y);
+  transpose_image->page=page;
+  if (status == MagickFalse)
+    transpose_image=DestroyImage(transpose_image);
+  return(transpose_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r a n s v e r s e I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TransverseImage() creates a vertical mirror image by reflecting the pixels
+%  around the central x-axis while rotating them by 270 degrees.
+%
+%  The format of the TransverseImage method is:
+%
+%      Image *TransverseImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *TransverseImage(const Image *image,ExceptionInfo *exception)
+{
+#define TransverseImageTag  "Transverse/Image"
+
+  CacheView
+    *image_view,
+    *transverse_view;
+
+  Image
+    *transverse_image;
+
+  MagickBooleanType
+    status;
+
+  MagickOffsetType
+    progress;
+
+  RectangleInfo
+    page;
+
+  ssize_t
+    y;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  transverse_image=CloneImage(image,image->rows,image->columns,MagickTrue,
+    exception);
+  if (transverse_image == (Image *) NULL)
+    return((Image *) NULL);
+  /*
+    Transverse image.
+  */
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  transverse_view=AcquireCacheView(transverse_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    MagickBooleanType
+      sync;
+
+    register const Quantum
+      *restrict p;
+
+    register ssize_t
+      x;
+
+    register Quantum
+      *restrict q;
+
+    if (status == MagickFalse)
+      continue;
+    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(transverse_view,(ssize_t) (image->rows-y-
+      1),0,1,transverse_image->rows,exception);
+    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
+      {
+        status=MagickFalse;
+        continue;
+      }
+    q+=GetPixelChannels(transverse_image)*image->columns;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      q-=GetPixelChannels(transverse_image);
+      SetPixelRed(transverse_image,GetPixelRed(image,p),q);
+      SetPixelGreen(transverse_image,GetPixelGreen(image,p),q);
+      SetPixelBlue(transverse_image,GetPixelBlue(image,p),q);
+      SetPixelAlpha(transverse_image,GetPixelAlpha(image,p),q);
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(transverse_image,GetPixelBlack(image,p),q);
+      p+=GetPixelChannels(image);
+    }
+    sync=SyncCacheViewAuthenticPixels(transverse_view,exception);
+    if (sync == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_TransverseImage)
+#endif
+        proceed=SetImageProgress(image,TransverseImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  transverse_view=DestroyCacheView(transverse_view);
+  image_view=DestroyCacheView(image_view);
+  transverse_image->type=image->type;
+  page=transverse_image->page;
+  Swap(page.width,page.height);
+  Swap(page.x,page.y);
+  if (page.width != 0)
+    page.x=(ssize_t) (page.width-transverse_image->columns-page.x);
+  if (page.height != 0)
+    page.y=(ssize_t) (page.height-transverse_image->rows-page.y);
+  transverse_image->page=page;
+  if (status == MagickFalse)
+    transverse_image=DestroyImage(transverse_image);
+  return(transverse_image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   T r i m I m a g e                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TrimImage() trims pixels from the image edges.  It allocates the memory
+%  necessary for the new Image structure and returns a pointer to the new
+%  image.
+%
+%  The format of the TrimImage method is:
+%
+%      Image *TrimImage(const Image *image,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *TrimImage(const Image *image,ExceptionInfo *exception)
+{
+  RectangleInfo
+    geometry;
+
+  assert(image != (const Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  geometry=GetImageBoundingBox(image,exception);
+  if ((geometry.width == 0) || (geometry.height == 0))
+    {
+      Image
+        *crop_image;
+
+      crop_image=CloneImage(image,1,1,MagickTrue,exception);
+      if (crop_image == (Image *) NULL)
+        return((Image *) NULL);
+      crop_image->background_color.alpha=(Quantum) TransparentAlpha;
+      (void) SetImageBackgroundColor(crop_image);
+      crop_image->page=image->page;
+      crop_image->page.x=(-1);
+      crop_image->page.y=(-1);
+      return(crop_image);
+    }
+  geometry.x+=image->page.x;
+  geometry.y+=image->page.y;
+  return(CropImage(image,&geometry,exception));
+}
diff --git a/MagickCore/transform.h b/MagickCore/transform.h
new file mode 100644
index 0000000..07098aa
--- /dev/null
+++ b/MagickCore/transform.h
@@ -0,0 +1,49 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image transform methods.
+*/
+#ifndef _MAGICKCORE_TRANSFORM_H
+#define _MAGICKCORE_TRANSFORM_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern MagickExport Image
+  *ChopImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *ConsolidateCMYKImages(const Image *,ExceptionInfo *),
+  *CropImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *CropImageToTiles(const Image *,const char *, ExceptionInfo *),
+  *ExcerptImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *ExtentImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *FlipImage(const Image *,ExceptionInfo *),
+  *FlopImage(const Image *,ExceptionInfo *),
+  *RollImage(const Image *,const ssize_t,const ssize_t,ExceptionInfo *),
+  *ShaveImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *SpliceImage(const Image *,const RectangleInfo *,ExceptionInfo *),
+  *TransposeImage(const Image *,ExceptionInfo *),
+  *TransverseImage(const Image *,ExceptionInfo *),
+  *TrimImage(const Image *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  TransformImage(Image **,const char *,const char *),
+  TransformImages(Image **,const char *,const char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/type.c b/MagickCore/type.c
new file mode 100644
index 0000000..2d3bd11
--- /dev/null
+++ b/MagickCore/type.c
@@ -0,0 +1,1386 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                        TTTTT  Y   Y  PPPP   EEEEE                           %
+%                          T     Y Y   P   P  E                               %
+%                          T      Y    PPPP   EEE                             %
+%                          T      Y    P      E                               %
+%                          T      Y    P      EEEEE                           %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Image Type Methods                         %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                                 May 2001                                    %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/client.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/draw.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/splay-tree.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/type.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xml-tree.h"
+#if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
+# include "fontconfig/fontconfig.h"
+#if (FC_VERSION < 20209)
+#undef FC_WEIGHT_LIGHT
+#define FC_WIDTH                  "width"    /* Int */
+#define FC_WIDTH_ULTRACONDENSED    50
+#define FC_WIDTH_EXTRACONDENSED    63
+#define FC_WIDTH_CONDENSED         75
+#define FC_WIDTH_SEMICONDENSED     87
+#define FC_WIDTH_NORMAL            100
+#define FC_WIDTH_SEMIEXPANDED      113
+#define FC_WIDTH_EXPANDED          125
+#define FC_WIDTH_EXTRAEXPANDED     150
+#define FC_WIDTH_ULTRAEXPANDED     200
+
+#define FC_WEIGHT_THIN             0
+#define FC_WEIGHT_EXTRALIGHT       40
+#define FC_WEIGHT_ULTRALIGHT       FC_WEIGHT_EXTRALIGHT
+#define FC_WEIGHT_LIGHT            50
+#define FC_WEIGHT_BOOK             75
+#define FC_WEIGHT_REGULAR          80
+#define FC_WEIGHT_NORMAL           FC_WEIGHT_REGULAR
+#define FC_WEIGHT_MEDIUM           100
+#define FC_WEIGHT_DEMIBOLD         180
+#define FC_WEIGHT_SEMIBOLD         FC_WEIGHT_DEMIBOLD
+#define FC_WEIGHT_BOLD             200
+#define FC_WEIGHT_EXTRABOLD        205
+#define FC_WEIGHT_ULTRABOLD        FC_WEIGHT_EXTRABOLD
+#define FC_WEIGHT_BLACK            210
+#define FC_WEIGHT_HEAVY            FC_WEIGHT_BLACK
+#endif
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+# include "MagickCore/nt-feature.h"
+#endif
+
+/*
+  Define declarations.
+*/
+#define MagickTypeFilename  "type.xml"
+
+/*
+  Declare type map.
+*/
+static const char
+  *TypeMap = (const char *)
+    "<?xml version=\"1.0\"?>"
+    "<typemap>"
+    "  <type stealth=\"True\" name=\"fixed\" family=\"helvetica\"/>"
+    "  <type stealth=\"True\" name=\"helvetica\" family=\"helvetica\"/>"
+    "</typemap>";
+
+/*
+  Static declarations.
+*/
+static SemaphoreInfo
+  *type_semaphore = (SemaphoreInfo *) NULL;
+
+static volatile MagickBooleanType
+  instantiate_type = MagickFalse;
+
+static SplayTreeInfo
+  *type_list = (SplayTreeInfo *) NULL;
+
+/*
+  Forward declarations.
+*/
+static MagickBooleanType
+  InitializeTypeList(ExceptionInfo *),
+  LoadTypeLists(const char *,ExceptionInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t T y p e I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetTypeInfo searches the type list for the specified name and if found
+%  returns attributes for that type.
+%
+%  The format of the GetTypeInfo method is:
+%
+%      const TypeInfo *GetTypeInfo(const char *name,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o name: the type name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport const TypeInfo *GetTypeInfo(const char *name,
+  ExceptionInfo *exception)
+{
+  assert(exception != (ExceptionInfo *) NULL);
+  if ((type_list == (SplayTreeInfo *) NULL) ||
+      (instantiate_type == MagickFalse))
+    if (InitializeTypeList(exception) == MagickFalse)
+      return((const TypeInfo *) NULL);
+  if ((type_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(type_list) == 0))
+    return((const TypeInfo *) NULL);
+  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
+    {
+      ResetSplayTreeIterator(type_list);
+      return((const TypeInfo *) GetNextValueInSplayTree(type_list));
+    }
+  return((const TypeInfo *) GetValueFromSplayTree(type_list,name));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   G e t T y p e I n f o B y F a m i l y                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetTypeInfoByFamily() searches the type list for the specified family and if
+%  found returns attributes for that type.
+%
+%  Type substitution and scoring algorithm contributed by Bob Friesenhahn.
+%
+%  The format of the GetTypeInfoByFamily method is:
+%
+%      const TypeInfo *GetTypeInfoByFamily(const char *family,
+%        const StyleType style,const StretchType stretch,
+%        const size_t weight,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o family: the type family.
+%
+%    o style: the type style.
+%
+%    o stretch: the type stretch.
+%
+%    o weight: the type weight.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline size_t MagickMax(const size_t x,
+  const size_t y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline size_t MagickMin(const size_t x,
+  const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport const TypeInfo *GetTypeInfoByFamily(const char *family,
+  const StyleType style,const StretchType stretch,const size_t weight,
+  ExceptionInfo *exception)
+{
+  typedef struct _Fontmap
+  {
+    const char
+      *name,
+      *substitute;
+  } Fontmap;
+
+  const TypeInfo
+    *type_info;
+
+  register const TypeInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    range;
+
+  static const Fontmap
+    fontmap[] =
+    {
+      { "fixed", "courier" },
+      { "modern","courier" },
+      { "monotype corsiva", "courier" },
+      { "news gothic", "helvetica" },
+      { "system", "courier" },
+      { "terminal", "courier" },
+      { "wingdings", "symbol" },
+      { NULL, NULL }
+    };
+
+  size_t
+    max_score,
+    score;
+
+  /*
+    Check for an exact type match.
+  */
+  (void) GetTypeInfo("*",exception);
+  if (type_list == (SplayTreeInfo *) NULL)
+    return((TypeInfo *) NULL);
+  LockSemaphoreInfo(type_semaphore);
+  ResetSplayTreeIterator(type_list);
+  type_info=(const TypeInfo *) NULL;
+  p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  while (p != (const TypeInfo *) NULL)
+  {
+    if (p->family == (char *) NULL)
+      {
+        p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+        continue;
+      }
+    if (family == (const char *) NULL)
+      {
+        if ((LocaleCompare(p->family,"arial") != 0) &&
+            (LocaleCompare(p->family,"helvetica") != 0))
+          {
+            p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+            continue;
+          }
+      }
+    else
+      if (LocaleCompare(p->family,family) != 0)
+        {
+          p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+          continue;
+        }
+    if ((style != UndefinedStyle) && (style != AnyStyle) && (p->style != style))
+      {
+        p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+        continue;
+      }
+    if ((stretch != UndefinedStretch) && (stretch != AnyStretch) &&
+        (p->stretch != stretch))
+      {
+        p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+        continue;
+      }
+    if ((weight != 0) && (p->weight != weight))
+      {
+        p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+        continue;
+      }
+    type_info=p;
+    break;
+  }
+  UnlockSemaphoreInfo(type_semaphore);
+  if (type_info != (const TypeInfo *) NULL)
+    return(type_info);
+  /*
+    Check for types in the same family.
+  */
+  max_score=0;
+  LockSemaphoreInfo(type_semaphore);
+  ResetSplayTreeIterator(type_list);
+  p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  while (p != (const TypeInfo *) NULL)
+  {
+    if (p->family == (char *) NULL)
+      {
+        p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+        continue;
+      }
+    if (family == (const char *) NULL)
+      {
+        if ((LocaleCompare(p->family,"arial") != 0) &&
+            (LocaleCompare(p->family,"helvetica") != 0))
+          {
+            p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+            continue;
+          }
+      }
+    else
+      if (LocaleCompare(p->family,family) != 0)
+        {
+          p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+          continue;
+        }
+    score=0;
+    if ((style == UndefinedStyle) || (style == AnyStyle) || (p->style == style))
+      score+=32;
+    else
+      if (((style == ItalicStyle) || (style == ObliqueStyle)) &&
+          ((p->style == ItalicStyle) || (p->style == ObliqueStyle)))
+        score+=25;
+    if (weight == 0)
+      score+=16;
+    else
+      score+=(16*(800-((ssize_t) MagickMax(MagickMin(weight,900),p->weight)-
+        (ssize_t) MagickMin(MagickMin(weight,900),p->weight))))/800;
+    if ((stretch == UndefinedStretch) || (stretch == AnyStretch))
+      score+=8;
+    else
+      {
+        range=(ssize_t) UltraExpandedStretch-(ssize_t) NormalStretch;
+        score+=(8*(range-((ssize_t) MagickMax(stretch,p->stretch)-
+          (ssize_t) MagickMin(stretch,p->stretch))))/range;
+      }
+    if (score > max_score)
+      {
+        max_score=score;
+        type_info=p;
+      }
+    p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  }
+  UnlockSemaphoreInfo(type_semaphore);
+  if (type_info != (const TypeInfo *) NULL)
+    return(type_info);
+  /*
+    Check for table-based substitution match.
+  */
+  for (i=0; fontmap[i].name != (char *) NULL; i++)
+  {
+    if (family == (const char *) NULL)
+      {
+        if ((LocaleCompare(fontmap[i].name,"arial") != 0) &&
+            (LocaleCompare(fontmap[i].name,"helvetica") != 0))
+          continue;
+      }
+    else
+      if (LocaleCompare(fontmap[i].name,family) != 0)
+        continue;
+    type_info=GetTypeInfoByFamily(fontmap[i].substitute,style,stretch,weight,
+      exception);
+    break;
+  }
+  if (type_info != (const TypeInfo *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),TypeError,
+        "FontSubstitutionRequired","`%s'",type_info->family);
+      return(type_info);
+    }
+  if (family != (const char *) NULL)
+    type_info=GetTypeInfoByFamily((const char *) NULL,style,stretch,weight,
+      exception);
+  return(type_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t T y p e I n f o L i s t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetTypeInfoList() returns any fonts that match the specified pattern.
+%
+%  The format of the GetTypeInfoList function is:
+%
+%      const TypeInfo **GetTypeInfoList(const char *pattern,
+%        size_t *number_fonts,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_fonts:  This integer returns the number of types in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int TypeInfoCompare(const void *x,const void *y)
+{
+  const TypeInfo
+    **p,
+    **q;
+
+  p=(const TypeInfo **) x,
+  q=(const TypeInfo **) y;
+  if (LocaleCompare((*p)->path,(*q)->path) == 0)
+    return(LocaleCompare((*p)->name,(*q)->name));
+  return(LocaleCompare((*p)->path,(*q)->path));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport const TypeInfo **GetTypeInfoList(const char *pattern,
+  size_t *number_fonts,ExceptionInfo *exception)
+{
+  const TypeInfo
+    **fonts;
+
+  register const TypeInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate type list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_fonts != (size_t *) NULL);
+  *number_fonts=0;
+  p=GetTypeInfo("*",exception);
+  if (p == (const TypeInfo *) NULL)
+    return((const TypeInfo **) NULL);
+  fonts=(const TypeInfo **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(type_list)+1UL,sizeof(*fonts));
+  if (fonts == (const TypeInfo **) NULL)
+    return((const TypeInfo **) NULL);
+  /*
+    Generate type list.
+  */
+  LockSemaphoreInfo(type_semaphore);
+  ResetSplayTreeIterator(type_list);
+  p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  for (i=0; p != (const TypeInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      fonts[i++]=p;
+    p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  }
+  UnlockSemaphoreInfo(type_semaphore);
+  qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeInfoCompare);
+  fonts[i]=(TypeInfo *) NULL;
+  *number_fonts=(size_t) i;
+  return(fonts);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t T y p e L i s t                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetTypeList() returns any fonts that match the specified pattern.
+%
+%  The format of the GetTypeList function is:
+%
+%      char **GetTypeList(const char *pattern,size_t *number_fonts,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_fonts:  This integer returns the number of fonts in the list.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int TypeCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport char **GetTypeList(const char *pattern,size_t *number_fonts,
+  ExceptionInfo *exception)
+{
+  char
+    **fonts;
+
+  register const TypeInfo
+    *p;
+
+  register ssize_t
+    i;
+
+  /*
+    Allocate type list.
+  */
+  assert(pattern != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
+  assert(number_fonts != (size_t *) NULL);
+  *number_fonts=0;
+  p=GetTypeInfo("*",exception);
+  if (p == (const TypeInfo *) NULL)
+    return((char **) NULL);
+  fonts=(char **) AcquireQuantumMemory((size_t)
+    GetNumberOfNodesInSplayTree(type_list)+1UL,sizeof(*fonts));
+  if (fonts == (char **) NULL)
+    return((char **) NULL);
+  /*
+    Generate type list.
+  */
+  LockSemaphoreInfo(type_semaphore);
+  ResetSplayTreeIterator(type_list);
+  p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  for (i=0; p != (const TypeInfo *) NULL; )
+  {
+    if ((p->stealth == MagickFalse) &&
+        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
+      fonts[i++]=ConstantString(p->name);
+    p=(const TypeInfo *) GetNextValueInSplayTree(type_list);
+  }
+  UnlockSemaphoreInfo(type_semaphore);
+  qsort((void *) fonts,(size_t) i,sizeof(*fonts),TypeCompare);
+  fonts[i]=(char *) NULL;
+  *number_fonts=(size_t) i;
+  return(fonts);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   I n i t i a l i z e T y p e L i s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InitializeTypeList() initializes the type list.
+%
+%  The format of the InitializeTypeList method is:
+%
+%      MagickBooleanType InitializeTypeList(ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+#if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
+MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_list,
+  ExceptionInfo *exception)
+{
+  char
+    extension[MaxTextExtent],
+    name[MaxTextExtent];
+
+  FcChar8
+    *family,
+    *file,
+    *style;
+
+  FcConfig
+    *font_config;
+
+  FcFontSet
+    *font_set;
+
+  FcObjectSet
+    *object_set;
+
+  FcPattern
+    *pattern;
+
+  FcResult
+    status;
+
+  int
+    slant,
+    width,
+    weight;
+
+  register ssize_t
+    i;
+
+  TypeInfo
+    *type_info;
+
+  /*
+    Load system fonts.
+  */
+  (void) exception;
+  font_config=FcInitLoadConfigAndFonts();
+  if (font_config == (FcConfig *) NULL)
+    return(MagickFalse);
+  font_set=(FcFontSet *) NULL;
+  object_set=FcObjectSetBuild(FC_FAMILY,FC_STYLE,FC_SLANT,FC_WIDTH,FC_WEIGHT,
+    FC_FILE,(char *) NULL);
+  if (object_set != (FcObjectSet *) NULL)
+    {
+      pattern=FcPatternCreate();
+      if (pattern != (FcPattern *) NULL)
+        {
+          font_set=FcFontList(0,pattern,object_set);
+          FcPatternDestroy(pattern);
+        }
+      FcObjectSetDestroy(object_set);
+    }
+  if (font_set == (FcFontSet *) NULL)
+    {
+      FcConfigDestroy(font_config);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) font_set->nfont; i++)
+  {
+    status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family);
+    if (status != FcResultMatch)
+      continue;
+    status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file);
+    if (status != FcResultMatch)
+      continue;
+    *extension='\0';
+    GetPathComponent((const char *) file,ExtensionPath,extension);
+    if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0))
+      continue;
+    type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
+    if (type_info == (TypeInfo *) NULL)
+      continue;
+    (void) ResetMagickMemory(type_info,0,sizeof(*type_info));
+    type_info->path=ConstantString("System Fonts");
+    type_info->signature=MagickSignature;
+    (void) CopyMagickString(name,(const char *) family,MaxTextExtent);
+    (void) ConcatenateMagickString(name," ",MaxTextExtent);
+    status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style);
+    if (status == FcResultMatch)
+      (void) ConcatenateMagickString(name,(const char *) style,MaxTextExtent);
+    type_info->name=ConstantString(name);
+    (void) SubstituteString(&type_info->name," ","-");
+    (void) SubstituteString(&type_info->name,"-L-","-");
+    (void) SubstituteString(&type_info->name,"semicondensed","SemiCondensed");
+    type_info->family=ConstantString((const char *) family);
+    (void) SubstituteString(&type_info->family," L","");
+    status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant);
+    type_info->style=NormalStyle;
+    if (slant == FC_SLANT_ITALIC)
+      type_info->style=ItalicStyle;
+    if (slant == FC_SLANT_OBLIQUE)
+      type_info->style=ObliqueStyle;
+    status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width);
+    type_info->stretch=NormalStretch;
+    if (width >= FC_WIDTH_ULTRACONDENSED)
+      type_info->stretch=UltraCondensedStretch;
+    if (width >= FC_WIDTH_EXTRACONDENSED)
+      type_info->stretch=ExtraCondensedStretch;
+    if (width >= FC_WIDTH_CONDENSED)
+      type_info->stretch=CondensedStretch;
+    if (width >= FC_WIDTH_SEMICONDENSED)
+      type_info->stretch=SemiCondensedStretch;
+    if (width >= FC_WIDTH_NORMAL)
+      type_info->stretch=NormalStretch;
+    if (width >= FC_WIDTH_SEMIEXPANDED)
+      type_info->stretch=SemiExpandedStretch;
+    if (width >= FC_WIDTH_EXPANDED)
+      type_info->stretch=ExpandedStretch;
+    if (width >= FC_WIDTH_EXTRAEXPANDED)
+      type_info->stretch=ExtraExpandedStretch;
+    if (width >= FC_WIDTH_ULTRAEXPANDED)
+      type_info->stretch=UltraExpandedStretch;
+    type_info->weight=400;
+    status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight);
+    if (weight >= FC_WEIGHT_THIN)
+      type_info->weight=100;
+    if (weight >= FC_WEIGHT_EXTRALIGHT)
+      type_info->weight=200;
+    if (weight >= FC_WEIGHT_LIGHT)
+      type_info->weight=300;
+    if (weight >= FC_WEIGHT_NORMAL)
+      type_info->weight=400;
+    if (weight >= FC_WEIGHT_MEDIUM)
+      type_info->weight=500;
+    if (weight >= FC_WEIGHT_DEMIBOLD)
+      type_info->weight=600;
+    if (weight >= FC_WEIGHT_BOLD)
+      type_info->weight=700;
+    if (weight >= FC_WEIGHT_EXTRABOLD)
+      type_info->weight=800;
+    if (weight >= FC_WEIGHT_BLACK)
+      type_info->weight=900;
+    type_info->glyphs=ConstantString((const char *) file);
+    (void) AddValueToSplayTree(type_list,type_info->name,type_info);
+  }
+  FcFontSetDestroy(font_set);
+  FcConfigDestroy(font_config);
+  return(MagickTrue);
+}
+#endif
+
+static MagickBooleanType InitializeTypeList(ExceptionInfo *exception)
+{
+  if ((type_list == (SplayTreeInfo *) NULL) &&
+      (instantiate_type == MagickFalse))
+    {
+      if (type_semaphore == (SemaphoreInfo *) NULL)
+        AcquireSemaphoreInfo(&type_semaphore);
+      LockSemaphoreInfo(type_semaphore);
+      if ((type_list == (SplayTreeInfo *) NULL) &&
+          (instantiate_type == MagickFalse))
+        {
+          (void) LoadTypeLists(MagickTypeFilename,exception);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+          (void) NTLoadTypeLists(type_list,exception);
+#endif
+#if defined(MAGICKCORE_FONTCONFIG_DELEGATE)
+          (void) LoadFontConfigFonts(type_list,exception);
+#endif
+          instantiate_type=MagickTrue;
+        }
+      UnlockSemaphoreInfo(type_semaphore);
+    }
+  return(type_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L i s t T y p e I n f o                                                    %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListTypeInfo() lists the fonts to a file.
+%
+%  The format of the ListTypeInfo method is:
+%
+%      MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o file:  An pointer to a FILE.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType ListTypeInfo(FILE *file,ExceptionInfo *exception)
+{
+  char
+    weight[MaxTextExtent];
+
+  const char
+    *family,
+    *glyphs,
+    *name,
+    *path,
+    *stretch,
+    *style;
+
+  const TypeInfo
+    **type_info;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_fonts;
+
+  if (file == (FILE *) NULL)
+    file=stdout;
+  number_fonts=0;
+  type_info=GetTypeInfoList("*",&number_fonts,exception);
+  if (type_info == (const TypeInfo **) NULL)
+    return(MagickFalse);
+  *weight='\0';
+  path=(const char *) NULL;
+  for (i=0; i < (ssize_t) number_fonts; i++)
+  {
+    if (type_info[i]->stealth != MagickFalse)
+      continue;
+    if (((path == (const char *) NULL) ||
+         (LocaleCompare(path,type_info[i]->path) != 0)) &&
+         (type_info[i]->path != (char *) NULL))
+      (void) FormatLocaleFile(file,"\nPath: %s\n",type_info[i]->path);
+    path=type_info[i]->path;
+    name="unknown";
+    if (type_info[i]->name != (char *) NULL)
+      name=type_info[i]->name;
+    family="unknown";
+    if (type_info[i]->family != (char *) NULL)
+      family=type_info[i]->family;
+    style=CommandOptionToMnemonic(MagickStyleOptions,type_info[i]->style);
+    stretch=CommandOptionToMnemonic(MagickStretchOptions,type_info[i]->stretch);
+    glyphs="unknown";
+    if (type_info[i]->glyphs != (char *) NULL)
+      glyphs=type_info[i]->glyphs;
+    (void) FormatLocaleString(weight,MaxTextExtent,"%.20g",(double)
+      type_info[i]->weight);
+    (void) FormatLocaleFile(file,"  Font: %s\n",name);
+    (void) FormatLocaleFile(file,"    family: %s\n",family);
+    (void) FormatLocaleFile(file,"    style: %s\n",style);
+    (void) FormatLocaleFile(file,"    stretch: %s\n",stretch);
+    (void) FormatLocaleFile(file,"    weight: %s\n",weight);
+    (void) FormatLocaleFile(file,"    glyphs: %s\n",glyphs);
+  }
+  (void) fflush(file);
+  type_info=(const TypeInfo **) RelinquishMagickMemory((void *) type_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   L o a d T y p e L i s t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadTypeList() loads the type configuration file which provides a mapping
+%  between type attributes and a type name.
+%
+%  The format of the LoadTypeList method is:
+%
+%      MagickBooleanType LoadTypeList(const char *xml,const char *filename,
+%        const size_t depth,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The type list in XML format.
+%
+%    o filename:  The type list filename.
+%
+%    o depth: depth of <include /> statements.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static void *DestroyTypeNode(void *type_info)
+{
+  register TypeInfo
+    *p;
+
+  p=(TypeInfo *) type_info;
+  if (p->path != (char *) NULL)
+    p->path=DestroyString(p->path);
+  if (p->name != (char *) NULL)
+    p->name=DestroyString(p->name);
+  if (p->description != (char *) NULL)
+    p->description=DestroyString(p->description);
+  if (p->family != (char *) NULL)
+    p->family=DestroyString(p->family);
+  if (p->encoding != (char *) NULL)
+    p->encoding=DestroyString(p->encoding);
+  if (p->foundry != (char *) NULL)
+    p->foundry=DestroyString(p->foundry);
+  if (p->format != (char *) NULL)
+    p->format=DestroyString(p->format);
+  if (p->metrics != (char *) NULL)
+    p->metrics=DestroyString(p->metrics);
+  if (p->glyphs != (char *) NULL)
+    p->glyphs=DestroyString(p->glyphs);
+  return(RelinquishMagickMemory(p));
+}
+
+static MagickBooleanType LoadTypeList(const char *xml,const char *filename,
+  const size_t depth,ExceptionInfo *exception)
+{
+  char
+    font_path[MaxTextExtent],
+    keyword[MaxTextExtent],
+    *token;
+
+  const char
+    *q;
+
+  MagickBooleanType
+    status;
+
+  TypeInfo
+    *type_info;
+
+  /*
+    Load the type map file.
+  */
+  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+    "Loading type configure file \"%s\" ...",filename);
+  if (xml == (const char *) NULL)
+    return(MagickFalse);
+  if (type_list == (SplayTreeInfo *) NULL)
+    {
+      type_list=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
+        DestroyTypeNode);
+      if (type_list == (SplayTreeInfo *) NULL)
+        {
+          ThrowFileException(exception,ResourceLimitError,
+            "MemoryAllocationFailed",filename);
+          return(MagickFalse);
+        }
+    }
+  status=MagickTrue;
+  type_info=(TypeInfo *) NULL;
+  token=AcquireString(xml);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  /*
+    Determine the Ghostscript font path.
+  */
+  *font_path='\0';
+  if (NTGhostscriptFonts(font_path,MaxTextExtent-2))
+    (void) ConcatenateMagickString(font_path,DirectorySeparator,MaxTextExtent);
+#endif
+  for (q=(char *) xml; *q != '\0'; )
+  {
+    /*
+      Interpret XML.
+    */
+    GetMagickToken(q,&q,token);
+    if (*token == '\0')
+      break;
+    (void) CopyMagickString(keyword,token,MaxTextExtent);
+    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
+      {
+        /*
+          Doctype element.
+        */
+        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleNCompare(keyword,"<!--",4) == 0)
+      {
+        /*
+          Comment element.
+        */
+        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
+          GetMagickToken(q,&q,token);
+        continue;
+      }
+    if (LocaleCompare(keyword,"<include") == 0)
+      {
+        /*
+          Include element.
+        */
+        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
+        {
+          (void) CopyMagickString(keyword,token,MaxTextExtent);
+          GetMagickToken(q,&q,token);
+          if (*token != '=')
+            continue;
+          GetMagickToken(q,&q,token);
+          if (LocaleCompare(keyword,"file") == 0)
+            {
+              if (depth > 200)
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
+              else
+                {
+                  char
+                    path[MaxTextExtent],
+                    *xml;
+
+                  ExceptionInfo
+                    *sans_exception;
+
+                  *path='\0';
+                  GetPathComponent(filename,HeadPath,path);
+                  if (*path != '\0')
+                    (void) ConcatenateMagickString(path,DirectorySeparator,
+                      MaxTextExtent);
+                  if (*token == *DirectorySeparator)
+                    (void) CopyMagickString(path,token,MaxTextExtent);
+                  else
+                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
+                  sans_exception=AcquireExceptionInfo();
+                  xml=FileToString(path,~0,sans_exception);
+                  sans_exception=DestroyExceptionInfo(sans_exception);
+                  if (xml != (char *) NULL)
+                    {
+                      status=LoadTypeList(xml,path,depth+1,exception);
+                      xml=(char *) RelinquishMagickMemory(xml);
+                    }
+                }
+            }
+        }
+        continue;
+      }
+    if (LocaleCompare(keyword,"<type") == 0)
+      {
+        /*
+          Type element.
+        */
+        type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
+        if (type_info == (TypeInfo *) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        (void) ResetMagickMemory(type_info,0,sizeof(*type_info));
+        type_info->path=ConstantString(filename);
+        type_info->signature=MagickSignature;
+        continue;
+      }
+    if (type_info == (TypeInfo *) NULL)
+      continue;
+    if (LocaleCompare(keyword,"/>") == 0)
+      {
+        status=AddValueToSplayTree(type_list,type_info->name,type_info);
+        if (status == MagickFalse)
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
+        type_info=(TypeInfo *) NULL;
+      }
+    GetMagickToken(q,(const char **) NULL,token);
+    if (*token != '=')
+      continue;
+    GetMagickToken(q,&q,token);
+    GetMagickToken(q,&q,token);
+    switch (*keyword)
+    {
+      case 'E':
+      case 'e':
+      {
+        if (LocaleCompare((char *) keyword,"encoding") == 0)
+          {
+            type_info->encoding=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'F':
+      case 'f':
+      {
+        if (LocaleCompare((char *) keyword,"face") == 0)
+          {
+            type_info->face=StringToUnsignedLong(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"family") == 0)
+          {
+            type_info->family=ConstantString(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"format") == 0)
+          {
+            type_info->format=ConstantString(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"foundry") == 0)
+          {
+            type_info->foundry=ConstantString(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"fullname") == 0)
+          {
+            type_info->description=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'G':
+      case 'g':
+      {
+        if (LocaleCompare((char *) keyword,"glyphs") == 0)
+          {
+            char
+              *path;
+
+            path=ConstantString(token);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+            if (strchr(path,'@') != (char *) NULL)
+              SubstituteString(&path,"@ghostscript_font_path@",font_path);
+#endif
+            if (IsPathAccessible(path) == MagickFalse)
+              {
+                /*
+                  Relative path.
+                */
+                path=DestroyString(path);
+                GetPathComponent(filename,HeadPath,font_path);
+                (void) ConcatenateMagickString(font_path,DirectorySeparator,
+                  MaxTextExtent);
+                (void) ConcatenateMagickString(font_path,token,MaxTextExtent);
+                path=ConstantString(font_path);
+                if (IsPathAccessible(path) == MagickFalse)
+                  {
+                    path=DestroyString(path);
+                    path=ConstantString(token);
+                  }
+              }
+            type_info->glyphs=path;
+            break;
+          }
+        break;
+      }
+      case 'M':
+      case 'm':
+      {
+        if (LocaleCompare((char *) keyword,"metrics") == 0)
+          {
+            char
+              *path;
+
+            path=ConstantString(token);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+            if (strchr(path,'@') != (char *) NULL)
+              SubstituteString(&path,"@ghostscript_font_path@",font_path);
+#endif
+            if (IsPathAccessible(path) == MagickFalse)
+              {
+                /*
+                  Relative path.
+                */
+                path=DestroyString(path);
+                GetPathComponent(filename,HeadPath,font_path);
+                (void) ConcatenateMagickString(font_path,DirectorySeparator,
+                  MaxTextExtent);
+                (void) ConcatenateMagickString(font_path,token,MaxTextExtent);
+                path=ConstantString(font_path);
+              }
+            type_info->metrics=path;
+            break;
+          }
+        break;
+      }
+      case 'N':
+      case 'n':
+      {
+        if (LocaleCompare((char *) keyword,"name") == 0)
+          {
+            type_info->name=ConstantString(token);
+            break;
+          }
+        break;
+      }
+      case 'S':
+      case 's':
+      {
+        if (LocaleCompare((char *) keyword,"stealth") == 0)
+          {
+            type_info->stealth=IsMagickTrue(token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"stretch") == 0)
+          {
+            type_info->stretch=(StretchType) ParseCommandOption(
+              MagickStretchOptions,MagickFalse,token);
+            break;
+          }
+        if (LocaleCompare((char *) keyword,"style") == 0)
+          {
+            type_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
+              MagickFalse,token);
+            break;
+          }
+        break;
+      }
+      case 'W':
+      case 'w':
+      {
+        if (LocaleCompare((char *) keyword,"weight") == 0)
+          {
+            type_info->weight=StringToUnsignedLong(token);
+            if (LocaleCompare(token,"bold") == 0)
+              type_info->weight=700;
+            if (LocaleCompare(token,"normal") == 0)
+              type_info->weight=400;
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  token=(char *) RelinquishMagickMemory(token);
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  L o a d T y p e L i s t s                                                  %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  LoadTypeList() loads one or more type configuration files which provides a
+%  mapping between type attributes and a type name.
+%
+%  The format of the LoadTypeLists method is:
+%
+%      MagickBooleanType LoadTypeLists(const char *filename,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o filename: the font file name.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+static MagickBooleanType LoadTypeLists(const char *filename,
+  ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
+  return(LoadTypeList(TypeMap,"built-in",0,exception));
+#else
+  char
+    *font_path,
+    path[MaxTextExtent];
+
+  const StringInfo
+    *option;
+
+  LinkedListInfo
+    *options;
+
+  MagickStatusType
+    status;
+
+  status=MagickFalse;
+  *path='\0';
+  options=GetConfigureOptions(filename,exception);
+  option=(const StringInfo *) GetNextValueInLinkedList(options);
+  while (option != (const StringInfo *) NULL)
+  {
+    (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent);
+    status|=LoadTypeList((const char *) GetStringInfoDatum(option),
+      GetStringInfoPath(option),0,exception);
+    option=(const StringInfo *) GetNextValueInLinkedList(options);
+  }
+  options=DestroyConfigureOptions(options);
+  font_path=GetEnvironmentValue("MAGICK_FONT_PATH");
+  if (font_path != (char *) NULL)
+    {
+      char
+        *option;
+
+      /*
+        Search MAGICK_FONT_PATH.
+      */
+      (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",font_path,
+        DirectorySeparator,filename);
+      option=FileToString(path,~0,exception);
+      if (option != (void *) NULL)
+        {
+          status|=LoadTypeList(option,path,0,exception);
+          option=DestroyString(option);
+        }
+      font_path=DestroyString(font_path);
+    }
+  if ((type_list == (SplayTreeInfo *) NULL) ||
+      (GetNumberOfNodesInSplayTree(type_list) == 0))
+    status|=LoadTypeList(TypeMap,"built-in",0,exception);
+  return(status != 0 ? MagickTrue : MagickFalse);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   T y p e C o m p o n e n t G e n e s i s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TypeComponentGenesis() instantiates the type component.
+%
+%  The format of the TypeComponentGenesis method is:
+%
+%      MagickBooleanType TypeComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType TypeComponentGenesis(void)
+{
+  AcquireSemaphoreInfo(&type_semaphore);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   T y p e C o m p o n e n t T e r m i n u s                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  TypeComponentTerminus() destroy type component.
+%
+%  The format of the TypeComponentTerminus method is:
+%
+%      void TypeComponentTerminus(void)
+%
+*/
+MagickExport void TypeComponentTerminus(void)
+{
+  if (type_semaphore == (SemaphoreInfo *) NULL)
+    AcquireSemaphoreInfo(&type_semaphore);
+  LockSemaphoreInfo(type_semaphore);
+  if (type_list != (SplayTreeInfo *) NULL)
+    type_list=DestroySplayTree(type_list);
+  instantiate_type=MagickFalse;
+  UnlockSemaphoreInfo(type_semaphore);
+  DestroySemaphoreInfo(&type_semaphore);
+}
diff --git a/MagickCore/type.h b/MagickCore/type.h
new file mode 100644
index 0000000..9076e8e
--- /dev/null
+++ b/MagickCore/type.h
@@ -0,0 +1,103 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore image type methods.
+*/
+#ifndef _MAGICKCORE_TYPE_H
+#define _MAGICKCORE_TYPE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedStretch,
+  NormalStretch,
+  UltraCondensedStretch,
+  ExtraCondensedStretch,
+  CondensedStretch,
+  SemiCondensedStretch,
+  SemiExpandedStretch,
+  ExpandedStretch,
+  ExtraExpandedStretch,
+  UltraExpandedStretch,
+  AnyStretch
+} StretchType;
+
+typedef enum
+{
+  UndefinedStyle,
+  NormalStyle,
+  ItalicStyle,
+  ObliqueStyle,
+  AnyStyle
+} StyleType;
+
+typedef struct _TypeInfo
+{
+  size_t
+    face;
+
+  char
+    *path,
+    *name,
+    *description,
+    *family;
+
+  StyleType
+    style;
+
+  StretchType
+    stretch;
+
+  size_t
+    weight;
+
+  char
+    *encoding,
+    *foundry,
+    *format,
+    *metrics,
+    *glyphs;
+
+  MagickBooleanType
+    stealth;
+
+  size_t
+    signature;
+} TypeInfo;
+
+extern MagickExport char
+  **GetTypeList(const char *,size_t *,ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  ListTypeInfo(FILE *,ExceptionInfo *),
+  TypeComponentGenesis(void);
+
+extern MagickExport const TypeInfo
+  *GetTypeInfo(const char *,ExceptionInfo *),
+  *GetTypeInfoByFamily(const char *,const StyleType,const StretchType,
+    const size_t,ExceptionInfo *),
+  **GetTypeInfoList(const char *,size_t *,ExceptionInfo *);
+
+MagickExport void
+  TypeComponentTerminus(void);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/utility.c b/MagickCore/utility.c
new file mode 100644
index 0000000..6b8867f
--- /dev/null
+++ b/MagickCore/utility.c
@@ -0,0 +1,2102 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%             U   U  TTTTT  IIIII  L      IIIII  TTTTT  Y   Y                 %
+%             U   U    T      I    L        I      T     Y Y                  %
+%             U   U    T      I    L        I      T      Y                   %
+%             U   U    T      I    L        I      T      Y                   %
+%              UUU     T    IIIII  LLLLL  IIIII    T      Y                   %
+%                                                                             %
+%                                                                             %
+%                       MagickCore Utility Methods                            %
+%                                                                             %
+%                             Software Design                                 %
+%                               John Cristy                                   %
+%                              January 1993                                   %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/property.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/color.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/list.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/signature-private.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#if defined(MAGICKCORE_HAVE_PROCESS_H)
+#include <process.h>
+#endif
+#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H)
+#include <mach-o/dyld.h>
+#endif
+
+/*
+  Static declarations.
+*/
+static const char
+  Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*
+  Forward declaration.
+*/
+static int
+  IsPathDirectory(const char *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e U n i q u e F i l e n a m e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireUniqueFilename() replaces the contents of path by a unique path name.
+%
+%  The format of the AcquireUniqueFilename method is:
+%
+%      MagickBooleanType AcquireUniqueFilename(char *path)
+%
+%  A description of each parameter follows.
+%
+%   o  path:  Specifies a pointer to an array of characters.  The unique path
+%      name is returned in this array.
+%
+*/
+MagickExport MagickBooleanType AcquireUniqueFilename(char *path)
+{
+  int
+    file;
+
+  file=AcquireUniqueFileResource(path);
+  if (file == -1)
+    return(MagickFalse);
+  file=close(file)-1;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A c q u i r e U n i q u e S ym b o l i c L i n k                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified
+%  source path and returns MagickTrue on success otherwise MagickFalse.  If the
+%  symlink() method fails or is not available, a unique file name is generated
+%  and the source file copied to it.  When you are finished with the file, use
+%  RelinquishUniqueFilename() to destroy it.
+%
+%  The format of the AcquireUniqueSymbolicLink method is:
+%
+%      MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
+%        char destination)
+%
+%  A description of each parameter follows.
+%
+%   o  source:  the source path.
+%
+%   o  destination:  the destination path.
+%
+*/
+
+static inline size_t MagickMin(const size_t x,const size_t y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
+  char *destination)
+{
+  int
+    destination_file,
+    source_file;
+
+  size_t
+    length,
+    quantum;
+
+  ssize_t
+    count;
+
+  struct stat
+    attributes;
+
+  unsigned char
+    *buffer;
+
+  assert(source != (const char *) NULL);
+  assert(destination != (char *) NULL);
+#if defined(MAGICKCORE_HAVE_SYMLINK)
+  (void) AcquireUniqueFilename(destination);
+  (void) RelinquishUniqueFileResource(destination);
+  if (*source == *DirectorySeparator)
+    {
+      if (symlink(source,destination) == 0)
+        return(MagickTrue);
+    }
+  else
+    {
+      char
+        path[MaxTextExtent];
+
+      *path='\0';
+      if (getcwd(path,MaxTextExtent) == (char *) NULL)
+        return(MagickFalse);
+      (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent);
+      (void) ConcatenateMagickString(path,source,MaxTextExtent);
+      if (symlink(path,destination) == 0)
+        return(MagickTrue);
+    }
+#endif
+  destination_file=AcquireUniqueFileResource(destination);
+  if (destination_file == -1)
+    return(MagickFalse);
+  source_file=open(source,O_RDONLY | O_BINARY);
+  if (source_file == -1)
+    {
+      (void) close(destination_file);
+      (void) RelinquishUniqueFileResource(destination);
+      return(MagickFalse);
+    }
+  quantum=(size_t) MagickMaxBufferExtent;
+  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
+    quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
+  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
+  if (buffer == (unsigned char *) NULL)
+    {
+      (void) close(source_file);
+      (void) close(destination_file);
+      (void) RelinquishUniqueFileResource(destination);
+      return(MagickFalse);
+    }
+  for (length=0; ; )
+  {
+    count=(ssize_t) read(source_file,buffer,quantum);
+    if (count <= 0)
+      break;
+    length=(size_t) count;
+    count=(ssize_t) write(destination_file,buffer,length);
+    if ((size_t) count != length)
+      {
+        (void) close(destination_file);
+        (void) close(source_file);
+        buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+        (void) RelinquishUniqueFileResource(destination);
+        return(MagickFalse);
+      }
+  }
+  (void) close(destination_file);
+  (void) close(source_file);
+  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  A p p e n d I m a g e F o r m a t                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AppendImageFormat() appends the image format type to the filename.  If an
+%  extension to the file already exists, it is first removed.
+%
+%  The format of the AppendImageFormat method is:
+%
+%      void AppendImageFormat(const char *format,char *filename)
+%
+%  A description of each parameter follows.
+%
+%   o  format:  Specifies a pointer to an array of characters.  This the
+%      format of the image.
+%
+%   o  filename:  Specifies a pointer to an array of characters.  The unique
+%      file name is returned in this array.
+%
+*/
+MagickExport void AppendImageFormat(const char *format,char *filename)
+{
+  char
+    extension[MaxTextExtent],
+    root[MaxTextExtent];
+
+  assert(format != (char *) NULL);
+  assert(filename != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  if ((*format == '\0') || (*filename == '\0'))
+    return;
+  if (LocaleCompare(filename,"-") == 0)
+    {
+      char
+        message[MaxTextExtent];
+
+      (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",format,filename);
+      (void) CopyMagickString(filename,message,MaxTextExtent);
+      return;
+    }
+  GetPathComponent(filename,ExtensionPath,extension);
+  if ((LocaleCompare(extension,"Z") == 0) ||
+      (LocaleCompare(extension,"bz2") == 0) ||
+      (LocaleCompare(extension,"gz") == 0) ||
+      (LocaleCompare(extension,"wmz") == 0) ||
+      (LocaleCompare(extension,"svgz") == 0))
+    {
+      GetPathComponent(filename,RootPath,root);
+      (void) CopyMagickString(filename,root,MaxTextExtent);
+      GetPathComponent(filename,RootPath,root);
+      (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s.%s",root,format,
+        extension);
+      return;
+    }
+  GetPathComponent(filename,RootPath,root);
+  (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s",root,format);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   B a s e 6 4 D e c o d e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Base64Decode() decodes Base64-encoded text and returns its binary
+%  equivalent.  NULL is returned if the text is not valid Base64 data, or a
+%  memory allocation failure occurs.
+%
+%  The format of the Base64Decode method is:
+%
+%      unsigned char *Base64Decode(const char *source,length_t *length)
+%
+%  A description of each parameter follows:
+%
+%    o source:  A pointer to a Base64-encoded string.
+%
+%    o length: the number of bytes decoded.
+%
+*/
+MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
+{
+  int
+    state;
+
+  register const char
+    *p,
+    *q;
+
+  register size_t
+    i;
+
+  unsigned char
+    *decode;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(source != (char *) NULL);
+  assert(length != (size_t *) NULL);
+  *length=0;
+  decode=(unsigned char *) AcquireQuantumMemory(strlen(source)/4+4,
+    3*sizeof(*decode));
+  if (decode == (unsigned char *) NULL)
+    return((unsigned char *) NULL);
+  i=0;
+  state=0;
+  for (p=source; *p != '\0'; p++)
+  {
+    if (isspace((int) ((unsigned char) *p)) != 0)
+      continue;
+    if (*p == '=')
+      break;
+    q=strchr(Base64,*p);
+    if (q == (char *) NULL)
+      {
+        decode=(unsigned char *) RelinquishMagickMemory(decode);
+        return((unsigned char *) NULL);  /* non-Base64 character */
+      }
+    switch (state)
+    {
+      case 0:
+      {
+        decode[i]=(q-Base64) << 2;
+        state++;
+        break;
+      }
+      case 1:
+      {
+        decode[i++]|=(q-Base64) >> 4;
+        decode[i]=((q-Base64) & 0x0f) << 4;
+        state++;
+        break;
+      }
+      case 2:
+      {
+        decode[i++]|=(q-Base64) >> 2;
+        decode[i]=((q-Base64) & 0x03) << 6;
+        state++;
+        break;
+      }
+      case 3:
+      {
+        decode[i++]|=(q-Base64);
+        state=0;
+        break;
+      }
+    }
+  }
+  /*
+    Verify Base-64 string has proper terminal characters.
+  */
+  if (*p != '=')
+    {
+      if (state != 0)
+        {
+          decode=(unsigned char *) RelinquishMagickMemory(decode);
+          return((unsigned char *) NULL);
+        }
+    }
+  else
+    {
+      p++;
+      switch (state)
+      {
+        case 0:
+        case 1:
+        {
+          /*
+            Unrecognized '=' character.
+          */
+          decode=(unsigned char *) RelinquishMagickMemory(decode);
+          return((unsigned char *) NULL);
+        }
+        case 2:
+        {
+          for ( ; *p != '\0'; p++)
+            if (isspace((int) ((unsigned char) *p)) == 0)
+              break;
+          if (*p != '=')
+            {
+              decode=(unsigned char *) RelinquishMagickMemory(decode);
+              return((unsigned char *) NULL);
+            }
+          p++;
+        }
+        case 3:
+        {
+          for ( ; *p != '\0'; p++)
+            if (isspace((int) ((unsigned char) *p)) == 0)
+              {
+                decode=(unsigned char *) RelinquishMagickMemory(decode);
+                return((unsigned char *) NULL);
+              }
+          if ((int) decode[i] != 0)
+            {
+              decode=(unsigned char *) RelinquishMagickMemory(decode);
+              return((unsigned char *) NULL);
+            }
+        }
+      }
+    }
+  *length=i;
+  return(decode);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   B a s e 6 4 E n c o d e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  Base64Encode() encodes arbitrary binary data to Base64 encoded format as
+%  described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
+%  returns the result as a null-terminated ASCII string.  NULL is returned if
+%  a memory allocation failure occurs.
+%
+%  The format of the Base64Encode method is:
+%
+%      char *Base64Encode(const unsigned char *blob,const size_t blob_length,
+%        size_t *encode_length)
+%
+%  A description of each parameter follows:
+%
+%    o blob:  A pointer to binary data to encode.
+%
+%    o blob_length: the number of bytes to encode.
+%
+%    o encode_length:  The number of bytes encoded.
+%
+*/
+MagickExport char *Base64Encode(const unsigned char *blob,
+  const size_t blob_length,size_t *encode_length)
+{
+  char
+    *encode;
+
+  register const unsigned char
+    *p;
+
+  register size_t
+    i;
+
+  size_t
+    remainder;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(blob != (const unsigned char *) NULL);
+  assert(blob_length != 0);
+  assert(encode_length != (size_t *) NULL);
+  *encode_length=0;
+  encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
+  if (encode == (char *) NULL)
+    return((char *) NULL);
+  i=0;
+  for (p=blob; p < (blob+blob_length-2); p+=3)
+  {
+    encode[i++]=Base64[(int) (*p >> 2)];
+    encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
+    encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
+    encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
+  }
+  remainder=blob_length % 3;
+  if (remainder != 0)
+    {
+      ssize_t
+        j;
+
+      unsigned char
+        code[3];
+
+      code[0]='\0';
+      code[1]='\0';
+      code[2]='\0';
+      for (j=0; j < (ssize_t) remainder; j++)
+        code[j]=(*p++);
+      encode[i++]=Base64[(int) (code[0] >> 2)];
+      encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
+      if (remainder == 1)
+        encode[i++]='=';
+      else
+        encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
+      encode[i++]='=';
+    }
+  *encode_length=i;
+  encode[i++]='\0';
+  return(encode);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C h o p P a t h C o m p o n e n t s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ChopPathComponents() removes the number of specified file components from a
+%  path.
+%
+%  The format of the ChopPathComponents method is:
+%
+%      ChopPathComponents(char *path,size_t components)
+%
+%  A description of each parameter follows:
+%
+%    o path:  The path.
+%
+%    o components:  The number of components to chop.
+%
+*/
+MagickExport void ChopPathComponents(char *path,const size_t components)
+{
+  register ssize_t
+    i;
+
+  for (i=0; i < (ssize_t) components; i++)
+    GetPathComponent(path,HeadPath,path);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x p a n d F i l e n a m e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExpandFilename() expands '~' in a path.
+%
+%  The format of the ExpandFilename function is:
+%
+%      ExpandFilename(char *path)
+%
+%  A description of each parameter follows:
+%
+%    o path: Specifies a pointer to a character array that contains the
+%      path.
+%
+*/
+MagickExport void ExpandFilename(char *path)
+{
+  char
+    expand_path[MaxTextExtent];
+
+  if (path == (char *) NULL)
+    return;
+  if (*path != '~')
+    return;
+  (void) CopyMagickString(expand_path,path,MaxTextExtent);
+  if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
+    {
+      char
+        *home;
+
+      /*
+        Substitute ~ with $HOME.
+      */
+      (void) CopyMagickString(expand_path,".",MaxTextExtent);
+      (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
+      home=GetEnvironmentValue("HOME");
+      if (home == (char *) NULL)
+        home=GetEnvironmentValue("USERPROFILE");
+      if (home != (char *) NULL)
+        {
+          (void) CopyMagickString(expand_path,home,MaxTextExtent);
+          (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
+          home=DestroyString(home);
+        }
+    }
+  else
+    {
+#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
+      char
+        username[MaxTextExtent];
+
+      register char
+        *p;
+
+      struct passwd
+        *entry;
+
+      /*
+        Substitute ~ with home directory from password file.
+      */
+      (void) CopyMagickString(username,path+1,MaxTextExtent);
+      p=strchr(username,'/');
+      if (p != (char *) NULL)
+        *p='\0';
+      entry=getpwnam(username);
+      if (entry == (struct passwd *) NULL)
+        return;
+      (void) CopyMagickString(expand_path,entry->pw_dir,MaxTextExtent);
+      if (p != (char *) NULL)
+        {
+          (void) ConcatenateMagickString(expand_path,"/",MaxTextExtent);
+          (void) ConcatenateMagickString(expand_path,p+1,MaxTextExtent);
+        }
+#endif
+    }
+  (void) CopyMagickString(path,expand_path,MaxTextExtent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   E x p a n d F i l e n a m e s                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ExpandFilenames() checks each argument of the command line vector and
+%  expands it if they have a wildcard character.  For example, *.jpg might
+%  expand to:  bird.jpg rose.jpg tiki.jpg.
+%
+%  The format of the ExpandFilenames function is:
+%
+%      status=ExpandFilenames(int *number_arguments,char ***arguments)
+%
+%  A description of each parameter follows:
+%
+%    o number_arguments: Specifies a pointer to an integer describing the
+%      number of elements in the argument vector.
+%
+%    o arguments: Specifies a pointer to a text array containing the command
+%      line arguments.
+%
+*/
+MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
+  char ***arguments)
+{
+  char
+    *directory,
+    home_directory[MaxTextExtent],
+    **vector;
+
+  register ssize_t
+    i,
+    j;
+
+  size_t
+    number_files;
+
+  ssize_t
+    count,
+    parameters;
+
+  /*
+    Allocate argument vector.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(number_arguments != (int *) NULL);
+  assert(arguments != (char ***) NULL);
+  vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
+    sizeof(*vector));
+  if (vector == (char **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  /*
+    Expand any wildcard filenames.
+  */
+  *home_directory='\0';
+  count=0;
+  for (i=0; i < (ssize_t) *number_arguments; i++)
+  {
+    char
+      **filelist,
+      filename[MaxTextExtent],
+      magick[MaxTextExtent],
+      *option,
+      path[MaxTextExtent],
+      subimage[MaxTextExtent];
+
+    MagickBooleanType
+      destroy;
+
+    option=(*arguments)[i];
+    *magick='\0';
+    *path='\0';
+    *filename='\0';
+    *subimage='\0';
+    vector[count++]=ConstantString(option);
+    destroy=MagickTrue;
+    parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
+    if (parameters > 0)
+      {
+        /*
+          Do not expand command option parameters.
+        */
+        for (j=0; j < parameters; j++)
+        {
+          i++;
+          if (i == (ssize_t) *number_arguments)
+            break;
+          option=(*arguments)[i];
+          vector[count++]=ConstantString(option);
+        }
+        continue;
+      }
+    if ((*option == '"') || (*option == '\''))
+      continue;
+    GetPathComponent(option,TailPath,filename);
+    GetPathComponent(option,MagickPath,magick);
+    if ((LocaleCompare(magick,"CAPTION") == 0) ||
+        (LocaleCompare(magick,"LABEL") == 0) ||
+        (LocaleCompare(magick,"VID") == 0))
+      continue;
+    if ((IsGlob(filename) == MagickFalse) && (*filename != '@'))
+      continue;
+    if (*filename != '@')
+      {
+        /*
+          Generate file list from wildcard filename (e.g. *.jpg).
+        */
+        GetPathComponent(option,HeadPath,path);
+        GetPathComponent(option,SubimagePath,subimage);
+        ExpandFilename(path);
+        if (*home_directory == '\0')
+          directory=getcwd(home_directory,MaxTextExtent-1);
+        (void) directory;
+        filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
+          &number_files);
+      }
+    else
+      {
+        char
+          *files;
+
+        ExceptionInfo
+          *exception;
+
+        int
+          length;
+
+        /*
+          Generate file list from file list (e.g. @filelist.txt).
+        */
+        exception=AcquireExceptionInfo();
+        files=FileToString(filename+1,~0,exception);
+        exception=DestroyExceptionInfo(exception);
+        if (files == (char *) NULL)
+          continue;
+        filelist=StringToArgv(files,&length);
+        if (filelist == (char **) NULL)
+          continue;
+        files=DestroyString(files);
+        filelist[0]=DestroyString(filelist[0]);
+        for (j=0; j < (ssize_t) (length-1); j++)
+          filelist[j]=filelist[j+1];
+        number_files=(size_t) length-1;
+      }
+    if (filelist == (char **) NULL)
+      continue;
+    for (j=0; j < (ssize_t) number_files; j++)
+      if (IsPathDirectory(filelist[j]) <= 0)
+        break;
+    if (j == (ssize_t) number_files)
+      {
+        for (j=0; j < (ssize_t) number_files; j++)
+          filelist[j]=DestroyString(filelist[j]);
+        filelist=(char **) RelinquishMagickMemory(filelist);
+        continue;
+      }
+    /*
+      Transfer file list to argument vector.
+    */
+    vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
+      count+number_files+1,sizeof(*vector));
+    if (vector == (char **) NULL)
+      return(MagickFalse);
+    for (j=0; j < (ssize_t) number_files; j++)
+    {
+      option=filelist[j];
+      parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
+      if (parameters > 0)
+        {
+          ssize_t
+            k;
+
+          /*
+            Do not expand command option parameters.
+          */
+          vector[count++]=ConstantString(option);
+          for (k=0; k < parameters; k++)
+          {
+            j++;
+            if (j == (ssize_t) number_files)
+              break;
+            option=filelist[j];
+            vector[count++]=ConstantString(option);
+          }
+          continue;
+        }
+      (void) CopyMagickString(filename,path,MaxTextExtent);
+      if (*path != '\0')
+        (void) ConcatenateMagickString(filename,DirectorySeparator,
+          MaxTextExtent);
+      (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
+      filelist[j]=DestroyString(filelist[j]);
+      if (strlen(filename) >= (MaxTextExtent-1))
+        ThrowFatalException(OptionFatalError,"FilenameTruncated");
+      if (IsPathDirectory(filename) <= 0)
+        {
+          char
+            path[MaxTextExtent];
+
+          *path='\0';
+          if (*magick != '\0')
+            {
+              (void) ConcatenateMagickString(path,magick,MaxTextExtent);
+              (void) ConcatenateMagickString(path,":",MaxTextExtent);
+            }
+          (void) ConcatenateMagickString(path,filename,MaxTextExtent);
+          if (*subimage != '\0')
+            {
+              (void) ConcatenateMagickString(path,"[",MaxTextExtent);
+              (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
+              (void) ConcatenateMagickString(path,"]",MaxTextExtent);
+            }
+          if (strlen(path) >= (MaxTextExtent-1))
+            ThrowFatalException(OptionFatalError,"FilenameTruncated");
+          if (destroy != MagickFalse)
+            {
+              count--;
+              vector[count]=DestroyString(vector[count]);
+              destroy=MagickFalse;
+            }
+          vector[count++]=ConstantString(path);
+        }
+    }
+    filelist=(char **) RelinquishMagickMemory(filelist);
+  }
+  vector[count]=(char *) NULL;
+  if (IsEventLogging() != MagickFalse)
+    {
+      char
+        *command_line;
+
+      command_line=AcquireString(vector[0]);
+      for (i=1; i < count; i++)
+      {
+        (void) ConcatenateString(&command_line," {");
+        (void) ConcatenateString(&command_line,vector[i]);
+        (void) ConcatenateString(&command_line,"}");
+      }
+      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
+        "Command line: %s",command_line);
+      command_line=DestroyString(command_line);
+    }
+  *number_arguments=(int) count;
+  *arguments=vector;
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t E x e c u t i o n P a t h                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetExecutionPath() returns the pathname of the executable that started
+%  the process.  On success MagickTrue is returned, otherwise MagickFalse.
+%
+%  The format of the GetExecutionPath method is:
+%
+%      MagickBooleanType GetExecutionPath(char *path,const size_t extent)
+%
+%  A description of each parameter follows:
+%
+%    o path: the pathname of the executable that started the process.
+%
+%    o extent: the maximum extent of the path.
+%
+*/
+MagickExport MagickBooleanType GetExecutionPath(char *path,const size_t extent)
+{
+  char
+    *directory;
+
+  *path='\0';
+  directory=getcwd(path,(unsigned long) extent);
+  (void) directory;
+#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
+  {
+    char
+      link_path[MaxTextExtent],
+      execution_path[PATH_MAX+1];
+
+    ssize_t
+      count;
+
+    (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
+      (double) getpid());
+    count=readlink(link_path,execution_path,PATH_MAX);
+    if (count == -1)
+      {
+        (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
+          (double) getpid());
+        count=readlink(link_path,execution_path,PATH_MAX);
+      }
+    if ((count > 0) && (count <= (ssize_t) PATH_MAX))
+      {
+        execution_path[count]='\0';
+        (void) CopyMagickString(path,execution_path,extent);
+      }
+  }
+#endif
+#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
+  {
+    char
+      executable_path[PATH_MAX << 1],
+      execution_path[PATH_MAX+1];
+
+    uint32_t
+      length;
+
+    length=sizeof(executable_path);
+    if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
+        (realpath(executable_path,execution_path) != (char *) NULL))
+      (void) CopyMagickString(path,execution_path,extent);
+  }
+#endif
+#if defined(MAGICKCORE_HAVE_GETEXECNAME)
+  {
+    const char
+      *execution_path;
+
+    execution_path=(const char *) getexecname();
+    if (execution_path != (const char *) NULL)
+      {
+        if (*execution_path != *DirectorySeparator)
+          (void) ConcatenateMagickString(path,DirectorySeparator,extent);
+        (void) ConcatenateMagickString(path,execution_path,extent);
+      }
+  }
+#endif
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  NTGetExecutionPath(path,extent);
+#endif
+#if defined(__GNU__)
+  {
+    char
+      *program_name,
+      *execution_path;
+
+    ssize_t
+      count;
+
+    count=0;
+    execution_path=(char *) NULL;
+    program_name=program_invocation_name;
+    if (*program_invocation_name != '/')
+      {
+        size_t
+          extent;
+
+        extent=strlen(directory)+strlen(program_name)+2;
+        program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
+        if (program_name == (char *) NULL)
+          program_name=program_invocation_name;
+        else
+          count=FormatLocaleString(program_name,extent,"%s/%s",directory,
+            program_invocation_name);
+      }
+    if (count != -1)
+      {
+        execution_path=realpath(program_name,NULL);
+        if (execution_path != (char *) NULL)
+          (void) CopyMagickString(path,execution_path,extent);
+      }
+    if (program_name != program_invocation_name)
+      program_name=(char *) RelinquishMagickMemory(program_name);
+    execution_path=(char *) RelinquishMagickMemory(execution_path);
+  }
+#endif
+  return(IsPathAccessible(path));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k P a g e S i z e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickPageSize() returns the memory page size.
+%
+%  The format of the GetMagickPageSize method is:
+%
+%      ssize_t GetMagickPageSize()
+%
+*/
+MagickExport ssize_t GetMagickPageSize(void)
+{
+  static ssize_t
+    page_size = -1;
+
+  if (page_size > 0)
+    return(page_size);
+#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+  page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
+#else
+#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
+  page_size=(ssize_t) getpagesize();
+#endif
+#endif
+  if (page_size <= 0)
+    page_size=16384;
+  return(page_size);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P a t h A t t r i b u t e s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPathAttributes() returns attributes (e.g. size of file) about a path.
+%
+%  The path of the GetPathAttributes method is:
+%
+%      MagickBooleanType GetPathAttributes(const char *path,void *attributes)
+%
+%  A description of each parameter follows.
+%
+%   o  path: the file path.
+%
+%   o  attributes: the path attributes are returned here.
+%
+*/
+
+#if defined(MAGICKCORE_HAVE__WFOPEN)
+static size_t UTF8ToUTF16(const unsigned char *utf8,wchar_t *utf16)
+{
+  register const unsigned char
+    *p;
+
+  if (utf16 != (wchar_t *) NULL)
+    {
+      register wchar_t
+        *q;
+
+      wchar_t
+        c;
+
+      /*
+        Convert UTF-8 to UTF-16.
+      */
+      q=utf16;
+      for (p=utf8; *p != '\0'; p++)
+      {
+        if ((*p & 0x80) == 0)
+          *q=(*p);
+        else
+          if ((*p & 0xE0) == 0xC0)
+            {
+              c=(*p);
+              *q=(c & 0x1F) << 6;
+              p++;
+              if ((*p & 0xC0) != 0x80)
+                return(0);
+              *q|=(*p & 0x3F);
+            }
+          else
+            if ((*p & 0xF0) == 0xE0)
+              {
+                c=(*p);
+                *q=c << 12;
+                p++;
+                if ((*p & 0xC0) != 0x80)
+                  return(0);
+                c=(*p);
+                *q|=(c & 0x3F) << 6;
+                p++;
+                if ((*p & 0xC0) != 0x80)
+                  return(0);
+                *q|=(*p & 0x3F);
+              }
+            else
+              return(0);
+        q++;
+      }
+      *q++='\0';
+      return(q-utf16);
+    }
+  /*
+    Compute UTF-16 string length.
+  */
+  for (p=utf8; *p != '\0'; p++)
+  {
+    if ((*p & 0x80) == 0)
+      ;
+    else
+      if ((*p & 0xE0) == 0xC0)
+        {
+          p++;
+          if ((*p & 0xC0) != 0x80)
+            return(0);
+        }
+      else
+        if ((*p & 0xF0) == 0xE0)
+          {
+            p++;
+            if ((*p & 0xC0) != 0x80)
+              return(0);
+            p++;
+            if ((*p & 0xC0) != 0x80)
+              return(0);
+         }
+       else
+         return(0);
+  }
+  return(p-utf8);
+}
+
+static wchar_t *ConvertUTF8ToUTF16(const unsigned char *source)
+{
+  size_t
+    length;
+
+  wchar_t
+    *utf16;
+
+  length=UTF8ToUTF16(source,(wchar_t *) NULL);
+  if (length == 0)
+    {
+      register ssize_t
+        i;
+
+      /*
+        Not UTF-8, just copy.
+      */
+      length=strlen((const char *) source);
+      utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
+      if (utf16 == (wchar_t *) NULL)
+        return((wchar_t *) NULL);
+      for (i=0; i <= (ssize_t) length; i++)
+        utf16[i]=source[i];
+      return(utf16);
+    }
+  utf16=(wchar_t *) AcquireQuantumMemory(length+1,sizeof(*utf16));
+  if (utf16 == (wchar_t *) NULL)
+    return((wchar_t *) NULL);
+  length=UTF8ToUTF16(source,utf16);
+  return(utf16);
+}
+#endif
+
+MagickExport MagickBooleanType GetPathAttributes(const char *path,
+  void *attributes)
+{
+  MagickBooleanType
+    status;
+
+  if (path == (const char *) NULL)
+    {
+      errno=EINVAL;
+      return(MagickFalse);
+    }
+#if !defined(MAGICKCORE_HAVE__WSTAT)
+  status=stat(path,(struct stat *) attributes) == 0 ? MagickTrue : MagickFalse;
+#else
+  {
+    wchar_t
+      *unicode_path;
+
+    unicode_path=ConvertUTF8ToUTF16((const unsigned char *) path);
+    if (unicode_path == (wchar_t *) NULL)
+      return(MagickFalse);
+    status=wstat(unicode_path,(struct stat *) attributes) == 0 ? MagickTrue :
+      MagickFalse;
+    unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
+  }
+#endif
+  return(status);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t P a t h C o m p o n e n t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPathComponent() returns the parent directory name, filename, basename, or
+%  extension of a file path.
+%
+%  The format of the GetPathComponent function is:
+%
+%      GetPathComponent(const char *path,PathType type,char *component)
+%
+%  A description of each parameter follows:
+%
+%    o path: Specifies a pointer to a character array that contains the
+%      file path.
+%
+%    o type: Specififies which file path component to return.
+%
+%    o component: the selected file path component is returned here.
+%
+*/
+MagickExport void GetPathComponent(const char *path,PathType type,
+  char *component)
+{
+  char
+    magick[MaxTextExtent],
+    *q,
+    subimage[MaxTextExtent];
+
+  register char
+    *p;
+
+  assert(path != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
+  assert(component != (char *) NULL);
+  if (*path == '\0')
+    {
+      *component='\0';
+      return;
+    }
+  (void) CopyMagickString(component,path,MaxTextExtent);
+  *magick='\0';
+#if defined(__OS2__)
+  if (path[1] != ":")
+#endif
+  for (p=component; *p != '\0'; p++)
+  {
+    if ((*p == '%') && (*(p+1) == '['))
+      {
+        /*
+          Skip over %[...].
+        */
+        for (p++; (*p != ']') && (*p != '\0'); p++) ;
+        if (*p == '\0')
+          break;
+      }
+    if ((*p == ':') && (IsPathDirectory(path) < 0) &&
+        (IsPathAccessible(path) == MagickFalse))
+      {
+        /*
+          Look for image format specification (e.g. ps3:image).
+        */
+        (void) CopyMagickString(magick,component,(size_t) (p-component+1));
+        if (IsMagickConflict(magick) != MagickFalse)
+          *magick='\0';
+        else
+          for (q=component; *q != '\0'; q++)
+            *q=(*++p);
+        break;
+      }
+  }
+  *subimage='\0';
+  p=component;
+  if (*p != '\0')
+    p=component+strlen(component)-1;
+  if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
+      (IsPathAccessible(path) == MagickFalse))
+    {
+      /*
+        Look for scene specification (e.g. img0001.pcd[4]).
+      */
+      for (q=p-1; q > component; q--)
+        if (*q == '[')
+          break;
+      if (*q == '[')
+        {
+          (void) CopyMagickString(subimage,q+1,MaxTextExtent);
+          subimage[p-q-1]='\0';
+          if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
+              (IsGeometry(subimage) == MagickFalse))
+            *subimage='\0';
+          else
+            *q='\0';
+        }
+    }
+  p=component;
+  if (*p != '\0')
+    for (p=component+strlen(component)-1; p > component; p--)
+      if (IsBasenameSeparator(*p) != MagickFalse)
+        break;
+  switch (type)
+  {
+    case MagickPath:
+    {
+      (void) CopyMagickString(component,magick,MaxTextExtent);
+      break;
+    }
+    case RootPath:
+    {
+      for (p=component+(strlen(component)-1); p > component; p--)
+      {
+        if (IsBasenameSeparator(*p) != MagickFalse)
+          break;
+        if (*p == '.')
+          break;
+      }
+      if (*p == '.')
+        *p='\0';
+      break;
+    }
+    case HeadPath:
+    {
+      *p='\0';
+      break;
+    }
+    case TailPath:
+    {
+      if (IsBasenameSeparator(*p) != MagickFalse)
+        (void) CopyMagickMemory((unsigned char *) component,
+          (const unsigned char *) (p+1),strlen(p+1)+1);
+      break;
+    }
+    case BasePath:
+    {
+      if (IsBasenameSeparator(*p) != MagickFalse)
+        (void) CopyMagickString(component,p+1,MaxTextExtent);
+      for (p=component+(strlen(component)-1); p > component; p--)
+        if (*p == '.')
+          {
+            *p='\0';
+            break;
+          }
+      break;
+    }
+    case ExtensionPath:
+    {
+      if (IsBasenameSeparator(*p) != MagickFalse)
+        (void) CopyMagickString(component,p+1,MaxTextExtent);
+      p=component;
+      if (*p != '\0')
+        for (p=component+strlen(component)-1; p > component; p--)
+          if (*p == '.')
+            break;
+      *component='\0';
+      if (*p == '.')
+        (void) CopyMagickString(component,p+1,MaxTextExtent);
+      break;
+    }
+    case SubimagePath:
+    {
+      (void) CopyMagickString(component,subimage,MaxTextExtent);
+      break;
+    }
+    case CanonicalPath:
+    case UndefinedPath:
+      break;
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  G e t P a t h C o m p o n e n t s                                          %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetPathComponents() returns a list of path components.
+%
+%  The format of the GetPathComponents method is:
+%
+%      char **GetPathComponents(const char *path,
+%        size_t *number_componenets)
+%
+%  A description of each parameter follows:
+%
+%    o path:  Specifies the string to segment into a list.
+%
+%    o number_components:  return the number of components in the list
+%
+*/
+MagickExport char **GetPathComponents(const char *path,
+  size_t *number_components)
+{
+  char
+    **components;
+
+  register const char
+    *p,
+    *q;
+
+  register ssize_t
+    i;
+
+  if (path == (char *) NULL)
+    return((char **) NULL);
+  *number_components=1;
+  for (p=path; *p != '\0'; p++)
+    if (IsBasenameSeparator(*p))
+      (*number_components)++;
+  components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
+    sizeof(*components));
+  if (components == (char **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  p=path;
+  for (i=0; i < (ssize_t) *number_components; i++)
+  {
+    for (q=p; *q != '\0'; q++)
+      if (IsBasenameSeparator(*q))
+        break;
+    components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
+      sizeof(**components));
+    if (components[i] == (char *) NULL)
+      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+    (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
+    p=q+1;
+  }
+  components[i]=(char *) NULL;
+  return(components);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  I s P a t h A c c e s s i b l e                                            %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsPathAccessible() returns MagickTrue if the file as defined by the path is
+%  accessible.
+%
+%  The format of the IsPathAccessible method is:
+%
+%      MagickBooleanType IsPathAccessible(const char *filename)
+%
+%  A description of each parameter follows.
+%
+%    o path:  Specifies a path to a file.
+%
+*/
+MagickExport MagickBooleanType IsPathAccessible(const char *path)
+{
+  MagickBooleanType
+    status;
+
+  struct stat
+    attributes;
+
+  if ((path == (const char *) NULL) || (*path == '\0'))
+    return(MagickFalse);
+  status=GetPathAttributes(path,&attributes);
+  if (status == MagickFalse)
+    return(status);
+  if (S_ISREG(attributes.st_mode) == 0)
+    return(MagickFalse);
+  if (access(path,F_OK) != 0)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++  I s P a t h D i r e c t o r y                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsPathDirectory() returns -1 if the directory does not exist,  1 is returned
+%  if the path represents a directory otherwise 0.
+%
+%  The format of the IsPathDirectory method is:
+%
+%      int IsPathDirectory(const char *path)
+%
+%  A description of each parameter follows.
+%
+%   o  path:  The directory path.
+%
+*/
+static int IsPathDirectory(const char *path)
+{
+  MagickBooleanType
+    status;
+
+  struct stat
+    attributes;
+
+  if ((path == (const char *) NULL) || (*path == '\0'))
+    return(MagickFalse);
+  status=GetPathAttributes(path,&attributes);
+  if (status == MagickFalse)
+    return(-1);
+  if (S_ISDIR(attributes.st_mode) == 0)
+    return(0);
+  return(1);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s M a g i c k T r u e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  IsMagickTrue() returns MagickTrue if the value is "true", "on", "yes" or
+%  "1".
+%
+%  The format of the IsMagickTrue method is:
+%
+%      MagickBooleanType IsMagickTrue(const char *value)
+%
+%  A description of each parameter follows:
+%
+%    o option: either MagickTrue or MagickFalse depending on the value
+%      parameter.
+%
+%    o value: Specifies a pointer to a character array.
+%
+*/
+MagickExport MagickBooleanType IsMagickTrue(const char *value)
+{
+  if (value == (const char *) NULL)
+    return(MagickFalse);
+  if (LocaleCompare(value,"true") == 0)
+    return(MagickTrue);
+  if (LocaleCompare(value,"on") == 0)
+    return(MagickTrue);
+  if (LocaleCompare(value,"yes") == 0)
+    return(MagickTrue);
+  if (LocaleCompare(value,"1") == 0)
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   L i s t F i l e s                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ListFiles() reads the directory specified and returns a list of filenames
+%  contained in the directory sorted in ascending alphabetic order.
+%
+%  The format of the ListFiles function is:
+%
+%      char **ListFiles(const char *directory,const char *pattern,
+%        ssize_t *number_entries)
+%
+%  A description of each parameter follows:
+%
+%    o filelist: Method ListFiles returns a list of filenames contained
+%      in the directory.  If the directory specified cannot be read or it is
+%      a file a NULL list is returned.
+%
+%    o directory: Specifies a pointer to a text string containing a directory
+%      name.
+%
+%    o pattern: Specifies a pointer to a text string containing a pattern.
+%
+%    o number_entries:  This integer returns the number of filenames in the
+%      list.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int FileCompare(const void *x,const void *y)
+{
+  register const char
+    **p,
+    **q;
+
+  p=(const char **) x;
+  q=(const char **) y;
+  return(LocaleCompare(*p,*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
+  struct dirent **result)
+{
+#if defined(MAGICKCORE_HAVE_READDIR_R)
+  return(readdir_r(directory,entry,result));
+#else
+  (void) entry;
+  errno=0;
+  *result=readdir(directory);
+  return(errno);
+#endif
+}
+
+MagickExport char **ListFiles(const char *directory,const char *pattern,
+  size_t *number_entries)
+{
+  char
+    **filelist;
+
+  DIR
+    *current_directory;
+
+  struct dirent
+    *buffer,
+    *entry;
+
+  size_t
+    max_entries;
+
+  /*
+    Open directory.
+  */
+  assert(directory != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
+  assert(pattern != (const char *) NULL);
+  assert(number_entries != (size_t *) NULL);
+  *number_entries=0;
+  current_directory=opendir(directory);
+  if (current_directory == (DIR *) NULL)
+    return((char **) NULL);
+  /*
+    Allocate filelist.
+  */
+  max_entries=2048;
+  filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
+    sizeof(*filelist));
+  if (filelist == (char **) NULL)
+    {
+      (void) closedir(current_directory);
+      return((char **) NULL);
+    }
+  /*
+    Save the current and change to the new directory.
+  */
+  buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
+    FILENAME_MAX+1);
+  if (buffer == (struct dirent *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
+         (entry != (struct dirent *) NULL))
+  {
+    if (*entry->d_name == '.')
+      continue;
+    if ((IsPathDirectory(entry->d_name) > 0) ||
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+        (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
+#else
+        (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
+#endif
+      {
+        if (*number_entries >= max_entries)
+          {
+            /*
+              Extend the file list.
+            */
+            max_entries<<=1;
+            filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
+              max_entries,sizeof(*filelist));
+            if (filelist == (char **) NULL)
+              break;
+          }
+#if defined(vms)
+        {
+          register char
+            *p;
+
+          p=strchr(entry->d_name,';');
+          if (p)
+            *p='\0';
+          if (*number_entries > 0)
+            if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
+              continue;
+        }
+#endif
+        filelist[*number_entries]=(char *) AcquireString(entry->d_name);
+        (*number_entries)++;
+      }
+  }
+  buffer=(struct dirent *) RelinquishMagickMemory(buffer);
+  (void) closedir(current_directory);
+  if (filelist == (char **) NULL)
+    return((char **) NULL);
+  /*
+    Sort filelist in ascending order.
+  */
+  qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
+    FileCompare);
+  return(filelist);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   M a g i c k D e l a y                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MagickDelay() suspends program execution for the number of milliseconds
+%  specified.
+%
+%  The format of the Delay method is:
+%
+%      void MagickDelay(const MagickSizeType milliseconds)
+%
+%  A description of each parameter follows:
+%
+%    o milliseconds: Specifies the number of milliseconds to delay before
+%      returning.
+%
+*/
+MagickExport void MagickDelay(const MagickSizeType milliseconds)
+{
+  if (milliseconds == 0)
+    return;
+#if defined(MAGICKCORE_HAVE_NANOSLEEP)
+  {
+    struct timespec
+      timer;
+
+    timer.tv_sec=(time_t) (milliseconds/1000);
+    timer.tv_nsec=(milliseconds % 1000)*1000*1000;
+    (void) nanosleep(&timer,(struct timespec *) NULL);
+  }
+#elif defined(MAGICKCORE_HAVE_USLEEP)
+  usleep(1000*milliseconds);
+#elif defined(MAGICKCORE_HAVE_SELECT)
+  {
+    struct timeval
+      timer;
+
+    timer.tv_sec=(long) milliseconds/1000;
+    timer.tv_usec=(long) (milliseconds % 1000)*1000;
+    (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
+  }
+#elif defined(MAGICKCORE_HAVE_POLL)
+  (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  Sleep((long) milliseconds);
+#elif defined(vms)
+  {
+    float
+      timer;
+
+    timer=milliseconds/1000.0;
+    lib$wait(&timer);
+  }
+#elif defined(__BEOS__)
+  snooze(1000*milliseconds);
+#else
+# error "Time delay method not defined."
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%  M u l t i l i n e C e n s u s                                              %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  MultilineCensus() returns the number of lines within a label.  A line is
+%  represented by a \n character.
+%
+%  The format of the MultilineCenus method is:
+%
+%      size_t MultilineCensus(const char *label)
+%
+%  A description of each parameter follows.
+%
+%   o  label:  This character string is the label.
+%
+%
+*/
+MagickExport size_t MultilineCensus(const char *label)
+{
+  size_t
+    number_lines;
+
+  /*
+    Determine the number of lines within this label.
+  */
+  if (label == (char *) NULL)
+    return(0);
+  for (number_lines=1; *label != '\0'; label++)
+    if (*label == '\n')
+      number_lines++;
+  return(number_lines);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   O p e n M a g i c k S t r e a m                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  OpenMagickStream() opens the file at the specified path and return the
+%  associated stream.
+%
+%  The path of the OpenMagickStream method is:
+%
+%      FILE *OpenMagickStream(const char *path,const char *mode)
+%
+%  A description of each parameter follows.
+%
+%   o  path: the file path.
+%
+%   o  mode: the file mode.
+%
+*/
+MagickExport FILE *OpenMagickStream(const char *path,const char *mode)
+{
+  FILE
+    *file;
+
+  if ((path == (const char *) NULL) || (mode == (const char *) NULL))
+    {
+      errno=EINVAL;
+      return((FILE *) NULL);
+    }
+  file=(FILE *) NULL;
+#if defined(MAGICKCORE_HAVE__WFOPEN)
+  {
+    wchar_t
+      *unicode_mode,
+      *unicode_path;
+
+    unicode_path=ConvertUTF8ToUTF16((const unsigned char *) path);
+    if (unicode_path == (wchar_t *) NULL)
+      return((FILE *) NULL);
+    unicode_mode=ConvertUTF8ToUTF16((const unsigned char *) mode);
+    if (unicode_mode == (wchar_t *) NULL)
+      {
+        unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
+        return((FILE *) NULL);
+      }
+    file=_wfopen(unicode_path,unicode_mode);
+    unicode_mode=(wchar_t *) RelinquishMagickMemory(unicode_mode);
+    unicode_path=(wchar_t *) RelinquishMagickMemory(unicode_path);
+  }
+#endif
+  if (file == (FILE *) NULL)
+    file=fopen(path,mode);
+  return(file);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S y s t e m C o m m a n d                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SystemCommand() executes the specified command and waits until it
+%  terminates.  The returned value is the exit status of the command.
+%
+%  The format of the SystemCommand method is:
+%
+%      int SystemCommand(const MagickBooleanType asynchronous,
+%        const MagickBooleanType verbose,const char *command,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o asynchronous: a value other than 0 executes the parent program
+%      concurrently with the new child process.
+%
+%    o verbose: a value other than 0 prints the executed command before it is
+%      invoked.
+%
+%    o command: this string is the command to execute.
+%
+%    o exception: return any errors here.
+%
+*/
+MagickExport int SystemCommand(const MagickBooleanType asynchronous,
+  const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
+{
+  char
+    **arguments,
+    *shell_command;
+
+  int
+    number_arguments,
+    status;
+
+  PolicyDomain
+    domain;
+
+  PolicyRights
+    rights;
+
+  register ssize_t
+    i;
+
+  status=(-1);
+  arguments=StringToArgv(command,&number_arguments);
+  if (arguments == (char **) NULL)
+    return(status);
+  rights=ExecutePolicyRights;
+  domain=DelegatePolicyDomain;
+  if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
+    {
+      errno=EPERM;
+      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
+        "NotAuthorized","`%s'",arguments[1]);
+      for (i=0; i < (ssize_t) number_arguments; i++)
+        arguments[i]=DestroyString(arguments[i]);
+      arguments=(char **) RelinquishMagickMemory(arguments);
+      return(-1);
+    }
+  if (verbose != MagickFalse)
+    {
+      (void) FormatLocaleFile(stderr,"%s\n",command);
+      (void) fflush(stderr);
+    }
+  shell_command=(char *) command;
+  if (asynchronous != MagickFalse)
+    {
+      shell_command=AcquireString(command);
+      (void) ConcatenateMagickString(shell_command,"&",MaxTextExtent);
+    }
+#if defined(MAGICKCORE_POSIX_SUPPORT)
+#if !defined(MAGICKCORE_HAVE_EXECVP)
+  status=system(shell_command);
+#else
+  if ((asynchronous != MagickFalse) || (strspn(shell_command,"&;<>|") == 0))
+    status=system(shell_command);
+  else
+    {
+      pid_t
+        child_pid;
+
+      /*
+        Call application directly rather than from a shell.
+      */
+      child_pid=fork();
+      if (child_pid == (pid_t) -1)
+        status=system(command);
+      else
+        if (child_pid == 0)
+          {
+            status=execvp(arguments[1],arguments+1);
+            _exit(1);
+          }
+        else
+          {
+            int
+              child_status;
+
+            pid_t
+              pid;
+
+            child_status=0;
+            pid=waitpid(child_pid,&child_status,0);
+            if (pid == -1)
+              status=(-1);
+            else
+              {
+                if (WIFEXITED(child_status) != 0)
+                  status=WEXITSTATUS(child_status);
+                else
+                  if (WIFSIGNALED(child_status))
+                    status=(-1);
+              }
+          }
+    }
+#endif
+#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
+  {
+    int
+      mode;
+
+    mode=_P_WAIT;
+    if (asynchronous != MagickFalse)
+      mode=_P_NOWAIT;
+    status=spawnvp(mode,arguments[1],(const char **) (arguments+1));
+  }
+#elif defined(macintosh)
+  status=MACSystemCommand(shell_command);
+#elif defined(vms)
+  status=system(shell_command);
+#else
+#  error No suitable system() method.
+#endif
+  if (status < 0)
+    (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
+      "`%s' (%d)",command,status);
+  if (shell_command != command)
+    shell_command=DestroyString(shell_command);
+  for (i=0; i < (ssize_t) number_arguments; i++)
+    arguments[i]=DestroyString(arguments[i]);
+  arguments=(char **) RelinquishMagickMemory(arguments);
+  return(status);
+}
diff --git a/MagickCore/utility.h b/MagickCore/utility.h
new file mode 100644
index 0000000..d8d308f
--- /dev/null
+++ b/MagickCore/utility.h
@@ -0,0 +1,79 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore utility methods.
+*/
+#ifndef _MAGICKCORE_UTILITY_H
+#define _MAGICKCORE_UTILITY_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum
+{
+  UndefinedPath,
+  MagickPath,
+  RootPath,
+  HeadPath,
+  TailPath,
+  BasePath,
+  ExtensionPath,
+  SubimagePath,
+  CanonicalPath
+} PathType;
+
+extern MagickExport char
+  *Base64Encode(const unsigned char *,const size_t,size_t *),
+  **GetPathComponents(const char *,size_t *),
+  **ListFiles(const char *,const char *,size_t *);
+
+extern MagickExport FILE
+  *OpenMagickStream(const char *,const char *);
+
+extern MagickExport int
+  SystemCommand(const MagickBooleanType,const MagickBooleanType,const char *,
+    ExceptionInfo *);
+
+extern MagickExport MagickBooleanType
+  AcquireUniqueFilename(char *),
+  AcquireUniqueSymbolicLink(const char *,char *),
+  ExpandFilenames(int *,char ***),
+  GetPathAttributes(const char *,void *),
+  GetExecutionPath(char *,const size_t),
+  IsMagickTrue(const char *),
+  IsPathAccessible(const char *);
+
+extern MagickExport size_t
+  MultilineCensus(const char *);
+
+extern MagickExport ssize_t
+  GetMagickPageSize(void);
+
+extern MagickExport unsigned char
+  *Base64Decode(const char *, size_t *);
+
+extern MagickExport void
+  AppendImageFormat(const char *,char *),
+  ChopPathComponents(char *,const size_t),
+  ExpandFilename(char *),
+  GetPathComponent(const char *,PathType,char *),
+  MagickDelay(const MagickSizeType);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/version.c b/MagickCore/version.c
new file mode 100644
index 0000000..869ccfb
--- /dev/null
+++ b/MagickCore/version.c
@@ -0,0 +1,288 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%               V   V  EEEEE  RRRR   SSSSS  IIIII   OOO   N   N               %
+%               V   V  E      R   R  SS       I    O   O  NN  N               %
+%               V   V  EEE    RRRR    SSS     I    O   O  N N N               %
+%                V V   E      R R       SS    I    O   O  N  NN               %
+%                 V    EEEEE  R  R   SSSSS  IIIII   OOO   N   N               %
+%                                                                             %
+%                                                                             %
+%                   MagickCore Version and Copyright Methods                  %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               September 2002                                %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+#include "MagickCore/studio.h"
+#include "MagickCore/configure.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/hashmap.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/option.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/version.h"
+
+/*
+  Define declarations.
+*/
+#define MagickURLFilename  "index.html"
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k C o p y r i g h t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickCopyright() returns the ImageMagick API copyright as a string.
+%
+%  The format of the GetMagickCopyright method is:
+%
+%      const char *GetMagickCopyright(void)
+%
+*/
+MagickExport const char *GetMagickCopyright(void)
+{
+  return(MagickCopyright);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k F e a t u r e s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickFeatures() returns the ImageMagick features.
+%
+%  The format of the GetMagickFeatures method is:
+%
+%      const char *GetMagickFeatures(void)
+%
+%  No parameters are required.
+%
+*/
+MagickExport const char *GetMagickFeatures(void)
+{
+  return(MagickFeatures);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k H o m e U R L                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickHomeURL() returns the ImageMagick home URL.
+%
+%  The format of the GetMagickHomeURL method is:
+%
+%      char *GetMagickHomeURL(void)
+%
+*/
+MagickExport char *GetMagickHomeURL(void)
+{
+  char
+    path[MaxTextExtent];
+
+  const char
+    *element;
+
+  ExceptionInfo
+    *exception;
+
+  LinkedListInfo
+    *paths;
+
+  exception=AcquireExceptionInfo();
+  paths=GetConfigurePaths(MagickURLFilename,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (paths == (LinkedListInfo *) NULL)
+    return(ConstantString(MagickHomeURL));
+  element=(const char *) GetNextValueInLinkedList(paths);
+  while (element != (const char *) NULL)
+  {
+    (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s",element,
+      DirectorySeparator,MagickURLFilename);
+    if (IsPathAccessible(path) != MagickFalse)
+      return(ConstantString(path));
+    element=(const char *) GetNextValueInLinkedList(paths);
+  }
+  return(ConstantString(MagickHomeURL));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k P a c k a g e N a m e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickPackageName() returns the ImageMagick package name.
+%
+%  The format of the GetMagickName method is:
+%
+%      const char *GetMagickName(void)
+%
+%  No parameters are required.
+%
+*/
+MagickExport const char *GetMagickPackageName(void)
+{
+  return(MagickPackageName);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k Q u a n t u m D e p t h                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickQuantumDepth() returns the ImageMagick quantum depth.
+%
+%  The format of the GetMagickQuantumDepth method is:
+%
+%      const char *GetMagickQuantumDepth(size_t *depth)
+%
+%  A description of each parameter follows:
+%
+%    o depth: the quantum depth is returned as a number.
+%
+*/
+MagickExport const char *GetMagickQuantumDepth(size_t *depth)
+{
+  if (depth != (size_t *) NULL)
+    *depth=(size_t) MAGICKCORE_QUANTUM_DEPTH;
+  return(MagickQuantumDepth);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k Q u a n t u m R a n g e                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickQuantumRange() returns the ImageMagick quantum range.
+%
+%  The format of the GetMagickQuantumRange method is:
+%
+%      const char *GetMagickQuantumRange(size_t *range)
+%
+%  A description of each parameter follows:
+%
+%    o range: the quantum range is returned as a number.
+%
+*/
+MagickExport const char *GetMagickQuantumRange(size_t *range)
+{
+  if (range != (size_t *) NULL)
+    *range=(size_t) QuantumRange;
+  return(MagickQuantumRange);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k R e l e a s e D a t e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickReleaseDate() returns the ImageMagick release date.
+%
+%  The format of the GetMagickReleaseDate method is:
+%
+%      const char *GetMagickReleaseDate(void)
+%
+%  No parameters are required.
+%
+*/
+MagickExport const char *GetMagickReleaseDate(void)
+{
+  return(MagickReleaseDate);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t M a g i c k V e r s i o n                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetMagickVersion() returns the ImageMagick API version as a string and
+%  as a number.
+%
+%  The format of the GetMagickVersion method is:
+%
+%      const char *GetMagickVersion(size_t *version)
+%
+%  A description of each parameter follows:
+%
+%    o version: the ImageMagick version is returned as a number.
+%
+*/
+MagickExport const char *GetMagickVersion(size_t *version)
+{
+  if (version != (size_t *) NULL)
+    *version=MagickLibVersion;
+  return(MagickVersion);
+}
diff --git a/MagickCore/version.h b/MagickCore/version.h
new file mode 100644
index 0000000..0cd48a7
--- /dev/null
+++ b/MagickCore/version.h
@@ -0,0 +1,93 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore version methods.
+*/
+#ifndef _MAGICKCORE_VERSION_H
+#define _MAGICKCORE_VERSION_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+  Define declarations.
+*/
+#define MagickPackageName "ImageMagick"
+#define MagickCopyright  "Copyright (C) 1999-2011 ImageMagick Studio LLC"
+#define MagickSVNRevision  "4683"
+#define MagickLibVersion  0x671
+#define MagickLibVersionText  "6.7.1"
+#define MagickLibVersionNumber  4,0,1
+#define MagickLibAddendum  "-0"
+#define MagickLibInterface  4
+#define MagickLibMinInterface  4
+#define MagickReleaseDate  "2011-07-01"
+#define MagickChangeDate   "20110701"
+#define MagickAuthoritativeURL  "http://www.imagemagick.org"
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#define MagickOpenMPFeature  "OpenMP "
+#else
+#define MagickOpenMPFeature  " "
+#endif
+#if defined(MAGICKCORE_OPENCL_SUPPORT)
+#define MagickOpenCLFeature  "OpenCL "
+#else
+#define MagickOpenCLFeature  " "
+#endif
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+#define MagickHDRIFeature  "HDRI "
+#else
+#define MagickHDRIFeature  " "
+#endif
+#define MagickFeatures MagickOpenMPFeature MagickOpenCLFeature MagickHDRIFeature
+#define MagickHomeURL  "file:///usr/local/share/doc/ImageMagick-7.0.0//index.html"
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+#define MagickQuantumDepth  "Q8"
+#define MagickQuantumRange  "255"
+#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
+#define MagickQuantumDepth  "Q16"
+#define MagickQuantumRange  "65535"
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+#define MagickQuantumDepth  "Q32"
+#define MagickQuantumRange  "4294967295"
+#elif (MAGICKCORE_QUANTUM_DEPTH == 64)
+#define MagickQuantumDepth  "Q64"
+#define MagickQuantumRange  "18446744073709551615"
+#else
+#define MagickQuantumDepth  "Q?"
+#define MagickQuantumRange  "?"
+#endif
+#define MagickVersion  \
+  MagickPackageName " " MagickLibVersionText MagickLibAddendum " " \
+  MagickReleaseDate " " MagickQuantumDepth " " MagickAuthoritativeURL
+
+extern MagickExport char
+  *GetMagickHomeURL(void);
+
+extern MagickExport const char
+  *GetMagickCopyright(void),
+  *GetMagickFeatures(void),
+  *GetMagickPackageName(void),
+  *GetMagickQuantumDepth(size_t *),
+  *GetMagickQuantumRange(size_t *),
+  *GetMagickReleaseDate(void),
+  *GetMagickVersion(size_t *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/version.h.in b/MagickCore/version.h.in
new file mode 100644
index 0000000..380266e
--- /dev/null
+++ b/MagickCore/version.h.in
@@ -0,0 +1,93 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore version methods.
+*/
+#ifndef _MAGICKCORE_VERSION_H
+#define _MAGICKCORE_VERSION_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/*
+  Define declarations.
+*/
+#define MagickPackageName "@PACKAGE_NAME@"
+#define MagickCopyright  "Copyright (C) 1999-2011 ImageMagick Studio LLC"
+#define MagickSVNRevision  "@MAGICK_SVN_REVISION@"
+#define MagickLibVersion  @PACKAGE_LIB_VERSION@
+#define MagickLibVersionText  "@MAGICK_LIB_VERSION_TEXT@"
+#define MagickLibVersionNumber  @MAGICK_LIB_VERSION_NUMBER@
+#define MagickLibAddendum  "@PACKAGE_VERSION_ADDENDUM@"
+#define MagickLibInterface  @MAGICK_LIBRARY_CURRENT@
+#define MagickLibMinInterface  @MAGICK_LIBRARY_CURRENT_MIN@
+#define MagickReleaseDate  "@PACKAGE_RELEASE_DATE@"
+#define MagickChangeDate   "@PACKAGE_CHANGE_DATE@"
+#define MagickAuthoritativeURL  "http://www.imagemagick.org"
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#define MagickOpenMPFeature  "OpenMP "
+#else
+#define MagickOpenMPFeature  " "
+#endif
+#if defined(MAGICKCORE_OPENCL_SUPPORT)
+#define MagickOpenCLFeature  "OpenCL "
+#else
+#define MagickOpenCLFeature  " "
+#endif
+#if defined(MAGICKCORE_HDRI_SUPPORT)
+#define MagickHDRIFeature  "HDRI "
+#else
+#define MagickHDRIFeature  " "
+#endif
+#define MagickFeatures MagickOpenMPFeature MagickOpenCLFeature MagickHDRIFeature
+#define MagickHomeURL  "file://@DOCUMENTATION_PATH@/index.html"
+#if (MAGICKCORE_QUANTUM_DEPTH == 8)
+#define MagickQuantumDepth  "Q8"
+#define MagickQuantumRange  "255"
+#elif (MAGICKCORE_QUANTUM_DEPTH == 16)
+#define MagickQuantumDepth  "Q16"
+#define MagickQuantumRange  "65535"
+#elif (MAGICKCORE_QUANTUM_DEPTH == 32)
+#define MagickQuantumDepth  "Q32"
+#define MagickQuantumRange  "4294967295"
+#elif (MAGICKCORE_QUANTUM_DEPTH == 64)
+#define MagickQuantumDepth  "Q64"
+#define MagickQuantumRange  "18446744073709551615"
+#else
+#define MagickQuantumDepth  "Q?"
+#define MagickQuantumRange  "?"
+#endif
+#define MagickVersion  \
+  MagickPackageName " " MagickLibVersionText MagickLibAddendum " " \
+  MagickReleaseDate " " MagickQuantumDepth " " MagickAuthoritativeURL
+
+extern MagickExport char
+  *GetMagickHomeURL(void);
+
+extern MagickExport const char
+  *GetMagickCopyright(void),
+  *GetMagickFeatures(void),
+  *GetMagickPackageName(void),
+  *GetMagickQuantumDepth(size_t *),
+  *GetMagickQuantumRange(size_t *),
+  *GetMagickReleaseDate(void),
+  *GetMagickVersion(size_t *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/vms.c b/MagickCore/vms.c
new file mode 100644
index 0000000..ff53923
--- /dev/null
+++ b/MagickCore/vms.c
@@ -0,0 +1,271 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                            V   V  M   M  SSSSS                              %
+%                            V   V  MM MM  SS                                 %
+%                            V   V  M M M   SSS                               %
+%                             V V   M   M     SS                              %
+%                              V    M   M  SSSSS                              %
+%                                                                             %
+%                                                                             %
+%                         MagickCore VMS Utility Methods                      %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                October 1994                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  The directory methods are strongly based on similar methods written
+%  by Rich Salz.
+%
+*/
+
+#if defined(vms)
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/vms.h"
+
+#if !defined(_AXP_) && (!defined(__VMS_VER) || (__VMS_VER < 70000000))
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   c l o s e d i r                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  closedir() closes the named directory stream and frees the DIR structure.
+%
+%  The format of the closedir method is:
+%
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+void closedir(DIR *directory)
+{
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(directory != (DIR *) NULL);
+  directory->pattern=DestroyString(directory->pattern);
+  directory=DestroyString(directory);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   o p e n d i r                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  opendir() opens the directory named by filename and associates a directory
+%  stream with it.
+%
+%  The format of the opendir method is:
+%
+%      opendir(entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+DIR *opendir(char *name)
+{
+  DIR
+    *directory;
+
+  /*
+    Allocate memory for handle and the pattern.
+  */
+  directory=(DIR *) AcquireMagickMemory(sizeof(DIR));
+  if (directory == (DIR *) NULL)
+    {
+      errno=ENOMEM;
+      return((DIR *) NULL);
+    }
+  if (strcmp(".",name) == 0)
+    name="";
+  directory->pattern=(char *) AcquireQuantumMemory(strlen(name)+sizeof("*.*")+
+    1UL,sizeof(*directory->pattern));
+  if (directory->pattern == (char *) NULL)
+    {
+      directory=DestroyString(directory);
+      errno=ENOMEM;
+      return(NULL);
+    }
+  /*
+    Initialize descriptor.
+  */
+  (void) FormatLocaleString(directory->pattern,MaxTextExtent,"%s*.*",name);
+  directory->context=0;
+  directory->pat.dsc$a_pointer=directory->pattern;
+  directory->pat.dsc$w_length=strlen(directory->pattern);
+  directory->pat.dsc$b_dtype=DSC$K_DTYPE_T;
+  directory->pat.dsc$b_class=DSC$K_CLASS_S;
+  return(directory);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   r e a d d i r                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  readdir() returns a pointer to a structure representing the directory entry
+%  at the current position in the directory stream to which entry refers.
+%
+%  The format of the readdir
+%
+%      readdir(entry)
+%
+%  A description of each parameter follows:
+%
+%    o entry: Specifies a pointer to a DIR structure.
+%
+%
+*/
+struct dirent *readdir(DIR *directory)
+{
+  char
+    buffer[sizeof(directory->entry.d_name)];
+
+  int
+    status;
+
+  register char
+    *p;
+
+  register int
+    i;
+
+  struct dsc$descriptor_s
+    result;
+
+  /*
+    Initialize the result descriptor.
+  */
+  result.dsc$a_pointer=buffer;
+  result.dsc$w_length=sizeof(buffer)-2;
+  result.dsc$b_dtype=DSC$K_DTYPE_T;
+  result.dsc$b_class=DSC$K_CLASS_S;
+  status=lib$find_file(&directory->pat,&result,&directory->context);
+  if ((status == RMS$_NMF) || (directory->context == 0L))
+    return((struct dirent *) NULL);
+  /*
+    Lowercase all filenames.
+  */
+  buffer[sizeof(buffer)-1]='\0';
+  for (p=buffer; *p; p++)
+    if (isupper((unsigned char) *p))
+      *p=tolower(*p);
+  /*
+    Skip any directory component and just copy the name.
+  */
+  p=buffer;
+  while (isspace((unsigned char) *p) == 0)
+    p++;
+  *p='\0';
+  p=strchr(buffer,']');
+  if (p)
+    (void) CopyMagickString(directory->entry.d_name,p+1,MaxTextExtent);
+  else
+    (void) CopyMagickString(directory->entry.d_name,buffer,MaxTextExtent);
+  directory->entry.d_namlen=strlen(directory->entry.d_name);
+  return(&directory->entry);
+}
+#endif /* !defined(_AXP_) && (!defined(__VMS_VER) || (__VMS_VER < 70000000)) */
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I s M a g i c k C o n f l i c t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  VMSIsMagickConflict() returns true if the image format conflicts with a
+%  logical drive (.e.g. SYS$SCRATCH:).
+%
+%  Contributed by Forrest Cahoon (forrest@wiredaemons.com)
+%
+%  The format of the VMSIsMagickConflict method is:
+%
+%      MagickBooleanType VMSIsMagickConflict(const char *magick)
+%
+%  A description of each parameter follows:
+%
+%    o magick: Specifies the image format.
+%
+%
+*/
+MagickExport MagickBooleanType VMSIsMagickConflict(const char *magick)
+{
+  ile3
+    item_list[2];
+
+  int
+    device_class,
+    status;
+
+  struct dsc$descriptor_s
+    device;
+
+  assert(magick != (char *) NULL);
+  device.dsc$w_length=strlen(magick);
+  device.dsc$a_pointer=(char *) magick;
+  device.dsc$b_class=DSC$K_CLASS_S;
+  device.dsc$b_dtype=DSC$K_DTYPE_T;
+  item_list[0].ile3$w_length=sizeof(device_class);
+  item_list[0].ile3$w_code=DVI$_DEVCLASS;
+  item_list[0].ile3$ps_bufaddr=&device_class;
+  item_list[0].ile3$ps_retlen_addr=NULL;
+  (void) ResetMagickMemory(&item_list[1],0,sizeof(item_list[1]));
+  status=sys$getdviw(0,0,&device,&item_list,0,0,0,0);
+  if ((status == SS$_NONLOCAL) ||
+      ((status & 0x01) && (device_class & (DC$_DISK | DC$_TAPE))))
+    return(MagickTrue);
+  return(MagickFalse);
+}
+#endif /* defined(vms) */
diff --git a/MagickCore/vms.h b/MagickCore/vms.h
new file mode 100644
index 0000000..0599a98
--- /dev/null
+++ b/MagickCore/vms.h
@@ -0,0 +1,985 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore VMS compatibility methods.
+*/
+#ifndef _MAGICKCORE_VMS_H
+#define _MAGICKCORE_VMS_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(__DECC) || defined(__DECCXX)
+#  include <lib$routines.h>
+#  include <starlet.h>
+#endif
+
+#include <errno.h>
+#include <descrip.h>
+#include <rmsdef.h>
+#include <ctype.h>
+#include <dvidef.h>
+#include <dcdef.h>
+#include <ssdef.h>
+
+#define DtSaverGetWindows DTSAVERGETWINDOWS
+#define XAddHosts XADDHOSTS
+#define XAllocClassHint XALLOCCLASSHINT
+#define XAllocColor XALLOCCOLOR
+#define XAllocColorCells XALLOCCOLORCELLS
+#define XAllocIconSize XALLOCICONSIZE
+#define XAllocNamedColor XALLOCNAMEDCOLOR
+#define XAllocSizeHints XALLOCSIZEHINTS
+#define XAllocStandardColormap XALLOCSTANDARDCOLORMAP
+#define XAllocWMHints XALLOCWMHINTS
+#define XAllowEvents XALLOWEVENTS
+#define XAutoRepeatOff XAUTOREPEATOFF
+#define XAutoRepeatOn XAUTOREPEATON
+#define XBaseFontNameListOfFontSet XBASEFONTNAMELISTOFFONTSET
+#define XBell XBELL
+#define XBitmapPad XBITMAPPAD
+#define XBlackPixel XBLACKPIXEL
+#define XBlackPixelOfScreen XBLACKPIXELOFSCREEN
+#define XChangeActivePointerGrab XCHANGEACTIVEPOINTERGRAB
+#define XChangeGC XCHANGEGC
+#define XChangeKeyboardControl XCHANGEKEYBOARDCONTROL
+#define XChangeProperty XCHANGEPROPERTY
+#define XChangeWindowAttributes XCHANGEWINDOWATTRIBUTES
+#define XCheckIfEvent XCHECKIFEVENT
+#define XCheckMaskEvent XCHECKMASKEVENT
+#define XCheckTypedWindowEvent XCHECKTYPEDWINDOWEVENT
+#define XCheckWindowEvent XCHECKWINDOWEVENT
+#define XClearArea XCLEARAREA
+#define XClearWindow XCLEARWINDOW
+#define XClipBox XCLIPBOX
+#define XCloseDisplay XCLOSEDISPLAY
+#define XCloseIM XCLOSEIM
+#define XConfigureWindow XCONFIGUREWINDOW
+#define XConvertSelection XCONVERTSELECTION
+#define XCopyArea XCOPYAREA
+#define XCopyColormapAndFree XCOPYCOLORMAPANDFREE
+#define XCopyGC XCOPYGC
+#define XCopyPlane XCOPYPLANE
+#define XCreateBitmapFromData XCREATEBITMAPFROMDATA
+#define XCreateColormap XCREATECOLORMAP
+#define XCreateFontCursor XCREATEFONTCURSOR
+#define XCreateFontSet XCREATEFONTSET
+#define XCreateGC XCREATEGC
+#define XCreateIC XCREATEIC
+#define XCreateImage XCREATEIMAGE
+#define XCreatePixmap XCREATEPIXMAP
+#define XCreatePixmapCursor XCREATEPIXMAPCURSOR
+#define XCreatePixmapFromBitmapData XCREATEPIXMAPFROMBITMAPDATA
+#define XCreateRegion XCREATEREGION
+#define XCreateSimpleWindow XCREATESIMPLEWINDOW
+#define XCreateWindow XCREATEWINDOW
+#define XDefaultColormap XDEFAULTCOLORMAP
+#define XDefaultColormapOfScreen XDEFAULTCOLORMAPOFSCREEN
+#define XDefaultDepth XDEFAULTDEPTH
+#define XDefaultGC XDEFAULTGC
+#define XDefaultRootWindow XDEFAULTROOTWINDOW
+#define XDefaultScreen XDEFAULTSCREEN
+#define XDefaultScreenOfDisplay XDEFAULTSCREENOFDISPLAY
+#define XDefaultVisual XDEFAULTVISUAL
+#define XDefineCursor XDEFINECURSOR
+#define XDeleteProperty XDELETEPROPERTY
+#define XDestroyIC XDESTROYIC
+#define XDestroyRegion XDESTROYREGION
+#define XDestroySubwindows XDESTROYSUBWINDOWS
+#define XDestroyWindow XDESTROYWINDOW
+#define XDisableAccessControl XDISABLEACCESSCONTROL
+#define XDisplayCells XDISPLAYCELLS
+#define XDisplayHeight XDISPLAYHEIGHT
+#define XDisplayName XDISPLAYNAME
+#define XDisplayOfScreen XDISPLAYOFSCREEN
+#define XDisplayWidth XDISPLAYWIDTH
+#define XDrawArc XDRAWARC
+#define XDrawArcs XDRAWARCS
+#define XDrawImageString XDRAWIMAGESTRING
+#define XDrawImageString16 XDRAWIMAGESTRING16
+#define XDrawLine XDRAWLINE
+#define XDrawLines XDRAWLINES
+#define XDrawPoint XDRAWPOINT
+#define XDrawPoints XDRAWPOINTS
+#define XDrawRectangle XDRAWRECTANGLE
+#define XDrawRectangles XDRAWRECTANGLES
+#define XDrawSegments XDRAWSEGMENTS
+#define XDrawString XDRAWSTRING
+#define XDrawString16 XDRAWSTRING16
+#define XDrawText XDRAWTEXT
+#define XEmptyRegion XEMPTYREGION
+#define XEnableAccessControl XENABLEACCESSCONTROL
+#define XEqualRegion XEQUALREGION
+#define XEventsQueued XEVENTSQUEUED
+#define XExtentsOfFontSet XEXTENTSOFFONTSET
+#define XFetchName XFETCHNAME
+#define XFillArc XFILLARC
+#define XFillArcs XFILLARCS
+#define XFillPolygon XFILLPOLYGON
+#define XFillRectangle XFILLRECTANGLE
+#define XFillRectangles XFILLRECTANGLES
+#define XFilterEvent XFILTEREVENT
+#define XFlush XFLUSH
+#define XFontsOfFontSet XFONTSOFFONTSET
+#define XForceScreenSaver XFORCESCREENSAVER
+#define XFree XFREE
+#define XFreeColormap XFREECOLORMAP
+#define XFreeColors XFREECOLORS
+#define XFreeCursor XFREECURSOR
+#define XFreeDeviceList XFREEDEVICELIST
+#define XFreeDeviceState XFREEDEVICESTATE
+#define XFreeFont XFREEFONT
+#define XFreeFontInfo XFREEFONTINFO
+#define XFreeFontNames XFREEFONTNAMES
+#define XFreeFontSet XFREEFONTSET
+#define XFreeGC XFREEGC
+#define XFreeModifiermap XFREEMODIFIERMAP
+#define XFreePixmap XFREEPIXMAP
+#define XFreeStringList XFREESTRINGLIST
+#define XGetAtomName XGETATOMNAME
+#define XGetCommand XGETCOMMAND
+#define XGetDefault XGETDEFAULT
+#define XGetErrorDatabaseText XGETERRORDATABASETEXT
+#define XGetErrorText XGETERRORTEXT
+#define XGetExtensionVersion XGETEXTENSIONVERSION
+#define XGetFontProperty XGETFONTPROPERTY
+#define XGetGCValues XGETGCVALUES
+#define XGetGeometry XGETGEOMETRY
+#define XGetICValues XGETICVALUES
+#define XGetIMValues XGETIMVALUES
+#define XGetIconName XGETICONNAME
+#define XGetIconSizes XGETICONSIZES
+#define XGetImage XGETIMAGE
+#define XGetKeyboardControl XGETKEYBOARDCONTROL
+#define XGetModifierMapping XGETMODIFIERMAPPING
+#define XGetMotionEvents XGETMOTIONEVENTS
+#define XGetNormalHints XGETNORMALHINTS
+#define XGetRGBColormaps XGETRGBCOLORMAPS
+#define XGetScreenSaver XGETSCREENSAVER
+#define XGetSelectionOwner XGETSELECTIONOWNER
+#define XGetSubImage XGETSUBIMAGE
+#define XGetVisualInfo XGETVISUALINFO
+#define XGetWMColormapWindows XGETWMCOLORMAPWINDOWS
+#define XGetWMHints XGETWMHINTS
+#define XGetWMName XGETWMNAME
+#define XGetWMNormalHints XGETWMNORMALHINTS
+#define XGetWindowAttributes XGETWINDOWATTRIBUTES
+#define XGetWindowProperty XGETWINDOWPROPERTY
+#define XGrabButton XGRABBUTTON
+#define XGrabKeyboard XGRABKEYBOARD
+#define XGrabPointer XGRABPOINTER
+#define XGrabServer XGRABSERVER
+#define XHeightOfScreen XHEIGHTOFSCREEN
+#define XIconifyWindow XICONIFYWINDOW
+#define XIfEvent XIFEVENT
+#define XInstallColormap XINSTALLCOLORMAP
+#define XInternAtom XINTERNATOM
+#define XIntersectRegion XINTERSECTREGION
+#define XKeycodeToKeysym XKEYCODETOKEYSYM
+#define XKeysymToKeycode XKEYSYMTOKEYCODE
+#define XKeysymToString XKEYSYMTOSTRING
+#define XKillClient XKILLCLIENT
+#define XListFonts XLISTFONTS
+#define XListFontsWithInfo XLISTFONTSWITHINFO
+#define XListHosts XLISTHOSTS
+#define XListInputDevices XLISTINPUTDEVICES
+#define XListInstalledColormaps XLISTINSTALLEDCOLORMAPS
+#define XListPixmapFormats XLISTPIXMAPFORMATS
+#define XListProperties XLISTPROPERTIES
+#define XLoadFont XLOADFONT
+#define XLoadQueryFont XLOADQUERYFONT
+#define XLookupColor XLOOKUPCOLOR
+#define XLookupKeysym XLOOKUPKEYSYM
+#define XLookupString XLOOKUPSTRING
+#define XLowerWindow XLOWERWINDOW
+#define XMapRaised XMAPRAISED
+#define XMapSubwindows XMAPSUBWINDOWS
+#define XMapWindow XMAPWINDOW
+#define XMatchVisualInfo XMATCHVISUALINFO
+#define XMaxRequestSize XMAXREQUESTSIZE
+#define XMoveResizeWindow XMOVERESIZEWINDOW
+#define XMoveWindow XMOVEWINDOW
+#define XNextEvent XNEXTEVENT
+#define XOffsetRegion XOFFSETREGION
+#define XOpenDevice XOPENDEVICE
+#define XOpenDisplay XOPENDISPLAY
+#define XOpenIM XOPENIM
+#define XParseColor XPARSECOLOR
+#define XParseGeometry XPARSEGEOMETRY
+#define XPeekEvent XPEEKEVENT
+#define XPeekIfEvent XPEEKIFEVENT
+#define XPending XPENDING
+#define XPointInRegion XPOINTINREGION
+#define XPolygonRegion XPOLYGONREGION
+#define XPutBackEvent XPUTBACKEVENT
+#define XPutImage XPUTIMAGE
+#define XQueryColor XQUERYCOLOR
+#define XQueryColors XQUERYCOLORS
+#define XQueryDeviceState XQUERYDEVICESTATE
+#define XQueryExtension XQUERYEXTENSION
+#define XQueryFont XQUERYFONT
+#define XQueryKeymap XQUERYKEYMAP
+#define XQueryPointer XQUERYPOINTER
+#define XQueryTree XQUERYTREE
+#define XRaiseWindow XRAISEWINDOW
+#define XReadBitmapFile XREADBITMAPFILE
+#define XRecolorCursor XRECOLORCURSOR
+#define XReconfigureWMWindow XRECONFIGUREWMWINDOW
+#define XRectInRegion XRECTINREGION
+#define XRefreshKeyboardMapping XREFRESHKEYBOARDMAPPING
+#define XRemoveHosts XREMOVEHOSTS
+#define XReparentWindow XREPARENTWINDOW
+#define XResetScreenSaver XRESETSCREENSAVER
+#define XResizeWindow XRESIZEWINDOW
+#define XResourceManagerString XRESOURCEMANAGERSTRING
+#define XRestackWindows XRESTACKWINDOWS
+#define XRootWindow XROOTWINDOW
+#define XRootWindowOfScreen XROOTWINDOWOFSCREEN
+#define XScreenNumberOfScreen XSCREENNUMBEROFSCREEN
+#define XScreenOfDisplay XSCREENOFDISPLAY
+#define XSelectAsyncEvent XSELECTASYNCEVENT
+#define XSelectAsyncInput XSELECTASYNCINPUT
+#define XSelectExtensionEvent XSELECTEXTENSIONEVENT
+#define XSelectInput XSELECTINPUT
+#define XSendEvent XSENDEVENT
+#define XServerVendor XSERVERVENDOR
+#define XSetBackground XSETBACKGROUND
+#define XSetClassHint XSETCLASSHINT
+#define XSetClipMask XSETCLIPMASK
+#define XSetClipOrigin XSETCLIPORIGIN
+#define XSetClipRectangles XSETCLIPRECTANGLES
+#define XSetCloseDownMode XSETCLOSEDOWNMODE
+#define XSetCommand XSETCOMMAND
+#define XSetDashes XSETDASHES
+#define XSetErrorHandler XSETERRORHANDLER
+#define XSetFillRule XSETFILLRULE
+#define XSetFillStyle XSETFILLSTYLE
+#define XSetFont XSETFONT
+#define XSetForeground XSETFOREGROUND
+#define XSetFunction XSETFUNCTION
+#define XSetGraphicsExposures XSETGRAPHICSEXPOSURES
+#define XSetICFocus XSETICFOCUS
+#define XSetICValues XSETICVALUES
+#define XSetIOErrorHandler XSETIOERRORHANDLER
+#define XSetIconName XSETICONNAME
+#define XSetInputFocus XSETINPUTFOCUS
+#define XSetLineAttributes XSETLINEATTRIBUTES
+#define XSetLocaleModifiers XSETLOCALEMODIFIERS
+#define XSetNormalHints XSETNORMALHINTS
+#define XSetPlaneMask XSETPLANEMASK
+#define XSetRegion XSETREGION
+#define XSetScreenSaver XSETSCREENSAVER
+#define XSetSelectionOwner XSETSELECTIONOWNER
+#define XSetStandardProperties XSETSTANDARDPROPERTIES
+#define XSetState XSETSTATE
+#define XSetStipple XSETSTIPPLE
+#define XSetSubwindowMode XSETSUBWINDOWMODE
+#define XSetTSOrigin XSETTSORIGIN
+#define XSetTile XSETTILE
+#define XSetTransientForHint XSETTRANSIENTFORHINT
+#define XSetWMColormapWindows XSETWMCOLORMAPWINDOWS
+#define XSetWMHints XSETWMHINTS
+#define XSetWMIconName XSETWMICONNAME
+#define XSetWMName XSETWMNAME
+#define XSetWMNormalHints XSETWMNORMALHINTS
+#define XSetWMProperties XSETWMPROPERTIES
+#define XSetWMProtocols XSETWMPROTOCOLS
+#define XSetWindowBackground XSETWINDOWBACKGROUND
+#define XSetWindowBackgroundPixmap XSETWINDOWBACKGROUNDPIXMAP
+#define XSetWindowColormap XSETWINDOWCOLORMAP
+#define XShapeCombineMask XSHAPECOMBINEMASK
+#define XShapeCombineRectangles XSHAPECOMBINERECTANGLES
+#define XShapeGetRectangles XSHAPEGETRECTANGLES
+#define XShrinkRegion XSHRINKREGION
+#define XStoreBytes XSTOREBYTES
+#define XStoreColor XSTORECOLOR
+#define XStoreColors XSTORECOLORS
+#define XStoreName XSTORENAME
+#define XStringListToTextProperty XSTRINGLISTTOTEXTPROPERTY
+#define XStringToKeysym XSTRINGTOKEYSYM
+#define XSubtractRegion XSUBTRACTREGION
+#define XSupportsLocale XSUPPORTSLOCALE
+#define XSync XSYNC
+#define XSynchronize XSYNCHRONIZE
+#define XTextExtents XTEXTEXTENTS
+#define XTextExtents16 XTEXTEXTENTS16
+#define XTextWidth XTEXTWIDTH
+#define XTextWidth16 XTEXTWIDTH16
+#define XTranslateCoordinates XTRANSLATECOORDINATES
+#define XUndefineCursor XUNDEFINECURSOR
+#define XUngrabButton XUNGRABBUTTON
+#define XUngrabKeyboard XUNGRABKEYBOARD
+#define XUngrabPointer XUNGRABPOINTER
+#define XUngrabServer XUNGRABSERVER
+#define XUninstallColormap XUNINSTALLCOLORMAP
+#define XUnionRectWithRegion XUNIONRECTWITHREGION
+#define XUnionRegion XUNIONREGION
+#define XUnmapWindow XUNMAPWINDOW
+#define XUnsetICFocus XUNSETICFOCUS
+#define XVaCreateNestedList XVACREATENESTEDLIST
+#define XVisualIDFromVisual XVISUALIDFROMVISUAL
+#define XWMGeometry XWMGEOMETRY
+#define XWarpPointer XWARPPOINTER
+#define XWhitePixel XWHITEPIXEL
+#define XWidthOfScreen XWIDTHOFSCREEN
+#define XWindowEvent XWINDOWEVENT
+#define XWithdrawWindow XWITHDRAWWINDOW
+#define XXorRegion XXORREGION
+#define XmActivateProtocol XMACTIVATEPROTOCOL
+#define XmAddProtocolCallback XMADDPROTOCOLCALLBACK
+#define XmAddProtocols XMADDPROTOCOLS
+#define XmChangeColor XMCHANGECOLOR
+#define XmClipboardCopy XMCLIPBOARDCOPY
+#define XmClipboardEndCopy XMCLIPBOARDENDCOPY
+#define XmClipboardInquireLength XMCLIPBOARDINQUIRELENGTH
+#define XmClipboardLock XMCLIPBOARDLOCK
+#define XmClipboardRetrieve XMCLIPBOARDRETRIEVE
+#define XmClipboardStartCopy XMCLIPBOARDSTARTCOPY
+#define XmClipboardUnlock XMCLIPBOARDUNLOCK
+#define XmCreateArrowButton XMCREATEARROWBUTTON
+#define XmCreateArrowButtonGadget XMCREATEARROWBUTTONGADGET
+#define XmCreateBulletinBoardDialog XMCREATEBULLETINBOARDDIALOG
+#define XmCreateCascadeButton XMCREATECASCADEBUTTON
+#define XmCreateCascadeButtonGadget XMCREATECASCADEBUTTONGADGET
+#define XmCreateDialogShell XMCREATEDIALOGSHELL
+#define XmCreateDragIcon XMCREATEDRAGICON
+#define XmCreateDrawingArea XMCREATEDRAWINGAREA
+#define XmCreateDrawnButton XMCREATEDRAWNBUTTON
+#define XmCreateErrorDialog XMCREATEERRORDIALOG
+#define XmCreateFileSelectionBox XMCREATEFILESELECTIONBOX
+#define XmCreateFileSelectionDialog XMCREATEFILESELECTIONDIALOG
+#define XmCreateForm XMCREATEFORM
+#define XmCreateFormDialog XMCREATEFORMDIALOG
+#define XmCreateFrame XMCREATEFRAME
+#define XmCreateInformationDialog XMCREATEINFORMATIONDIALOG
+#define XmCreateLabel XMCREATELABEL
+#define XmCreateLabelGadget XMCREATELABELGADGET
+#define XmCreateMainWindow XMCREATEMAINWINDOW
+#define XmCreateMenuBar XMCREATEMENUBAR
+#define XmCreateMessageBox XMCREATEMESSAGEBOX
+#define XmCreateMessageDialog XMCREATEMESSAGEDIALOG
+#define XmCreateOptionMenu XMCREATEOPTIONMENU
+#define XmCreatePanedWindow XMCREATEPANEDWINDOW
+#define XmCreatePopupMenu XMCREATEPOPUPMENU
+#define XmCreatePromptDialog XMCREATEPROMPTDIALOG
+#define XmCreatePulldownMenu XMCREATEPULLDOWNMENU
+#define XmCreatePushButton XMCREATEPUSHBUTTON
+#define XmCreatePushButtonGadget XMCREATEPUSHBUTTONGADGET
+#define XmCreateQuestionDialog XMCREATEQUESTIONDIALOG
+#define XmCreateRadioBox XMCREATERADIOBOX
+#define XmCreateRowColumn XMCREATEROWCOLUMN
+#define XmCreateScale XMCREATESCALE
+#define XmCreateScrollBar XMCREATESCROLLBAR
+#define XmCreateScrolledList XMCREATESCROLLEDLIST
+#define XmCreateScrolledText XMCREATESCROLLEDTEXT
+#define XmCreateScrolledWindow XMCREATESCROLLEDWINDOW
+#define XmCreateSelectionDialog XMCREATESELECTIONDIALOG
+#define XmCreateSeparator XMCREATESEPARATOR
+#define XmCreateSeparatorGadget XMCREATESEPARATORGADGET
+#define XmCreateTemplateDialog XMCREATETEMPLATEDIALOG
+#define XmCreateText XMCREATETEXT
+#define XmCreateTextField XMCREATETEXTFIELD
+#define XmCreateToggleButton XMCREATETOGGLEBUTTON
+#define XmCreateToggleButtonGadget XMCREATETOGGLEBUTTONGADGET
+#define XmCreateWarningDialog XMCREATEWARNINGDIALOG
+#define XmCvtCTToXmString XMCVTCTTOXMSTRING
+#define XmDestroyPixmap XMDESTROYPIXMAP
+#define XmDragStart XMDRAGSTART
+#define XmDropSiteRegister XMDROPSITEREGISTER
+#define XmDropSiteUnregister XMDROPSITEUNREGISTER
+#define XmDropSiteUpdate XMDROPSITEUPDATE
+#define XmDropTransferStart XMDROPTRANSFERSTART
+#define XmFileSelectionBoxGetChild XMFILESELECTIONBOXGETCHILD
+#define XmFileSelectionDoSearch XMFILESELECTIONDOSEARCH
+#define XmFontListAppendEntry XMFONTLISTAPPENDENTRY
+#define XmFontListCopy XMFONTLISTCOPY
+#define XmFontListCreate XMFONTLISTCREATE
+#define XmFontListEntryCreate XMFONTLISTENTRYCREATE
+#define XmFontListEntryFree XMFONTLISTENTRYFREE
+#define XmFontListEntryGetFont XMFONTLISTENTRYGETFONT
+#define XmFontListEntryGetTag XMFONTLISTENTRYGETTAG
+#define XmFontListEntryLoad XMFONTLISTENTRYLOAD
+#define XmFontListFree XMFONTLISTFREE
+#define XmFontListFreeFontContext XMFONTLISTFREEFONTCONTEXT
+#define XmFontListGetNextFont XMFONTLISTGETNEXTFONT
+#define XmFontListInitFontContext XMFONTLISTINITFONTCONTEXT
+#define XmFontListNextEntry XMFONTLISTNEXTENTRY
+#define XmGetColors XMGETCOLORS
+#define XmGetFocusWidget XMGETFOCUSWIDGET
+#define XmGetMenuCursor XMGETMENUCURSOR
+#define XmGetPixmap XMGETPIXMAP
+#define XmGetPixmapByDepth XMGETPIXMAPBYDEPTH
+#define XmGetTearOffControl XMGETTEAROFFCONTROL
+#define XmGetXmDisplay XMGETXMDISPLAY
+#define XmImMbLookupString XMIMMBLOOKUPSTRING
+#define XmImRegister XMIMREGISTER
+#define XmImSetFocusValues XMIMSETFOCUSVALUES
+#define XmImSetValues XMIMSETVALUES
+#define XmImUnregister XMIMUNREGISTER
+#define XmImUnsetFocus XMIMUNSETFOCUS
+#define XmInstallImage XMINSTALLIMAGE
+#define XmInternAtom XMINTERNATOM
+#define XmIsMotifWMRunning XMISMOTIFWMRUNNING
+#define XmListAddItem XMLISTADDITEM
+#define XmListAddItemUnselected XMLISTADDITEMUNSELECTED
+#define XmListAddItems XMLISTADDITEMS
+#define XmListAddItemsUnselected XMLISTADDITEMSUNSELECTED
+#define XmListDeleteAllItems XMLISTDELETEALLITEMS
+#define XmListDeleteItem XMLISTDELETEITEM
+#define XmListDeleteItemsPos XMLISTDELETEITEMSPOS
+#define XmListDeletePos XMLISTDELETEPOS
+#define XmListDeselectAllItems XMLISTDESELECTALLITEMS
+#define XmListDeselectPos XMLISTDESELECTPOS
+#define XmListGetKbdItemPos XMLISTGETKBDITEMPOS
+#define XmListGetMatchPos XMLISTGETMATCHPOS
+#define XmListGetSelectedPos XMLISTGETSELECTEDPOS
+#define XmListItemExists XMLISTITEMEXISTS
+#define XmListItemPos XMLISTITEMPOS
+#define XmListPosSelected XMLISTPOSSELECTED
+#define XmListReplaceItems XMLISTREPLACEITEMS
+#define XmListReplaceItemsPos XMLISTREPLACEITEMSPOS
+#define XmListSelectItem XMLISTSELECTITEM
+#define XmListSelectPos XMLISTSELECTPOS
+#define XmListSetBottomPos XMLISTSETBOTTOMPOS
+#define XmListSetItem XMLISTSETITEM
+#define XmListSetKbdItemPos XMLISTSETKBDITEMPOS
+#define XmListSetPos XMLISTSETPOS
+#define XmMainWindowSetAreas XMMAINWINDOWSETAREAS
+#define XmMenuPosition XMMENUPOSITION
+#define XmMessageBoxGetChild XMMESSAGEBOXGETCHILD
+#define XmOptionButtonGadget XMOPTIONBUTTONGADGET
+#define XmOptionLabelGadget XMOPTIONLABELGADGET
+#define XmProcessTraversal XMPROCESSTRAVERSAL
+#define XmQmotif XMQMOTIF
+#define XmRemoveProtocolCallback XMREMOVEPROTOCOLCALLBACK
+#define XmRemoveProtocols XMREMOVEPROTOCOLS
+#define XmRemoveTabGroup XMREMOVETABGROUP
+#define XmRepTypeGetId XMREPTYPEGETID
+#define XmRepTypeGetRecord XMREPTYPEGETRECORD
+#define XmRepTypeRegister XMREPTYPEREGISTER
+#define XmRepTypeValidValue XMREPTYPEVALIDVALUE
+#define XmScrollBarSetValues XMSCROLLBARSETVALUES
+#define XmScrolledWindowSetAreas XMSCROLLEDWINDOWSETAREAS
+#define XmSelectionBoxGetChild XMSELECTIONBOXGETCHILD
+#define XmSetColorCalculation XMSETCOLORCALCULATION
+#define XmStringByteCompare XMSTRINGBYTECOMPARE
+#define XmStringCompare XMSTRINGCOMPARE
+#define XmStringConcat XMSTRINGCONCAT
+#define XmStringCopy XMSTRINGCOPY
+#define XmStringCreate XMSTRINGCREATE
+#define XmStringCreateLocalized XMSTRINGCREATELOCALIZED
+#define XmStringCreateLtoR XMSTRINGCREATELTOR
+#define XmStringCreateSimple XMSTRINGCREATESIMPLE
+#define XmStringDraw XMSTRINGDRAW
+#define XmStringDrawUnderline XMSTRINGDRAWUNDERLINE
+#define XmStringExtent XMSTRINGEXTENT
+#define XmStringFree XMSTRINGFREE
+#define XmStringFreeContext XMSTRINGFREECONTEXT
+#define XmStringGetLtoR XMSTRINGGETLTOR
+#define XmStringGetNextComponent XMSTRINGGETNEXTCOMPONENT
+#define XmStringGetNextSegment XMSTRINGGETNEXTSEGMENT
+#define XmStringInitContext XMSTRINGINITCONTEXT
+#define XmStringLength XMSTRINGLENGTH
+#define XmStringLtoRCreate XMSTRINGLTORCREATE
+#define XmStringNConcat XMSTRINGNCONCAT
+#define XmStringSegmentCreate XMSTRINGSEGMENTCREATE
+#define XmStringWidth XMSTRINGWIDTH
+#define XmTextClearSelection XMTEXTCLEARSELECTION
+#define XmTextCopy XMTEXTCOPY
+#define XmTextCut XMTEXTCUT
+#define XmTextFieldClearSelection XMTEXTFIELDCLEARSELECTION
+#define XmTextFieldCopy XMTEXTFIELDCOPY
+#define XmTextFieldCut XMTEXTFIELDCUT
+#define XmTextFieldGetEditable XMTEXTFIELDGETEDITABLE
+#define XmTextFieldGetInsertionPosition XMTEXTFIELDGETINSERTIONPOSITION
+#define XmTextFieldGetLastPosition XMTEXTFIELDGETLASTPOSITION
+#define XmTextFieldGetMaxLength XMTEXTFIELDGETMAXLENGTH
+#define XmTextFieldGetSelection XMTEXTFIELDGETSELECTION
+#define XmTextFieldGetSelectionPosition XMTEXTFIELDGETSELECTIONPOSITION
+#define XmTextFieldGetString XMTEXTFIELDGETSTRING
+#define XmTextFieldInsert XMTEXTFIELDINSERT
+#define XmTextFieldPaste XMTEXTFIELDPASTE
+#define XmTextFieldRemove XMTEXTFIELDREMOVE
+#define XmTextFieldReplace XMTEXTFIELDREPLACE
+#define XmTextFieldSetAddMode XMTEXTFIELDSETADDMODE
+#define XmTextFieldSetHighlight XMTEXTFIELDSETHIGHLIGHT
+#define XmTextFieldSetInsertionPosition XMTEXTFIELDSETINSERTIONPOSITION
+#define XmTextFieldSetMaxLength XMTEXTFIELDSETMAXLENGTH
+#define XmTextFieldSetSelection XMTEXTFIELDSETSELECTION
+#define XmTextFieldSetString XMTEXTFIELDSETSTRING
+#define XmTextFieldShowPosition XMTEXTFIELDSHOWPOSITION
+#define XmTextGetCursorPosition XMTEXTGETCURSORPOSITION
+#define XmTextGetEditable XMTEXTGETEDITABLE
+#define XmTextGetInsertionPosition XMTEXTGETINSERTIONPOSITION
+#define XmTextGetLastPosition XMTEXTGETLASTPOSITION
+#define XmTextGetMaxLength XMTEXTGETMAXLENGTH
+#define XmTextGetSelection XMTEXTGETSELECTION
+#define XmTextGetSelectionPosition XMTEXTGETSELECTIONPOSITION
+#define XmTextGetString XMTEXTGETSTRING
+#define XmTextInsert XMTEXTINSERT
+#define XmTextPaste XMTEXTPASTE
+#define XmTextPosToXY XMTEXTPOSTOXY
+#define XmTextRemove XMTEXTREMOVE
+#define XmTextReplace XMTEXTREPLACE
+#define XmTextSetCursorPosition XMTEXTSETCURSORPOSITION
+#define XmTextSetEditable XMTEXTSETEDITABLE
+#define XmTextSetHighlight XMTEXTSETHIGHLIGHT
+#define XmTextSetInsertionPosition XMTEXTSETINSERTIONPOSITION
+#define XmTextSetSelection XMTEXTSETSELECTION
+#define XmTextSetString XMTEXTSETSTRING
+#define XmTextShowPosition XMTEXTSHOWPOSITION
+#define XmToggleButtonGadgetGetState XMTOGGLEBUTTONGADGETGETSTATE
+#define XmToggleButtonGadgetSetState XMTOGGLEBUTTONGADGETSETSTATE
+#define XmToggleButtonGetState XMTOGGLEBUTTONGETSTATE
+#define XmToggleButtonSetState XMTOGGLEBUTTONSETSTATE
+#define XmUninstallImage XMUNINSTALLIMAGE
+#define XmUpdateDisplay XMUPDATEDISPLAY
+#define XmVaCreateSimpleRadioBox XMVACREATESIMPLERADIOBOX
+#define XmbDrawString XMBDRAWSTRING
+#define XmbLookupString XMBLOOKUPSTRING
+#define XmbResetIC XMBRESETIC
+#define XmbSetWMProperties XMBSETWMPROPERTIES
+#define XmbTextEscapement XMBTEXTESCAPEMENT
+#define XmbTextExtents XMBTEXTEXTENTS
+#define XmbTextListToTextProperty XMBTEXTLISTTOTEXTPROPERTY
+#define XmbTextPropertyToTextList XMBTEXTPROPERTYTOTEXTLIST
+#define XmuClientWindow XMUCLIENTWINDOW
+#define XmuCvtStringToBitmap XMUCVTSTRINGTOBITMAP
+#define XmuLookupStandardColormap XMULOOKUPSTANDARDCOLORMAP
+#define XmuPrintDefaultErrorMessage XMUPRINTDEFAULTERRORMESSAGE
+#define XrmCombineDatabase XRMCOMBINEDATABASE
+#define XrmCombineFileDatabase XRMCOMBINEFILEDATABASE
+#define XrmDestroyDatabase XRMDESTROYDATABASE
+#define XrmGetDatabase XRMGETDATABASE
+#define XrmGetFileDatabase XRMGETFILEDATABASE
+#define XrmGetResource XRMGETRESOURCE
+#define XrmGetStringDatabase XRMGETSTRINGDATABASE
+#define XrmInitialize XRMINITIALIZE
+#define XrmMergeDatabases XRMMERGEDATABASES
+#define XrmParseCommand XRMPARSECOMMAND
+#define XrmPutFileDatabase XRMPUTFILEDATABASE
+#define XrmPutLineResource XRMPUTLINERESOURCE
+#define XrmPutStringResource XRMPUTSTRINGRESOURCE
+#define XrmQPutStringResource XRMQPUTSTRINGRESOURCE
+#define XrmQuarkToString XRMQUARKTOSTRING
+#define XrmStringToBindingQuarkList XRMSTRINGTOBINDINGQUARKLIST
+#define XrmStringToQuark XRMSTRINGTOQUARK
+#define XrmStringToQuark XRMSTRINGTOQUARK
+#define XtAddCallback XTADDCALLBACK
+#define XtAddCallbacks XTADDCALLBACKS
+#define XtAddConverter XTADDCONVERTER
+#define XtAddEventHandler XTADDEVENTHANDLER
+#define XtAddExposureToRegion XTADDEXPOSURETOREGION
+#define XtAddGrab XTADDGRAB
+#define XtAllocateGC XTALLOCATEGC
+#define XtAppAddActions XTAPPADDACTIONS
+#define XtAppAddInput XTAPPADDINPUT
+#define XtAppAddTimeOut XTAPPADDTIMEOUT
+#define XtAppAddWorkProc XTAPPADDWORKPROC
+#define XtAppCreateShell XTAPPCREATESHELL
+#define XtAppInitialize XTAPPINITIALIZE
+#define XtAppMainLoop XTAPPMAINLOOP
+#define XtAppNextEvent XTAPPNEXTEVENT
+#define XtAppPeekEvent XTAPPPEEKEVENT
+#define XtAppPending XTAPPPENDING
+#define XtAppProcessEvent XTAPPPROCESSEVENT
+#define XtAppSetErrorHandler XTAPPSETERRORHANDLER
+#define XtAppSetFallbackResources XTAPPSETFALLBACKRESOURCES
+#define XtAppSetWarningHandler XTAPPSETWARNINGHANDLER
+#define XtAppSetWarningMsgHandler XTAPPSETWARNINGMSGHANDLER
+#define XtAppWarning XTAPPWARNING
+#define XtCallActionProc XTCALLACTIONPROC
+#define XtCallCallbackList XTCALLCALLBACKLIST
+#define XtCallCallbacks XTCALLCALLBACKS
+#define XtCloseDisplay XTCLOSEDISPLAY
+#define XtConfigureWidget XTCONFIGUREWIDGET
+#define XtConvertAndStore XTCONVERTANDSTORE
+#define XtCreateApplicationContext XTCREATEAPPLICATIONCONTEXT
+#define XtCreateManagedWidget XTCREATEMANAGEDWIDGET
+#define XtCreatePopupShell XTCREATEPOPUPSHELL
+#define XtCreateWidget XTCREATEWIDGET
+#define XtDatabase XTDATABASE
+#define XtDestroyApplicationContext XTDESTROYAPPLICATIONCONTEXT
+#define XtDestroyWidget XTDESTROYWIDGET
+#define XtDisownSelection XTDISOWNSELECTION
+#define XtDispatchEvent XTDISPATCHEVENT
+#define XtDisplay XTDISPLAY
+#define XtDisplayOfObject XTDISPLAYOFOBJECT
+#define XtDisplayStringConvWarning XTDISPLAYSTRINGCONVWARNING
+#define XtDisplayToApplicationContext XTDISPLAYTOAPPLICATIONCONTEXT
+#define XtError XTERROR
+#define XtFree XTFREE
+#define XtGetActionKeysym XTGETACTIONKEYSYM
+#define XtGetActionList XTGETACTIONLIST
+#define XtGetApplicationNameAndClass XTGETAPPLICATIONNAMEANDCLASS
+#define XtGetApplicationResources XTGETAPPLICATIONRESOURCES
+#define XtGetGC XTGETGC
+#define XtGetMultiClickTime XTGETMULTICLICKTIME
+#define XtGetSelectionValue XTGETSELECTIONVALUE
+#define XtGetSelectionValues XTGETSELECTIONVALUES
+#define XtGetSubresources XTGETSUBRESOURCES
+#define XtGetValues XTGETVALUES
+#define XtGrabButton XTGRABBUTTON
+#define XtGrabKeyboard XTGRABKEYBOARD
+#define XtGrabPointer XTGRABPOINTER
+#define XtHasCallbacks XTHASCALLBACKS
+#define XtInitialize XTINITIALIZE
+#define XtInitializeWidgetClass XTINITIALIZEWIDGETCLASS
+#define XtInsertEventHandler XTINSERTEVENTHANDLER
+#define XtIsManaged XTISMANAGED
+#define XtIsObject XTISOBJECT
+#define XtIsRealized XTISREALIZED
+#define XtIsSensitive XTISSENSITIVE
+#define XtIsSubclass XTISSUBCLASS
+#define XtLastTimestampProcessed XTLASTTIMESTAMPPROCESSED
+#define XtMainLoop XTMAINLOOP
+#define XtMakeGeometryRequest XTMAKEGEOMETRYREQUEST
+#define XtMakeResizeRequest XTMAKERESIZEREQUEST
+#define XtMalloc XTMALLOC
+#define XtManageChild XTMANAGECHILD
+#define XtManageChildren XTMANAGECHILDREN
+#define XtMergeArgLists XTMERGEARGLISTS
+#define XtMoveWidget XTMOVEWIDGET
+#define XtName XTNAME
+#define XtNameToWidget XTNAMETOWIDGET
+#define XtOpenDisplay XTOPENDISPLAY
+#define XtOverrideTranslations XTOVERRIDETRANSLATIONS
+#define XtOwnSelection XTOWNSELECTION
+#define XtParseTranslationTable XTPARSETRANSLATIONTABLE
+#define XtPopdown XTPOPDOWN
+#define XtPopup XTPOPUP
+#define XtQueryGeometry XTQUERYGEOMETRY
+#define XtRealizeWidget XTREALIZEWIDGET
+#define XtRealloc XTREALLOC
+#define XtRegisterDrawable _XTREGISTERWINDOW
+#define XtReleaseGC XTRELEASEGC
+#define XtRemoveAllCallbacks XTREMOVEALLCALLBACKS
+#define XtRemoveCallback XTREMOVECALLBACK
+#define XtRemoveEventHandler XTREMOVEEVENTHANDLER
+#define XtRemoveGrab XTREMOVEGRAB
+#define XtRemoveInput XTREMOVEINPUT
+#define XtRemoveTimeOut XTREMOVETIMEOUT
+#define XtRemoveWorkProc XTREMOVEWORKPROC
+#define XtResizeWidget XTRESIZEWIDGET
+#define XtResolvePathname XTRESOLVEPATHNAME
+#define XtScreen XTSCREEN
+#define XtSetKeyboardFocus XTSETKEYBOARDFOCUS
+#define XtSetMappedWhenManaged XTSETMAPPEDWHENMANAGED
+#define XtSetSensitive XTSETSENSITIVE
+#define XtSetTypeConverter XTSETTYPECONVERTER
+#define XtSetValues XTSETVALUES
+#define XtShellStrings XTSHELLSTRINGS
+#define XtStrings XTSTRINGS
+#define XtToolkitInitialize XTTOOLKITINITIALIZE
+#define XtTranslateCoords XTTRANSLATECOORDS
+#define XtTranslateKeycode XTTRANSLATEKEYCODE
+#define XtUngrabButton XTUNGRABBUTTON
+#define XtUngrabKeyboard XTUNGRABKEYBOARD
+#define XtUngrabPointer XTUNGRABPOINTER
+#define XtUnmanageChild XTUNMANAGECHILD
+#define XtUnmanageChildren XTUNMANAGECHILDREN
+#define XtUnrealizeWidget XTUNREALIZEWIDGET
+#define XtUnregisterDrawable _XTUNREGISTERWINDOW
+#define XtVaCreateManagedWidget XTVACREATEMANAGEDWIDGET
+#define XtVaCreatePopupShell XTVACREATEPOPUPSHELL
+#define XtVaCreateWidget XTVACREATEWIDGET
+#define XtVaGetValues XTVAGETVALUES
+#define XtVaSetValues XTVASETVALUES
+#define XtWarning XTWARNING
+#define XtWidgetToApplicationContext XTWIDGETTOAPPLICATIONCONTEXT
+#define XtWindow XTWINDOW
+#define XtWindowOfObject XTWINDOWOFOBJECT
+#define XtWindowToWidget XTWINDOWTOWIDGET
+#define XwcDrawString XWCDRAWSTRING
+#define XwcFreeStringList XWCFREESTRINGLIST
+#define XwcTextEscapement XWCTEXTESCAPEMENT
+#define XwcTextExtents XWCTEXTEXTENTS
+#define XwcTextListToTextProperty XWCTEXTLISTTOTEXTPROPERTY
+#define XwcTextPropertyToTextList XWCTEXTPROPERTYTOTEXTLIST
+#define _XRegisterFilterByType _XREGISTERFILTERBYTYPE
+#define _XUnregisterFilter _XUNREGISTERFILTER
+#define _XmBottomShadowColorDefault _XMBOTTOMSHADOWCOLORDEFAULT
+#define _XmClearBorder _XMCLEARBORDER
+#define _XmConfigureObject _XMCONFIGUREOBJECT
+#define _XmDestroyParentCallback _XMDESTROYPARENTCALLBACK
+#define _XmDrawArrow _XMDRAWARROW
+#define _XmDrawShadows _XMDRAWSHADOWS
+#define _XmFontListGetDefaultFont _XMFONTLISTGETDEFAULTFONT
+#define _XmFromHorizontalPixels _XMFROMHORIZONTALPIXELS
+#define _XmFromVerticalPixels _XMFROMVERTICALPIXELS
+#define _XmGetClassExtensionPtr _XMGETCLASSEXTENSIONPTR
+#define _XmGetDefaultFontList _XMGETDEFAULTFONTLIST
+#define _XmGetTextualDragIcon _XMGETTEXTUALDRAGICON
+#define _XmGetWidgetExtData _XMGETWIDGETEXTDATA
+#define _XmGrabKeyboard _XMGRABKEYBOARD
+#define _XmGrabPointer _XMGRABPOINTER
+#define _XmInheritClass _XMINHERITCLASS
+#define _XmInputInGadget _XMINPUTINGADGET
+#define _XmMakeGeometryRequest _XMMAKEGEOMETRYREQUEST
+#define _XmMenuPopDown _XMMENUPOPDOWN
+#define _XmMoveObject _XMMOVEOBJECT
+#define _XmNavigChangeManaged _XMNAVIGCHANGEMANAGED
+#define _XmOSBuildFileList _XMOSBUILDFILELIST
+#define _XmOSFileCompare _XMOSFILECOMPARE
+#define _XmOSFindPatternPart _XMOSFINDPATTERNPART
+#define _XmOSQualifyFileSpec _XMOSQUALIFYFILESPEC
+#define _XmPostPopupMenu _XMPOSTPOPUPMENU
+#define _XmPrimitiveEnter _XMPRIMITIVEENTER
+#define _XmPrimitiveLeave _XMPRIMITIVELEAVE
+#define _XmRedisplayGadgets _XMREDISPLAYGADGETS
+#define _XmShellIsExclusive _XMSHELLISEXCLUSIVE
+#define _XmStringDraw _XMSTRINGDRAW
+#define _XmStringGetTextConcat _XMSTRINGGETTEXTCONCAT
+#define _XmStrings _XMSTRINGS
+#define _XmToHorizontalPixels _XMTOHORIZONTALPIXELS
+#define _XmToVerticalPixels _XMTOVERTICALPIXELS
+#define _XmTopShadowColorDefault _XMTOPSHADOWCOLORDEFAULT
+#define _Xm_fastPtr _XM_FASTPTR
+#define _XtCheckSubclassFlag _XTCHECKSUBCLASSFLAG
+#define _XtInherit _XTINHERIT
+#define _XtInheritTranslations _XTINHERITTRANSLATIONS
+#define applicationShellWidgetClass APPLICATIONSHELLWIDGETCLASS
+#define compositeWidgetClass COMPOSITEWIDGETCLASS
+#define lib$ediv LIB$EDIV
+#define lib$find_file LIB$FIND_FILE
+#define lib$find_file_end LIB$FIND_FILE_END
+#define lib$set_symbol LIB$SET_SYMBOL
+#define lib$sfree1_dd LIB$SFREE1_DD
+#define lib$spawn LIB$SPAWN
+#define lib$subx LIB$SUBX
+#define lib$wait LIB$WAIT
+#define overrideShellWidgetClass OVERRIDESHELLWIDGETCLASS
+#define pthread_attr_create PTHREAD_ATTR_CREATE
+#define pthread_attr_delete PTHREAD_ATTR_DELETE
+#define pthread_attr_destroy PTHREAD_ATTR_DESTROY
+#define pthread_attr_getdetach_np PTHREAD_ATTR_GETDETACH_NP
+#define pthread_attr_getguardsize_np PTHREAD_ATTR_GETGUARDSIZE_NP
+#define pthread_attr_getinheritsched PTHREAD_ATTR_GETINHERITSCHED
+#define pthread_attr_getprio PTHREAD_ATTR_GETPRIO
+#define pthread_attr_getsched PTHREAD_ATTR_GETSCHED
+#define pthread_attr_getschedparam PTHREAD_ATTR_GETSCHEDPARAM
+#define pthread_attr_getschedpolicy PTHREAD_ATTR_GETSCHEDPOLICY
+#define pthread_attr_getstacksize PTHREAD_ATTR_GETSTACKSIZE
+#define pthread_attr_init PTHREAD_ATTR_INIT
+#define pthread_attr_setdetach_np PTHREAD_ATTR_SETDETACH_NP
+#define pthread_attr_setdetachstate PTHREAD_ATTR_SETDETACHSTATE
+#define pthread_attr_setguardsize_np PTHREAD_ATTR_SETGUARDSIZE_NP
+#define pthread_attr_setinheritsched PTHREAD_ATTR_SETINHERITSCHED
+#define pthread_attr_setprio PTHREAD_ATTR_SETPRIO
+#define pthread_attr_setsched PTHREAD_ATTR_SETSCHED
+#define pthread_attr_setschedparam PTHREAD_ATTR_SETSCHEDPARAM
+#define pthread_attr_setschedpolicy PTHREAD_ATTR_SETSCHEDPOLICY
+#define pthread_attr_setstacksize PTHREAD_ATTR_SETSTACKSIZE
+#define pthread_cancel PTHREAD_CANCEL
+#define pthread_cancel_e PTHREAD_CANCEL_E
+#define pthread_cond_broadcast PTHREAD_COND_BROADCAST
+#define pthread_cond_destroy PTHREAD_COND_DESTROY
+#define pthread_cond_init PTHREAD_COND_INIT
+#define pthread_cond_sig_preempt_int_np PTHREAD_COND_SIG_PREEMPT_INT_NP
+#define pthread_cond_signal PTHREAD_COND_SIGNAL
+#define pthread_cond_signal_int_np PTHREAD_COND_SIGNAL_INT_NP
+#define pthread_cond_timedwait PTHREAD_COND_TIMEDWAIT
+#define pthread_cond_wait PTHREAD_COND_WAIT
+#define pthread_condattr_create PTHREAD_CONDATTR_CREATE
+#define pthread_condattr_delete PTHREAD_CONDATTR_DELETE
+#define pthread_condattr_init PTHREAD_CONDATTR_INIT
+#define pthread_create PTHREAD_CREATE
+#define pthread_delay_np PTHREAD_DELAY_NP
+#define pthread_detach PTHREAD_DETACH
+#define pthread_equal PTHREAD_EQUAL
+#define pthread_exc_fetch_fp_np PTHREAD_EXC_FETCH_FP_NP
+#define pthread_exc_handler_np PTHREAD_EXC_HANDLER_NP
+#define pthread_exc_pop_ctx_np PTHREAD_EXC_POP_CTX_NP
+#define pthread_exc_push_ctx_np PTHREAD_EXC_PUSH_CTX_NP
+#define pthread_exc_savecontext_np PTHREAD_EXC_SAVECONTEXT_NP
+#define pthread_exit PTHREAD_EXIT
+#define pthread_get_expiration_np PTHREAD_GET_EXPIRATION_NP
+#define pthread_getprio PTHREAD_GETPRIO
+#define pthread_getschedparam PTHREAD_GETSCHEDPARAM
+#define pthread_getscheduler PTHREAD_GETSCHEDULER
+#define pthread_getspecific PTHREAD_GETSPECIFIC
+#define pthread_getunique_np PTHREAD_GETUNIQUE_NP
+#define pthread_join PTHREAD_JOIN
+#define pthread_join32 PTHREAD_JOIN32
+#define pthread_key_create PTHREAD_KEY_CREATE
+#define pthread_key_delete PTHREAD_KEY_DELETE
+#define pthread_keycreate PTHREAD_KEYCREATE
+#define pthread_kill PTHREAD_KILL
+#define pthread_lock_global_np PTHREAD_LOCK_GLOBAL_NP
+#define pthread_mutex_destroy PTHREAD_MUTEX_DESTROY
+#define pthread_mutex_init PTHREAD_MUTEX_INIT
+#define pthread_mutex_lock PTHREAD_MUTEX_LOCK
+#define pthread_mutex_trylock PTHREAD_MUTEX_TRYLOCK
+#define pthread_mutex_unlock PTHREAD_MUTEX_UNLOCK
+#define pthread_mutexattr_create PTHREAD_MUTEXATTR_CREATE
+#define pthread_mutexattr_delete PTHREAD_MUTEXATTR_DELETE
+#define pthread_mutexattr_destroy PTHREAD_MUTEXATTR_DESTROY
+#define pthread_mutexattr_getkind_np PTHREAD_MUTEXATTR_GETKIND_NP
+#define pthread_mutexattr_init PTHREAD_MUTEXATTR_INIT
+#define pthread_mutexattr_setkind_np PTHREAD_MUTEXATTR_SETKIND_NP
+#define pthread_mutexattr_settype_np PTHREAD_MUTEXATTR_SETTYPE_NP
+#define pthread_once PTHREAD_ONCE
+#define pthread_resume_np PTHREAD_RESUME_NP
+#define pthread_self PTHREAD_SELF
+#define pthread_setasynccancel PTHREAD_SETASYNCCANCEL
+#define pthread_setcancel PTHREAD_SETCANCEL
+#define pthread_setcancelstate PTHREAD_SETCANCELSTATE
+#define pthread_setprio PTHREAD_SETPRIO
+#define pthread_setschedparam PTHREAD_SETSCHEDPARAM
+#define pthread_setscheduler PTHREAD_SETSCHEDULER
+#define pthread_setspecific PTHREAD_SETSPECIFIC
+#define pthread_suspend_np PTHREAD_SUSPEND_NP
+#define pthread_testcancel PTHREAD_TESTCANCEL
+#define pthread_unlock_global_np PTHREAD_UNLOCK_GLOBAL_NP
+#define pthread_yield PTHREAD_YIELD
+#define pthread_yield_np PTHREAD_YIELD_NP
+#define pthread_exc_raise_np PTHREAD_EXC_RAISE_NP
+#define pthread_setcanceltype PTHREAD_SETCANCELTYPE
+#define shellWidgetClass SHELLWIDGETCLASS
+#define sys$assign SYS$ASSIGN
+#define sys$bintim SYS$BINTIM
+#define sys$crembx SYS$CREMBX
+#define sys$dassgn SYS$DASSGN
+#define sys$dclexh SYS$DCLEXH
+#define sys$getdviw SYS$GETDVIW
+#define sys$getsyiw SYS$GETSYIW
+#define sys$gettim SYS$GETTIM
+#define sys$qio SYS$QIO
+#define sys$qiow SYS$QIOW
+#define sys$setef SYS$SETEF
+#define sys$synch SYS$SYNCH
+#define topLevelShellClassRec TOPLEVELSHELLCLASSREC
+#define topLevelShellWidgetClass TOPLEVELSHELLWIDGETCLASS
+#define transientShellWidgetClass TRANSIENTSHELLWIDGETCLASS
+#define vendorShellClassRec VENDORSHELLCLASSREC
+#define vendorShellWidgetClass VENDORSHELLWIDGETCLASS
+#define wmShellWidgetClass WMSHELLWIDGETCLASS
+#define xmArrowButtonWidgetClass XMARROWBUTTONWIDGETCLASS
+#define xmBulletinBoardWidgetClass XMBULLETINBOARDWIDGETCLASS
+#define xmCascadeButtonClassRec XMCASCADEBUTTONCLASSREC
+#define xmCascadeButtonGadgetClass XMCASCADEBUTTONGADGETCLASS
+#define xmCascadeButtonWidgetClass XMCASCADEBUTTONWIDGETCLASS
+#define xmDialogShellWidgetClass XMDIALOGSHELLWIDGETCLASS
+#define xmDrawingAreaWidgetClass XMDRAWINGAREAWIDGETCLASS
+#define xmDrawnButtonWidgetClass XMDRAWNBUTTONWIDGETCLASS
+#define xmFileSelectionBoxWidgetClass XMFILESELECTIONBOXWIDGETCLASS
+#define xmFormWidgetClass XMFORMWIDGETCLASS
+#define xmFrameWidgetClass XMFRAMEWIDGETCLASS
+#define xmGadgetClass XMGADGETCLASS
+#define xmLabelGadgetClass XMLABELGADGETCLASS
+#define xmLabelWidgetClass XMLABELWIDGETCLASS
+#define xmListWidgetClass XMLISTWIDGETCLASS
+#define xmMainWindowWidgetClass XMMAINWINDOWWIDGETCLASS
+#define xmManagerClassRec XMMANAGERCLASSREC
+#define xmManagerWidgetClass XMMANAGERWIDGETCLASS
+#define xmMenuShellWidgetClass XMMENUSHELLWIDGETCLASS
+#define xmMessageBoxWidgetClass XMMESSAGEBOXWIDGETCLASS
+#define xmPrimitiveClassRec XMPRIMITIVECLASSREC
+#define xmPrimitiveWidgetClass XMPRIMITIVEWIDGETCLASS
+#define xmPushButtonClassRec XMPUSHBUTTONCLASSREC
+#define xmPushButtonGadgetClass XMPUSHBUTTONGADGETCLASS
+#define xmPushButtonWidgetClass XMPUSHBUTTONWIDGETCLASS
+#define xmRowColumnWidgetClass XMROWCOLUMNWIDGETCLASS
+#define xmSashWidgetClass XMSASHWIDGETCLASS
+#define xmScaleWidgetClass XMSCALEWIDGETCLASS
+#define xmScrollBarWidgetClass XMSCROLLBARWIDGETCLASS
+#define xmScrolledWindowClassRec XMSCROLLEDWINDOWCLASSREC
+#define xmScrolledWindowWidgetClass XMSCROLLEDWINDOWWIDGETCLASS
+#define xmSeparatorGadgetClass XMSEPARATORGADGETCLASS
+#define xmSeparatorWidgetClass XMSEPARATORWIDGETCLASS
+#define xmTextFieldWidgetClass XMTEXTFIELDWIDGETCLASS
+#define xmTextWidgetClass XMTEXTWIDGETCLASS
+#define xmToggleButtonGadgetClass XMTOGGLEBUTTONGADGETCLASS
+#define xmToggleButtonWidgetClass XMTOGGLEBUTTONWIDGETCLASS
+#define XInitImage XINITIMAGE
+#define _XInitImageFuncPtrs _XINITIMAGEFUNCPTRS
+#define XtParent XTPARENT
+#define XConnectionNumber XCONNECTIONNUMBER
+#define XDrawText16 XDRAWTEXT16
+#define XFindContext XFINDCONTEXT
+#define XGetInputFocus XGETINPUTFOCUS
+#define XSaveContext XSAVECONTEXT
+#define XUniqueContext XUNIQUECONTEXT
+#define XChangePointerControl XCHANGEPOINTERCONTROL
+#pragma __member_alignment __save
+typedef struct _ile3
+{
+#pragma __nomember_alignment
+  unsigned short int
+    ile3$w_length,
+    ile3$w_code;
+
+  void
+    *ile3$ps_bufaddr;
+
+  unsigned short int
+    *ile3$ps_retlen_addr;
+} ile3;
+#pragma __member_alignment __restore
+
+
+#if defined(__VMS_VER) && (__VMS_VER >= 70000000)
+#include <dirent.h>
+#else
+
+/*
+  Typedef declarations.
+*/
+struct dirent
+{
+  char
+    d_name[255];
+
+  int
+    d_namlen;
+};
+
+typedef struct _dirdesc
+{
+  long
+    context;
+
+  char
+    *pattern;
+
+  struct dirent
+    entry;
+
+  struct dsc$descriptor_s
+    pat;
+} DIR;
+
+extern DIR
+  *opendir(char *);
+
+extern struct dirent
+  *readdir(DIR *);
+
+extern void
+  closedir(DIR *);
+#endif
+
+extern MagickExport MagickBooleanType
+  VMSIsMagickConflict(const char *);
+
+extern void
+  XtFree(char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/widget.c b/MagickCore/widget.c
new file mode 100644
index 0000000..9d77007
--- /dev/null
+++ b/MagickCore/widget.c
@@ -0,0 +1,9655 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                  W   W  IIIII  DDDD    GGGG  EEEEE  TTTTT                   %
+%                  W   W    I    D   D  G      E        T                     %
+%                  W W W    I    D   D  G  GG  EEE      T                     %
+%                  WW WW    I    D   D  G   G  E        T                     %
+%                  W   W  IIIII  DDDD    GGGG  EEEEE    T                     %
+%                                                                             %
+%                                                                             %
+%                   MagickCore X11 User Interface Methods                     %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                              September 1993                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/PreRvIcccm.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/token.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/xwindow-private.h"
+#include "MagickCore/widget.h"
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+
+/*
+  Define declarations.
+*/
+#define AreaIsActive(matte_info,position)  ( \
+  ((position.y >= (int) (matte_info.y-matte_info.bevel_width)) &&  \
+   (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
+   ? MagickTrue : MagickFalse)
+#define Extent(s)  ((int) strlen(s))
+#define MatteIsActive(matte_info,position)  ( \
+  ((position.x >= (int) (matte_info.x-matte_info.bevel_width)) && \
+   (position.y >= (int) (matte_info.y-matte_info.bevel_width)) &&  \
+   (position.x < (int) (matte_info.x+matte_info.width+matte_info.bevel_width)) &&  \
+   (position.y < (int) (matte_info.y+matte_info.height+matte_info.bevel_width))) \
+   ? MagickTrue : MagickFalse)
+#define MaxTextWidth  ((unsigned int) (255*XTextWidth(font_info,"_",1)))
+#define MinTextWidth  (26*XTextWidth(font_info,"_",1))
+#define QuantumMargin   MagickMax(font_info->max_bounds.width,12)
+#define WidgetTextWidth(font_info,text)  \
+  ((unsigned int) XTextWidth(font_info,text,Extent(text)))
+#define WindowIsActive(window_info,position)  ( \
+  ((position.x >= 0) && (position.y >= 0) &&  \
+   (position.x < (int) window_info.width) &&  \
+   (position.y < (int) window_info.height)) ? MagickTrue : MagickFalse)
+
+/*
+  Enum declarations.
+*/
+typedef enum
+{
+  ControlState = 0x0001,
+  InactiveWidgetState = 0x0004,
+  JumpListState = 0x0008,
+  RedrawActionState = 0x0010,
+  RedrawListState = 0x0020,
+  RedrawWidgetState = 0x0040,
+  UpdateListState = 0x0100
+} WidgetState;
+
+/*
+  Typedef declarations.
+*/
+typedef struct _XWidgetInfo
+{
+  char
+    *cursor,
+    *text,
+    *marker;
+
+  int
+    id;
+
+  unsigned int
+    bevel_width,
+    width,
+    height;
+
+  int
+    x,
+    y,
+    min_y,
+    max_y;
+
+  MagickStatusType
+    raised,
+    active,
+    center,
+    trough,
+    highlight;
+} XWidgetInfo;
+
+/*
+  Variable declarations.
+*/
+static XWidgetInfo
+  monitor_info =
+  {
+    (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
+    MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
+  },
+  submenu_info =
+  {
+    (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
+    MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
+  },
+  *selection_info = (XWidgetInfo *) NULL,
+  toggle_info =
+  {
+    (char *) NULL, (char *) NULL, (char *) NULL, 0, 0, 0, 0, 0, 0, 0, 0,
+    MagickFalse, MagickFalse, MagickFalse, MagickFalse, MagickFalse
+  };
+
+/*
+  Constant declarations.
+*/
+static const int
+  BorderOffset = 4,
+  DoubleClick = 250;
+
+/*
+  Method prototypes.
+*/
+static void
+  XDrawMatte(Display *,const XWindowInfo *,const XWidgetInfo *),
+  XSetBevelColor(Display *,const XWindowInfo *,const MagickStatusType),
+  XSetMatteColor(Display *,const XWindowInfo *,const MagickStatusType),
+  XSetTextColor(Display *,const XWindowInfo *,const MagickStatusType);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y X W i d g e t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyXWidget() destroys resources associated with the X widget.
+%
+%  The format of the DestroyXWidget method is:
+%
+%      void DestroyXWidget()
+%
+%  A description of each parameter follows:
+%
+*/
+MagickExport void DestroyXWidget(void)
+{
+  if (selection_info != (XWidgetInfo *) NULL)
+    selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w B e v e l                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawBevel() "sets off" an area with a highlighted upper and left bevel and
+%  a shadowed lower and right bevel.  The highlighted and shadowed bevels
+%  create a 3-D effect.
+%
+%  The format of the XDrawBevel function is:
+%
+%      XDrawBevel(display,window_info,bevel_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o bevel_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the bevel.
+%
+*/
+static void XDrawBevel(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *bevel_info)
+{
+  int
+    x1,
+    x2,
+    y1,
+    y2;
+
+  unsigned int
+    bevel_width;
+
+  XPoint
+    points[6];
+
+  /*
+    Draw upper and left beveled border.
+  */
+  x1=bevel_info->x;
+  y1=bevel_info->y+bevel_info->height;
+  x2=bevel_info->x+bevel_info->width;
+  y2=bevel_info->y;
+  bevel_width=bevel_info->bevel_width;
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x1;
+  points[1].y=y2;
+  points[2].x=x2;
+  points[2].y=y2;
+  points[3].x=x2+bevel_width;
+  points[3].y=y2-bevel_width;
+  points[4].x=x1-bevel_width;
+  points[4].y=y2-bevel_width;
+  points[5].x=x1-bevel_width;
+  points[5].y=y1+bevel_width;
+  XSetBevelColor(display,window_info,bevel_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,6,Complex,CoordModeOrigin);
+  /*
+    Draw lower and right beveled border.
+  */
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y1;
+  points[2].x=x2;
+  points[2].y=y2;
+  points[3].x=x2+bevel_width;
+  points[3].y=y2-bevel_width;
+  points[4].x=x2+bevel_width;
+  points[4].y=y1+bevel_width;
+  points[5].x=x1-bevel_width;
+  points[5].y=y1+bevel_width;
+  XSetBevelColor(display,window_info,!bevel_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,6,Complex,CoordModeOrigin);
+  (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w B e v e l e d B u t t o n                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawBeveledButton() draws a button with a highlighted upper and left bevel
+%  and a shadowed lower and right bevel.  The highlighted and shadowed bevels
+%  create a 3-D effect.
+%
+%  The format of the XDrawBeveledButton function is:
+%
+%      XDrawBeveledButton(display,window_info,button_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o button_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the button.
+%
+*/
+
+static inline int MagickAbsoluteValue(const int x)
+{
+  if (x < 0)
+    return(-x);
+  return(x);
+}
+
+static inline int MagickMax(const int x,const int y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline int MagickMin(const int x,const int y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+static void XDrawBeveledButton(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *button_info)
+{
+  int
+    x,
+    y;
+
+  unsigned int
+    width;
+
+  XFontStruct
+    *font_info;
+
+  XRectangle
+    crop_info;
+
+  /*
+    Draw matte.
+  */
+  XDrawBevel(display,window_info,button_info);
+  XSetMatteColor(display,window_info,button_info->raised);
+  (void) XFillRectangle(display,window_info->id,window_info->widget_context,
+    button_info->x,button_info->y,button_info->width,button_info->height);
+  x=button_info->x-button_info->bevel_width-1;
+  y=button_info->y-button_info->bevel_width-1;
+  (void) XSetForeground(display,window_info->widget_context,
+    window_info->pixel_info->trough_color.pixel);
+  if (button_info->raised || (window_info->depth == 1))
+    (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
+      x,y,button_info->width+(button_info->bevel_width << 1)+1,
+      button_info->height+(button_info->bevel_width << 1)+1);
+  if (button_info->text == (char *) NULL)
+    return;
+  /*
+    Set cropping region.
+  */
+  crop_info.width=(unsigned short) button_info->width;
+  crop_info.height=(unsigned short) button_info->height;
+  crop_info.x=button_info->x;
+  crop_info.y=button_info->y;
+  /*
+    Draw text.
+  */
+  font_info=window_info->font_info;
+  width=WidgetTextWidth(font_info,button_info->text);
+  x=button_info->x+(QuantumMargin >> 1);
+  if (button_info->center)
+    x=button_info->x+(button_info->width >> 1)-(width >> 1);
+  y=button_info->y+((button_info->height-
+    (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
+  if ((int) button_info->width == (QuantumMargin >> 1))
+    {
+      /*
+        Option button-- write label to right of button.
+      */
+      XSetTextColor(display,window_info,MagickTrue);
+      x=button_info->x+button_info->width+button_info->bevel_width+
+        (QuantumMargin >> 1);
+      (void) XDrawString(display,window_info->id,window_info->widget_context,
+        x,y,button_info->text,Extent(button_info->text));
+      return;
+    }
+  (void) XSetClipRectangles(display,window_info->widget_context,0,0,&crop_info,
+    1,Unsorted);
+  XSetTextColor(display,window_info,button_info->raised);
+  (void) XDrawString(display,window_info->id,window_info->widget_context,x,y,
+    button_info->text,Extent(button_info->text));
+  (void) XSetClipMask(display,window_info->widget_context,None);
+  if (button_info->raised == MagickFalse)
+    XDelay(display,SuspendTime << 2);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w B e v e l e d M a t t e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawBeveledMatte() draws a matte with a shadowed upper and left bevel and
+%  a highlighted lower and right bevel.  The highlighted and shadowed bevels
+%  create a 3-D effect.
+%
+%  The format of the XDrawBeveledMatte function is:
+%
+%      XDrawBeveledMatte(display,window_info,matte_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the matte.
+%
+*/
+static void XDrawBeveledMatte(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *matte_info)
+{
+  /*
+    Draw matte.
+  */
+  XDrawBevel(display,window_info,matte_info);
+  XDrawMatte(display,window_info,matte_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w M a t t e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawMatte() fills a rectangular area with the matte color.
+%
+%  The format of the XDrawMatte function is:
+%
+%      XDrawMatte(display,window_info,matte_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o matte_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the matte.
+%
+*/
+static void XDrawMatte(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *matte_info)
+{
+  /*
+    Draw matte.
+  */
+  if ((matte_info->trough == MagickFalse) || (window_info->depth == 1))
+    (void) XFillRectangle(display,window_info->id,
+      window_info->highlight_context,matte_info->x,matte_info->y,
+      matte_info->width,matte_info->height);
+  else
+    {
+      (void) XSetForeground(display,window_info->widget_context,
+        window_info->pixel_info->trough_color.pixel);
+      (void) XFillRectangle(display,window_info->id,window_info->widget_context,
+        matte_info->x,matte_info->y,matte_info->width,matte_info->height);
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w M a t t e T e x t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawMatteText() draws a matte with text.  If the text exceeds the extents
+%  of the text, a portion of the text relative to the cursor is displayed.
+%
+%  The format of the XDrawMatteText function is:
+%
+%      XDrawMatteText(display,window_info,text_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the text.
+%
+*/
+static void XDrawMatteText(Display *display,const XWindowInfo *window_info,
+  XWidgetInfo *text_info)
+{
+  const char
+    *text;
+
+  int
+    n,
+    x,
+    y;
+
+  register int
+    i;
+
+  unsigned int
+    height,
+    width;
+
+  XFontStruct
+    *font_info;
+
+  XRectangle
+    crop_info;
+
+  /*
+    Clear the text area.
+  */
+  XSetMatteColor(display,window_info,MagickFalse);
+  (void) XFillRectangle(display,window_info->id,window_info->widget_context,
+    text_info->x,text_info->y,text_info->width,text_info->height);
+  if (text_info->text == (char *) NULL)
+    return;
+  XSetTextColor(display,window_info,text_info->highlight);
+  font_info=window_info->font_info;
+  x=text_info->x+(QuantumMargin >> 2);
+  y=text_info->y+font_info->ascent+(text_info->height >> 2);
+  width=text_info->width-(QuantumMargin >> 1);
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  if (*text_info->text == '\0')
+    {
+      /*
+        No text-- just draw cursor.
+      */
+      (void) XDrawLine(display,window_info->id,window_info->annotate_context,
+        x,y+3,x,y-height+3);
+      return;
+    }
+  /*
+    Set cropping region.
+  */
+  crop_info.width=(unsigned short) text_info->width;
+  crop_info.height=(unsigned short) text_info->height;
+  crop_info.x=text_info->x;
+  crop_info.y=text_info->y;
+  /*
+    Determine beginning of the visible text.
+  */
+  if (text_info->cursor < text_info->marker)
+    text_info->marker=text_info->cursor;
+  else
+    {
+      text=text_info->marker;
+      if (XTextWidth(font_info,(char *) text,(int) (text_info->cursor-text)) >
+          (int) width)
+        {
+          text=text_info->text;
+          for (i=0; i < Extent(text); i++)
+          {
+            n=XTextWidth(font_info,(char *) text+i,(int)
+              (text_info->cursor-text-i));
+            if (n <= (int) width)
+              break;
+          }
+          text_info->marker=(char *) text+i;
+        }
+    }
+  /*
+    Draw text and cursor.
+  */
+  if (text_info->highlight == MagickFalse)
+    {
+      (void) XSetClipRectangles(display,window_info->widget_context,0,0,
+        &crop_info,1,Unsorted);
+      (void) XDrawString(display,window_info->id,window_info->widget_context,
+        x,y,text_info->marker,Extent(text_info->marker));
+      (void) XSetClipMask(display,window_info->widget_context,None);
+    }
+  else
+    {
+      (void) XSetClipRectangles(display,window_info->annotate_context,0,0,
+        &crop_info,1,Unsorted);
+      width=WidgetTextWidth(font_info,text_info->marker);
+      (void) XFillRectangle(display,window_info->id,
+        window_info->annotate_context,x,y-font_info->ascent,width,height);
+      (void) XSetClipMask(display,window_info->annotate_context,None);
+      (void) XSetClipRectangles(display,window_info->highlight_context,0,0,
+        &crop_info,1,Unsorted);
+      (void) XDrawString(display,window_info->id,
+        window_info->highlight_context,x,y,text_info->marker,
+        Extent(text_info->marker));
+      (void) XSetClipMask(display,window_info->highlight_context,None);
+    }
+  x+=XTextWidth(font_info,text_info->marker,(int)
+    (text_info->cursor-text_info->marker));
+  (void) XDrawLine(display,window_info->id,window_info->annotate_context,x,y+3,
+    x,y-height+3);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w T r i a n g l e E a s t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawTriangleEast() draws a triangle with a highlighted left bevel and a
+%  shadowed right and lower bevel.  The highlighted and shadowed bevels create
+%  a 3-D effect.
+%
+%  The format of the XDrawTriangleEast function is:
+%
+%      XDrawTriangleEast(display,window_info,triangle_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the triangle.
+%
+*/
+static void XDrawTriangleEast(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *triangle_info)
+{
+  int
+    x1,
+    x2,
+    x3,
+    y1,
+    y2,
+    y3;
+
+  unsigned int
+    bevel_width;
+
+  XFontStruct
+    *font_info;
+
+  XPoint
+    points[4];
+
+  /*
+    Draw triangle matte.
+  */
+  x1=triangle_info->x;
+  y1=triangle_info->y;
+  x2=triangle_info->x+triangle_info->width;
+  y2=triangle_info->y+(triangle_info->height >> 1);
+  x3=triangle_info->x;
+  y3=triangle_info->y+triangle_info->height;
+  bevel_width=triangle_info->bevel_width;
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y2;
+  points[2].x=x3;
+  points[2].y=y3;
+  XSetMatteColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,3,Complex,CoordModeOrigin);
+  /*
+    Draw bottom bevel.
+  */
+  points[0].x=x2;
+  points[0].y=y2;
+  points[1].x=x3;
+  points[1].y=y3;
+  points[2].x=x3-bevel_width;
+  points[2].y=y3+bevel_width;
+  points[3].x=x2+bevel_width;
+  points[3].y=y2;
+  XSetBevelColor(display,window_info,!triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  /*
+    Draw Left bevel.
+  */
+  points[0].x=x3;
+  points[0].y=y3;
+  points[1].x=x1;
+  points[1].y=y1;
+  points[2].x=x1-bevel_width+1;
+  points[2].y=y1-bevel_width;
+  points[3].x=x3-bevel_width+1;
+  points[3].y=y3+bevel_width;
+  XSetBevelColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  /*
+    Draw top bevel.
+  */
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y2;
+  points[2].x=x2+bevel_width;
+  points[2].y=y2;
+  points[3].x=x1-bevel_width;
+  points[3].y=y1-bevel_width;
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
+  if (triangle_info->text == (char *) NULL)
+    return;
+  /*
+    Write label to right of triangle.
+  */
+  font_info=window_info->font_info;
+  XSetTextColor(display,window_info,MagickTrue);
+  x1=triangle_info->x+triangle_info->width+triangle_info->bevel_width+
+    (QuantumMargin >> 1);
+  y1=triangle_info->y+((triangle_info->height-
+    (font_info->ascent+font_info->descent)) >> 1)+font_info->ascent;
+  (void) XDrawString(display,window_info->id,window_info->widget_context,x1,y1,
+    triangle_info->text,Extent(triangle_info->text));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w T r i a n g l e N o r t h                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawTriangleNorth() draws a triangle with a highlighted left bevel and a
+%  shadowed right and lower bevel.  The highlighted and shadowed bevels create
+%  a 3-D effect.
+%
+%  The format of the XDrawTriangleNorth function is:
+%
+%      XDrawTriangleNorth(display,window_info,triangle_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the triangle.
+%
+*/
+static void XDrawTriangleNorth(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *triangle_info)
+{
+  int
+    x1,
+    x2,
+    x3,
+    y1,
+    y2,
+    y3;
+
+  unsigned int
+    bevel_width;
+
+  XPoint
+    points[4];
+
+  /*
+    Draw triangle matte.
+  */
+  x1=triangle_info->x;
+  y1=triangle_info->y+triangle_info->height;
+  x2=triangle_info->x+(triangle_info->width >> 1);
+  y2=triangle_info->y;
+  x3=triangle_info->x+triangle_info->width;
+  y3=triangle_info->y+triangle_info->height;
+  bevel_width=triangle_info->bevel_width;
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y2;
+  points[2].x=x3;
+  points[2].y=y3;
+  XSetMatteColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,3,Complex,CoordModeOrigin);
+  /*
+    Draw left bevel.
+  */
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y2;
+  points[2].x=x2;
+  points[2].y=y2-bevel_width-2;
+  points[3].x=x1-bevel_width-1;
+  points[3].y=y1+bevel_width;
+  XSetBevelColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  /*
+    Draw right bevel.
+  */
+  points[0].x=x2;
+  points[0].y=y2;
+  points[1].x=x3;
+  points[1].y=y3;
+  points[2].x=x3+bevel_width;
+  points[2].y=y3+bevel_width;
+  points[3].x=x2;
+  points[3].y=y2-bevel_width;
+  XSetBevelColor(display,window_info,!triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  /*
+    Draw lower bevel.
+  */
+  points[0].x=x3;
+  points[0].y=y3;
+  points[1].x=x1;
+  points[1].y=y1;
+  points[2].x=x1-bevel_width;
+  points[2].y=y1+bevel_width;
+  points[3].x=x3+bevel_width;
+  points[3].y=y3+bevel_width;
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w T r i a n g l e S o u t h                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawTriangleSouth() draws a border with a highlighted left and right bevel
+%  and a shadowed lower bevel.  The highlighted and shadowed bevels create a
+%  3-D effect.
+%
+%  The format of the XDrawTriangleSouth function is:
+%
+%      XDrawTriangleSouth(display,window_info,triangle_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o triangle_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the triangle.
+%
+*/
+static void XDrawTriangleSouth(Display *display,const XWindowInfo *window_info,
+  const XWidgetInfo *triangle_info)
+{
+  int
+    x1,
+    x2,
+    x3,
+    y1,
+    y2,
+    y3;
+
+  unsigned int
+    bevel_width;
+
+  XPoint
+    points[4];
+
+  /*
+    Draw triangle matte.
+  */
+  x1=triangle_info->x;
+  y1=triangle_info->y;
+  x2=triangle_info->x+(triangle_info->width >> 1);
+  y2=triangle_info->y+triangle_info->height;
+  x3=triangle_info->x+triangle_info->width;
+  y3=triangle_info->y;
+  bevel_width=triangle_info->bevel_width;
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y2;
+  points[2].x=x3;
+  points[2].y=y3;
+  XSetMatteColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,3,Complex,CoordModeOrigin);
+  /*
+    Draw top bevel.
+  */
+  points[0].x=x3;
+  points[0].y=y3;
+  points[1].x=x1;
+  points[1].y=y1;
+  points[2].x=x1-bevel_width;
+  points[2].y=y1-bevel_width;
+  points[3].x=x3+bevel_width;
+  points[3].y=y3-bevel_width;
+  XSetBevelColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  /*
+    Draw right bevel.
+  */
+  points[0].x=x2;
+  points[0].y=y2;
+  points[1].x=x3+1;
+  points[1].y=y3-bevel_width;
+  points[2].x=x3+bevel_width;
+  points[2].y=y3-bevel_width;
+  points[3].x=x2;
+  points[3].y=y2+bevel_width;
+  XSetBevelColor(display,window_info,!triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  /*
+    Draw left bevel.
+  */
+  points[0].x=x1;
+  points[0].y=y1;
+  points[1].x=x2;
+  points[1].y=y2;
+  points[2].x=x2;
+  points[2].y=y2+bevel_width;
+  points[3].x=x1-bevel_width;
+  points[3].y=y1-bevel_width;
+  XSetBevelColor(display,window_info,triangle_info->raised);
+  (void) XFillPolygon(display,window_info->id,window_info->widget_context,
+    points,4,Complex,CoordModeOrigin);
+  (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X D r a w W i d g e t T e x t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawWidgetText() first clears the widget and draws a text string justifed
+%  left (or center) in the x-direction and centered within the y-direction.
+%
+%  The format of the XDrawWidgetText function is:
+%
+%      XDrawWidgetText(display,window_info,text_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a XWindowText structure.
+%
+%    o text_info: Specifies a pointer to XWidgetInfo structure.
+%
+*/
+static void XDrawWidgetText(Display *display,const XWindowInfo *window_info,
+  XWidgetInfo *text_info)
+{
+  GC
+    widget_context;
+
+  int
+    x,
+    y;
+
+  unsigned int
+    height,
+    width;
+
+  XFontStruct
+    *font_info;
+
+  XRectangle
+    crop_info;
+
+  /*
+    Clear the text area.
+  */
+  widget_context=window_info->annotate_context;
+  if (text_info->raised)
+    (void) XClearArea(display,window_info->id,text_info->x,text_info->y,
+      text_info->width,text_info->height,MagickFalse);
+  else
+    {
+      (void) XFillRectangle(display,window_info->id,widget_context,text_info->x,
+        text_info->y,text_info->width,text_info->height);
+      widget_context=window_info->highlight_context;
+    }
+  if (text_info->text == (char *) NULL)
+    return;
+  if (*text_info->text == '\0')
+    return;
+  /*
+    Set cropping region.
+  */
+  font_info=window_info->font_info;
+  crop_info.width=(unsigned short) text_info->width;
+  crop_info.height=(unsigned short) text_info->height;
+  crop_info.x=text_info->x;
+  crop_info.y=text_info->y;
+  /*
+    Draw text.
+  */
+  width=WidgetTextWidth(font_info,text_info->text);
+  x=text_info->x+(QuantumMargin >> 1);
+  if (text_info->center)
+    x=text_info->x+(text_info->width >> 1)-(width >> 1);
+  if (text_info->raised)
+    if (width > (text_info->width-QuantumMargin))
+      x+=(text_info->width-QuantumMargin-width);
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  y=text_info->y+((text_info->height-height) >> 1)+font_info->ascent;
+  (void) XSetClipRectangles(display,widget_context,0,0,&crop_info,1,Unsorted);
+  (void) XDrawString(display,window_info->id,widget_context,x,y,text_info->text,
+    Extent(text_info->text));
+  (void) XSetClipMask(display,widget_context,None);
+  if (x < text_info->x)
+    (void) XDrawLine(display,window_info->id,window_info->annotate_context,
+      text_info->x,text_info->y,text_info->x,text_info->y+text_info->height-1);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X E d i t T e x t                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XEditText() edits a text string as indicated by the key symbol.
+%
+%  The format of the XEditText function is:
+%
+%      XEditText(display,text_info,key_symbol,text,state)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o text_info: Specifies a pointer to a XWidgetInfo structure.  It
+%      contains the extents of the text.
+%
+%    o key_symbol:  A X11 KeySym that indicates what editing function to
+%      perform to the text.
+%
+%    o text: A character string to insert into the text.
+%
+%    o state:  An size_t that indicates whether the key symbol is a
+%      control character or not.
+%
+*/
+static void XEditText(Display *display,XWidgetInfo *text_info,
+  const KeySym key_symbol,char *text,const size_t state)
+{
+  switch ((int) key_symbol)
+  {
+    case XK_BackSpace:
+    case XK_Delete:
+    {
+      if (text_info->highlight)
+        {
+          /*
+            Erase the entire line of text.
+          */
+          *text_info->text='\0';
+          text_info->cursor=text_info->text;
+          text_info->marker=text_info->text;
+          text_info->highlight=MagickFalse;
+        }
+      /*
+        Erase one character.
+      */
+      if (text_info->cursor != text_info->text)
+        {
+          text_info->cursor--;
+          (void) CopyMagickString(text_info->cursor,text_info->cursor+1,
+            MaxTextExtent);
+          text_info->highlight=MagickFalse;
+          break;
+        }
+    }
+    case XK_Left:
+    case XK_KP_Left:
+    {
+      /*
+        Move cursor one position left.
+      */
+      if (text_info->cursor == text_info->text)
+        break;
+      text_info->cursor--;
+      break;
+    }
+    case XK_Right:
+    case XK_KP_Right:
+    {
+      /*
+        Move cursor one position right.
+      */
+      if (text_info->cursor == (text_info->text+Extent(text_info->text)))
+        break;
+      text_info->cursor++;
+      break;
+    }
+    default:
+    {
+      register char
+        *p,
+        *q;
+
+      register int
+        i;
+
+      if (state & ControlState)
+        break;
+      if (*text == '\0')
+        break;
+      if ((Extent(text_info->text)+1) >= (int) MaxTextExtent)
+        (void) XBell(display,0);
+      else
+        {
+          if (text_info->highlight)
+            {
+              /*
+                Erase the entire line of text.
+              */
+              *text_info->text='\0';
+              text_info->cursor=text_info->text;
+              text_info->marker=text_info->text;
+              text_info->highlight=MagickFalse;
+            }
+          /*
+            Insert a string into the text.
+          */
+          q=text_info->text+Extent(text_info->text)+strlen(text);
+          for (i=0; i <= Extent(text_info->cursor); i++)
+          {
+            *q=(*(q-Extent(text)));
+            q--;
+          }
+          p=text;
+          for (i=0; i < Extent(text); i++)
+            *text_info->cursor++=(*p++);
+        }
+      break;
+    }
+  }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X G e t W i d g e t I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetWidgetInfo() initializes the XWidgetInfo structure.
+%
+%  The format of the XGetWidgetInfo function is:
+%
+%      XGetWidgetInfo(text,widget_info)
+%
+%  A description of each parameter follows:
+%
+%    o text: A string of characters associated with the widget.
+%
+%    o widget_info: Specifies a pointer to a X11 XWidgetInfo structure.
+%
+*/
+static void XGetWidgetInfo(const char *text,XWidgetInfo *widget_info)
+{
+  /*
+    Initialize widget info.
+  */
+  widget_info->id=(~0);
+  widget_info->bevel_width=3;
+  widget_info->width=1;
+  widget_info->height=1;
+  widget_info->x=0;
+  widget_info->y=0;
+  widget_info->min_y=0;
+  widget_info->max_y=0;
+  widget_info->raised=MagickTrue;
+  widget_info->active=MagickFalse;
+  widget_info->center=MagickTrue;
+  widget_info->trough=MagickFalse;
+  widget_info->highlight=MagickFalse;
+  widget_info->text=(char *) text;
+  widget_info->cursor=(char *) text;
+  if (text != (char *) NULL)
+    widget_info->cursor+=Extent(text);
+  widget_info->marker=(char *) text;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X H i g h l i g h t W i d g e t                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XHighlightWidget() draws a highlighted border around a window.
+%
+%  The format of the XHighlightWidget function is:
+%
+%      XHighlightWidget(display,window_info,x,y)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o x: Specifies an integer representing the rectangle offset in the
+%      x-direction.
+%
+%    o y: Specifies an integer representing the rectangle offset in the
+%      y-direction.
+%
+*/
+static void XHighlightWidget(Display *display,const XWindowInfo *window_info,
+  const int x,const int y)
+{
+  /*
+    Draw the widget highlighting rectangle.
+  */
+  XSetBevelColor(display,window_info,MagickTrue);
+  (void) XDrawRectangle(display,window_info->id,window_info->widget_context,x,y,
+    window_info->width-(x << 1),window_info->height-(y << 1));
+  (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
+    x-1,y-1,window_info->width-(x << 1)+1,window_info->height-(y << 1)+1);
+  XSetBevelColor(display,window_info,MagickFalse);
+  (void) XDrawRectangle(display,window_info->id,window_info->widget_context,
+    x-1,y-1,window_info->width-(x << 1),window_info->height-(y << 1));
+  (void) XSetFillStyle(display,window_info->widget_context,FillSolid);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S c r e e n E v e n t                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XScreenEvent() returns MagickTrue if the any event on the X server queue is
+%  associated with the widget window.
+%
+%  The format of the XScreenEvent function is:
+%
+%      int XScreenEvent(Display *display,XEvent *event,char *data)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o event: Specifies a pointer to a X11 XEvent structure.
+%
+%    o data: Specifies a pointer to a XWindows structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int XScreenEvent(Display *display,XEvent *event,char *data)
+{
+  XWindows
+    *windows;
+
+  windows=(XWindows *) data;
+  if (event->xany.window == windows->popup.id)
+    {
+      if (event->type == MapNotify)
+        windows->popup.mapped=MagickTrue;
+      if (event->type == UnmapNotify)
+        windows->popup.mapped=MagickFalse;
+      return(MagickTrue);
+    }
+  if (event->xany.window == windows->widget.id)
+    {
+      if (event->type == MapNotify)
+        windows->widget.mapped=MagickTrue;
+      if (event->type == UnmapNotify)
+        windows->widget.mapped=MagickFalse;
+      return(MagickTrue);
+    }
+  switch (event->type)
+  {
+    case ButtonPress:
+    {
+      if ((event->xbutton.button == Button3) &&
+          (event->xbutton.state & Mod1Mask))
+        {
+          /*
+            Convert Alt-Button3 to Button2.
+          */
+          event->xbutton.button=Button2;
+          event->xbutton.state&=(~Mod1Mask);
+        }
+      return(MagickTrue);
+    }
+    case Expose:
+    {
+      if (event->xexpose.window == windows->image.id)
+        {
+          XRefreshWindow(display,&windows->image,event);
+          break;
+        }
+      if (event->xexpose.window == windows->magnify.id)
+        if (event->xexpose.count == 0)
+          if (windows->magnify.mapped)
+            {
+              XMakeMagnifyImage(display,windows);
+              break;
+            }
+      if (event->xexpose.window == windows->command.id)
+        if (event->xexpose.count == 0)
+          {
+            (void) XCommandWidget(display,windows,(const char **) NULL,event);
+            break;
+          }
+      break;
+    }
+    case FocusOut:
+    {
+      /*
+        Set input focus for backdrop window.
+      */
+      if (event->xfocus.window == windows->image.id)
+        (void) XSetInputFocus(display,windows->image.id,RevertToNone,
+          CurrentTime);
+      return(MagickTrue);
+    }
+    case ButtonRelease:
+    case KeyPress:
+    case KeyRelease:
+    case MotionNotify:
+    case SelectionNotify:
+      return(MagickTrue);
+    default:
+      break;
+  }
+  return(MagickFalse);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S e t B e v e l C o l o r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSetBevelColor() sets the graphic context for drawing a beveled border.
+%
+%  The format of the XSetBevelColor function is:
+%
+%      XSetBevelColor(display,window_info,raised)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o raised: A value other than zero indicates the color show be a
+%      "highlight" color, otherwise the "shadow" color is set.
+%
+*/
+static void XSetBevelColor(Display *display,const XWindowInfo *window_info,
+  const MagickStatusType raised)
+{
+  if (window_info->depth == 1)
+    {
+      Pixmap
+        stipple;
+
+      /*
+        Monochrome window.
+      */
+      (void) XSetBackground(display,window_info->widget_context,
+        XBlackPixel(display,window_info->screen));
+      (void) XSetForeground(display,window_info->widget_context,
+        XWhitePixel(display,window_info->screen));
+      (void) XSetFillStyle(display,window_info->widget_context,
+        FillOpaqueStippled);
+      stipple=window_info->highlight_stipple;
+      if (raised == MagickFalse)
+        stipple=window_info->shadow_stipple;
+      (void) XSetStipple(display,window_info->widget_context,stipple);
+    }
+  else
+    if (raised)
+      (void) XSetForeground(display,window_info->widget_context,
+        window_info->pixel_info->highlight_color.pixel);
+    else
+      (void) XSetForeground(display,window_info->widget_context,
+        window_info->pixel_info->shadow_color.pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S e t M a t t e C o l o r                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSetMatteColor() sets the graphic context for drawing the matte.
+%
+%  The format of the XSetMatteColor function is:
+%
+%      XSetMatteColor(display,window_info,raised)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o raised: A value other than zero indicates the matte is active.
+%
+*/
+static void XSetMatteColor(Display *display,const XWindowInfo *window_info,
+  const MagickStatusType raised)
+{
+  if (window_info->depth == 1)
+    {
+      /*
+        Monochrome window.
+      */
+      if (raised)
+        (void) XSetForeground(display,window_info->widget_context,
+          XWhitePixel(display,window_info->screen));
+      else
+        (void) XSetForeground(display,window_info->widget_context,
+          XBlackPixel(display,window_info->screen));
+    }
+  else
+    if (raised)
+      (void) XSetForeground(display,window_info->widget_context,
+        window_info->pixel_info->matte_color.pixel);
+    else
+      (void) XSetForeground(display,window_info->widget_context,
+        window_info->pixel_info->depth_color.pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X S e t T e x t C o l o r                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSetTextColor() sets the graphic context for drawing text on a matte.
+%
+%  The format of the XSetTextColor function is:
+%
+%      XSetTextColor(display,window_info,raised)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+%    o raised: A value other than zero indicates the color show be a
+%      "highlight" color, otherwise the "shadow" color is set.
+%
+*/
+static void XSetTextColor(Display *display,const XWindowInfo *window_info,
+  const MagickStatusType raised)
+{
+  ssize_t
+    foreground,
+    matte;
+
+  if (window_info->depth == 1)
+    {
+      /*
+        Monochrome window.
+      */
+      if (raised)
+        (void) XSetForeground(display,window_info->widget_context,
+          XBlackPixel(display,window_info->screen));
+      else
+        (void) XSetForeground(display,window_info->widget_context,
+          XWhitePixel(display,window_info->screen));
+      return;
+    }
+  foreground=(ssize_t) XPixelIntensity(
+    &window_info->pixel_info->foreground_color);
+  matte=(ssize_t) XPixelIntensity(&window_info->pixel_info->matte_color);
+  if (MagickAbsoluteValue((int) (foreground-matte)) > (65535L >> 3))
+    (void) XSetForeground(display,window_info->widget_context,
+      window_info->pixel_info->foreground_color.pixel);
+  else
+    (void) XSetForeground(display,window_info->widget_context,
+      window_info->pixel_info->background_color.pixel);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C o l o r B r o w s e r W i d g e t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XColorBrowserWidget() displays a Color Browser widget with a color query
+%  to the user.  The user keys a reply and presses the Action or Cancel button
+%  to exit.  The typed text is returned as the reply function parameter.
+%
+%  The format of the XColorBrowserWidget method is:
+%
+%      void XColorBrowserWidget(Display *display,XWindows *windows,
+%        const char *action,char *reply)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o action: Specifies a pointer to the action of this widget.
+%
+%    o reply: the response from the user is returned in this parameter.
+%
+*/
+MagickExport void XColorBrowserWidget(Display *display,XWindows *windows,
+  const char *action,char *reply)
+{
+#define CancelButtonText  "Cancel"
+#define ColornameText  "Name:"
+#define ColorPatternText  "Pattern:"
+#define GrabButtonText  "Grab"
+#define ResetButtonText  "Reset"
+
+  char
+    **colorlist,
+    primary_selection[MaxTextExtent],
+    reset_pattern[MaxTextExtent],
+    text[MaxTextExtent];
+
+  ExceptionInfo
+    *exception;
+
+  int
+    x,
+    y;
+
+  register int
+    i;
+
+  static char
+    glob_pattern[MaxTextExtent] = "*";
+
+  static MagickStatusType
+    mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
+
+  Status
+    status;
+
+  unsigned int
+    height,
+    text_width,
+    visible_colors,
+    width;
+
+  size_t
+    colors,
+    delay,
+    state;
+
+  XColor
+    color;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    action_info,
+    cancel_info,
+    expose_info,
+    grab_info,
+    list_info,
+    mode_info,
+    north_info,
+    reply_info,
+    reset_info,
+    scroll_info,
+    selection_info,
+    slider_info,
+    south_info,
+    text_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Get color list and sort in ascending order.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(action != (char *) NULL);
+  assert(reply != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
+  exception=AcquireExceptionInfo();
+  colorlist=GetColorList(glob_pattern,&colors,exception);
+  if (colorlist == (char **) NULL)
+    {
+      /*
+        Pattern failed, obtain all the colors.
+      */
+      (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
+      colorlist=GetColorList(glob_pattern,&colors,exception);
+      if (colorlist == (char **) NULL)
+        {
+          XNoticeWidget(display,windows,"Unable to obtain colors names:",
+            glob_pattern);
+          (void) XDialogWidget(display,windows,action,"Enter color name:",
+            reply);
+          return;
+        }
+    }
+  /*
+    Determine Color Browser widget attributes.
+  */
+  font_info=windows->widget.font_info;
+  text_width=0;
+  for (i=0; i < (int) colors; i++)
+    if (WidgetTextWidth(font_info,colorlist[i]) > text_width)
+      text_width=WidgetTextWidth(font_info,colorlist[i]);
+  width=WidgetTextWidth(font_info,(char *) action);
+  if (WidgetTextWidth(font_info,CancelButtonText) > width)
+    width=WidgetTextWidth(font_info,CancelButtonText);
+  if (WidgetTextWidth(font_info,ResetButtonText) > width)
+    width=WidgetTextWidth(font_info,ResetButtonText);
+  if (WidgetTextWidth(font_info,GrabButtonText) > width)
+    width=WidgetTextWidth(font_info,GrabButtonText);
+  width+=QuantumMargin;
+  if (WidgetTextWidth(font_info,ColorPatternText) > width)
+    width=WidgetTextWidth(font_info,ColorPatternText);
+  if (WidgetTextWidth(font_info,ColornameText) > width)
+    width=WidgetTextWidth(font_info,ColornameText);
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position Color Browser widget.
+  */
+  windows->widget.width=(unsigned int)
+    (width+MagickMin((int) text_width,(int) MaxTextWidth)+6*QuantumMargin);
+  windows->widget.min_width=(unsigned int)
+    (width+MinTextWidth+4*QuantumMargin);
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int)
+    ((81*height) >> 2)+((13*QuantumMargin) >> 1)+4;
+  windows->widget.min_height=(unsigned int)
+    (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Color Browser widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Browse and Select a Color",
+    MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
+    mask,&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  XGetWidgetInfo((char *) NULL,&slider_info);
+  XGetWidgetInfo((char *) NULL,&north_info);
+  XGetWidgetInfo((char *) NULL,&south_info);
+  XGetWidgetInfo((char *) NULL,&expose_info);
+  visible_colors=0;
+  delay=SuspendTime << 2;
+  state=UpdateConfigurationState;
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        int
+          id;
+
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=width;
+        cancel_info.height=(unsigned int) ((3*height) >> 1);
+        cancel_info.x=(int)
+          (windows->widget.width-cancel_info.width-QuantumMargin-2);
+        cancel_info.y=(int)
+          (windows->widget.height-cancel_info.height-QuantumMargin);
+        XGetWidgetInfo(action,&action_info);
+        action_info.width=width;
+        action_info.height=(unsigned int) ((3*height) >> 1);
+        action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
+          (action_info.bevel_width << 1));
+        action_info.y=cancel_info.y;
+        XGetWidgetInfo(GrabButtonText,&grab_info);
+        grab_info.width=width;
+        grab_info.height=(unsigned int) ((3*height) >> 1);
+        grab_info.x=QuantumMargin;
+        grab_info.y=((5*QuantumMargin) >> 1)+height;
+        XGetWidgetInfo(ResetButtonText,&reset_info);
+        reset_info.width=width;
+        reset_info.height=(unsigned int) ((3*height) >> 1);
+        reset_info.x=QuantumMargin;
+        reset_info.y=grab_info.y+grab_info.height+QuantumMargin;
+        /*
+          Initialize reply information.
+        */
+        XGetWidgetInfo(reply,&reply_info);
+        reply_info.raised=MagickFalse;
+        reply_info.bevel_width--;
+        reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
+        reply_info.height=height << 1;
+        reply_info.x=(int) (width+(QuantumMargin << 1));
+        reply_info.y=action_info.y-reply_info.height-QuantumMargin;
+        /*
+          Initialize mode information.
+        */
+        XGetWidgetInfo((char *) NULL,&mode_info);
+        mode_info.active=MagickTrue;
+        mode_info.bevel_width=0;
+        mode_info.width=(unsigned int) (action_info.x-(QuantumMargin << 1));
+        mode_info.height=action_info.height;
+        mode_info.x=QuantumMargin;
+        mode_info.y=action_info.y;
+        /*
+          Initialize scroll information.
+        */
+        XGetWidgetInfo((char *) NULL,&scroll_info);
+        scroll_info.bevel_width--;
+        scroll_info.width=height;
+        scroll_info.height=(unsigned int) (reply_info.y-grab_info.y-
+          (QuantumMargin >> 1));
+        scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
+        scroll_info.y=grab_info.y-reply_info.bevel_width;
+        scroll_info.raised=MagickFalse;
+        scroll_info.trough=MagickTrue;
+        north_info=scroll_info;
+        north_info.raised=MagickTrue;
+        north_info.width-=(north_info.bevel_width << 1);
+        north_info.height=north_info.width-1;
+        north_info.x+=north_info.bevel_width;
+        north_info.y+=north_info.bevel_width;
+        south_info=north_info;
+        south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
+          south_info.height;
+        id=slider_info.id;
+        slider_info=north_info;
+        slider_info.id=id;
+        slider_info.width-=2;
+        slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
+          slider_info.bevel_width+2;
+        slider_info.height=scroll_info.height-((slider_info.min_y-
+          scroll_info.y+1) << 1)+4;
+        visible_colors=scroll_info.height/(height+(height >> 3));
+        if (colors > visible_colors)
+          slider_info.height=(unsigned int)
+            ((visible_colors*slider_info.height)/colors);
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.x=scroll_info.x+slider_info.bevel_width+1;
+        slider_info.y=slider_info.min_y;
+        expose_info=scroll_info;
+        expose_info.y=slider_info.y;
+        /*
+          Initialize list information.
+        */
+        XGetWidgetInfo((char *) NULL,&list_info);
+        list_info.raised=MagickFalse;
+        list_info.bevel_width--;
+        list_info.width=(unsigned int)
+          (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
+        list_info.height=scroll_info.height;
+        list_info.x=reply_info.x;
+        list_info.y=scroll_info.y;
+        if (windows->widget.mapped == MagickFalse)
+          state|=JumpListState;
+        /*
+          Initialize text information.
+        */
+        *text='\0';
+        XGetWidgetInfo(text,&text_info);
+        text_info.center=MagickFalse;
+        text_info.width=reply_info.width;
+        text_info.height=height;
+        text_info.x=list_info.x-(QuantumMargin >> 1);
+        text_info.y=QuantumMargin;
+        /*
+          Initialize selection information.
+        */
+        XGetWidgetInfo((char *) NULL,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.width=list_info.width;
+        selection_info.height=(unsigned int) ((9*height) >> 3);
+        selection_info.x=list_info.x;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Color Browser window.
+        */
+        x=QuantumMargin;
+        y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,ColorPatternText,
+          Extent(ColorPatternText));
+        (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawBeveledButton(display,&windows->widget,&grab_info);
+        XDrawBeveledButton(display,&windows->widget,&reset_info);
+        XDrawBeveledMatte(display,&windows->widget,&list_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        x=QuantumMargin;
+        y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,ColornameText,
+          Extent(ColornameText));
+        XDrawBeveledMatte(display,&windows->widget,&reply_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        XDrawBeveledButton(display,&windows->widget,&action_info);
+        XDrawBeveledButton(display,&windows->widget,&cancel_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        selection_info.id=(~0);
+        state|=RedrawActionState;
+        state|=RedrawListState;
+        state&=(~RedrawWidgetState);
+      }
+    if (state & UpdateListState)
+      {
+        char
+          **checklist;
+
+        size_t
+          number_colors;
+
+        status=XParseColor(display,windows->widget.map_info->colormap,
+          glob_pattern,&color);
+        if ((status != False) || (strchr(glob_pattern,'-') != (char *) NULL))
+          {
+            /*
+              Reply is a single color name-- exit.
+            */
+            (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
+            (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        /*
+          Update color list.
+        */
+        checklist=GetColorList(glob_pattern,&number_colors,exception);
+        if (number_colors == 0)
+          {
+            (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
+            (void) XBell(display,0);
+          }
+        else
+          {
+            for (i=0; i < (int) colors; i++)
+              colorlist[i]=DestroyString(colorlist[i]);
+            if (colorlist != (char **) NULL)
+              colorlist=(char **) RelinquishMagickMemory(colorlist);
+            colorlist=checklist;
+            colors=number_colors;
+          }
+        /*
+          Sort color list in ascending order.
+        */
+        slider_info.height=
+          scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
+        if (colors > visible_colors)
+          slider_info.height=(unsigned int)
+            ((visible_colors*slider_info.height)/colors);
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        expose_info.y=slider_info.y;
+        selection_info.id=(~0);
+        list_info.id=(~0);
+        state|=RedrawListState;
+        /*
+          Redraw color name & reply.
+        */
+        *reply_info.text='\0';
+        reply_info.cursor=reply_info.text;
+        (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~UpdateListState);
+      }
+    if (state & JumpListState)
+      {
+        /*
+          Jump scroll to match user color.
+        */
+        list_info.id=(~0);
+        for (i=0; i < (int) colors; i++)
+          if (LocaleCompare(colorlist[i],reply) >= 0)
+            {
+              list_info.id=LocaleCompare(colorlist[i],reply) == 0 ? i : ~0;
+              break;
+            }
+        if ((i < slider_info.id) ||
+            (i >= (int) (slider_info.id+visible_colors)))
+          slider_info.id=i-(visible_colors >> 1);
+        selection_info.id=(~0);
+        state|=RedrawListState;
+        state&=(~JumpListState);
+      }
+    if (state & RedrawListState)
+      {
+        /*
+          Determine slider id and position.
+        */
+        if (slider_info.id >= (int) (colors-visible_colors))
+          slider_info.id=(int) (colors-visible_colors);
+        if ((slider_info.id < 0) || (colors <= visible_colors))
+          slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        if (colors != 0)
+          slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
+            slider_info.min_y+1)/colors);
+        if (slider_info.id != selection_info.id)
+          {
+            /*
+              Redraw scroll bar and file names.
+            */
+            selection_info.id=slider_info.id;
+            selection_info.y=list_info.y+(height >> 3)+2;
+            for (i=0; i < (int) visible_colors; i++)
+            {
+              selection_info.raised=(slider_info.id+i) != list_info.id ?
+                MagickTrue : MagickFalse;
+              selection_info.text=(char *) NULL;
+              if ((slider_info.id+i) < (int) colors)
+                selection_info.text=colorlist[slider_info.id+i];
+              XDrawWidgetText(display,&windows->widget,&selection_info);
+              selection_info.y+=(int) selection_info.height;
+            }
+            /*
+              Update slider.
+            */
+            if (slider_info.y > expose_info.y)
+              {
+                expose_info.height=(unsigned int) slider_info.y-expose_info.y;
+                expose_info.y=slider_info.y-expose_info.height-
+                  slider_info.bevel_width-1;
+              }
+            else
+              {
+                expose_info.height=(unsigned int) expose_info.y-slider_info.y;
+                expose_info.y=slider_info.y+slider_info.height+
+                  slider_info.bevel_width+1;
+              }
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+            XDrawMatte(display,&windows->widget,&expose_info);
+            XDrawBeveledButton(display,&windows->widget,&slider_info);
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+            expose_info.y=slider_info.y;
+          }
+        state&=(~RedrawListState);
+      }
+    if (state & RedrawActionState)
+      {
+        static char
+          colorname[MaxTextExtent];
+
+        /*
+          Display the selected color in a drawing area.
+        */
+        color=windows->widget.pixel_info->matte_color;
+        (void) XParseColor(display,windows->widget.map_info->colormap,
+          reply_info.text,&windows->widget.pixel_info->matte_color);
+        XBestPixel(display,windows->widget.map_info->colormap,(XColor *) NULL,
+          (unsigned int) windows->widget.visual_info->colormap_size,
+          &windows->widget.pixel_info->matte_color);
+        mode_info.text=colorname;
+        (void) FormatLocaleString(mode_info.text,MaxTextExtent,"#%02x%02x%02x",
+          windows->widget.pixel_info->matte_color.red,
+          windows->widget.pixel_info->matte_color.green,
+          windows->widget.pixel_info->matte_color.blue);
+        XDrawBeveledButton(display,&windows->widget,&mode_info);
+        windows->widget.pixel_info->matte_color=color;
+        state&=(~RedrawActionState);
+      }
+    /*
+      Wait for next event.
+    */
+    if (north_info.raised && south_info.raised)
+      (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    else
+      {
+        /*
+          Brief delay before advancing scroll bar.
+        */
+        XDelay(display,delay);
+        delay=SuspendTime;
+        (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
+        if (north_info.raised == MagickFalse)
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              slider_info.id--;
+              state|=RedrawListState;
+            }
+        if (south_info.raised == MagickFalse)
+          if (slider_info.id < (int) colors)
+            {
+              /*
+                Move slider down.
+              */
+              slider_info.id++;
+              state|=RedrawListState;
+            }
+        if (event.type != ButtonRelease)
+          continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(slider_info,event.xbutton))
+          {
+            /*
+              Track slider.
+            */
+            slider_info.active=MagickTrue;
+            break;
+          }
+        if (MatteIsActive(north_info,event.xbutton))
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              north_info.raised=MagickFalse;
+              slider_info.id--;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(south_info,event.xbutton))
+          if (slider_info.id < (int) colors)
+            {
+              /*
+                Move slider down.
+              */
+              south_info.raised=MagickFalse;
+              slider_info.id++;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(scroll_info,event.xbutton))
+          {
+            /*
+              Move slider.
+            */
+            if (event.xbutton.y < slider_info.y)
+              slider_info.id-=(visible_colors-1);
+            else
+              slider_info.id+=(visible_colors-1);
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(list_info,event.xbutton))
+          {
+            int
+              id;
+
+            /*
+              User pressed list matte.
+            */
+            id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
+              selection_info.height;
+            if (id >= (int) colors)
+              break;
+            (void) CopyMagickString(reply_info.text,colorlist[id],
+              MaxTextExtent);
+            reply_info.highlight=MagickFalse;
+            reply_info.marker=reply_info.text;
+            reply_info.cursor=reply_info.text+Extent(reply_info.text);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            state|=RedrawActionState;
+            if (id == list_info.id)
+              {
+                (void) CopyMagickString(glob_pattern,reply_info.text,
+                  MaxTextExtent);
+                state|=UpdateListState;
+              }
+            selection_info.id=(~0);
+            list_info.id=id;
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(grab_info,event.xbutton))
+          {
+            /*
+              User pressed Grab button.
+            */
+            grab_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&grab_info);
+            break;
+          }
+        if (MatteIsActive(reset_info,event.xbutton))
+          {
+            /*
+              User pressed Reset button.
+            */
+            reset_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&reset_info);
+            break;
+          }
+        if (MatteIsActive(mode_info,event.xbutton))
+          {
+            /*
+              User pressed mode button.
+            */
+            (void) CopyMagickString(reply_info.text,mode_info.text,
+              MaxTextExtent);
+            (void) CopyMagickString(primary_selection,reply_info.text,
+              MaxTextExtent);
+            (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
+              event.xbutton.time);
+            reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
+              windows->widget.id ? MagickTrue : MagickFalse;
+            reply_info.marker=reply_info.text;
+            reply_info.cursor=reply_info.text+Extent(reply_info.text);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            break;
+          }
+        if (MatteIsActive(action_info,event.xbutton))
+          {
+            /*
+              User pressed action button.
+            */
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed Cancel button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        if (event.xbutton.button != Button2)
+          {
+            static Time
+              click_time;
+
+            /*
+              Move text cursor to position of button press.
+            */
+            x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
+            for (i=1; i <= Extent(reply_info.marker); i++)
+              if (XTextWidth(font_info,reply_info.marker,i) > x)
+                break;
+            reply_info.cursor=reply_info.marker+i-1;
+            if (event.xbutton.time > (click_time+DoubleClick))
+              reply_info.highlight=MagickFalse;
+            else
+              {
+                /*
+                  Become the XA_PRIMARY selection owner.
+                */
+                (void) CopyMagickString(primary_selection,reply_info.text,
+                  MaxTextExtent);
+                (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
+                  event.xbutton.time);
+                reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
+                  windows->widget.id ? MagickTrue : MagickFalse;
+              }
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            click_time=event.xbutton.time;
+            break;
+          }
+        /*
+          Request primary selection.
+        */
+        (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
+          windows->widget.id,event.xbutton.time);
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (north_info.raised == MagickFalse)
+          {
+            /*
+              User released up button.
+            */
+            delay=SuspendTime << 2;
+            north_info.raised=MagickTrue;
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+          }
+        if (south_info.raised == MagickFalse)
+          {
+            /*
+              User released down button.
+            */
+            delay=SuspendTime << 2;
+            south_info.raised=MagickTrue;
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+          }
+        if (slider_info.active)
+          {
+            /*
+              Stop tracking slider.
+            */
+            slider_info.active=MagickFalse;
+            break;
+          }
+        if (grab_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(grab_info,event.xbutton))
+                {
+                  /*
+                    Select a pen color from the X server.
+                  */
+                  (void) XGetWindowColor(display,windows,reply_info.text);
+                  reply_info.marker=reply_info.text;
+                  reply_info.cursor=reply_info.text+Extent(reply_info.text);
+                  XDrawMatteText(display,&windows->widget,&reply_info);
+                  state|=RedrawActionState;
+                }
+            grab_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&grab_info);
+          }
+        if (reset_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(reset_info,event.xbutton))
+                {
+                  (void) CopyMagickString(glob_pattern,reset_pattern,
+                    MaxTextExtent);
+                  state|=UpdateListState;
+                }
+            reset_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&reset_info);
+          }
+        if (action_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              {
+                if (MatteIsActive(action_info,event.xbutton))
+                  {
+                    if (*reply_info.text == '\0')
+                      (void) XBell(display,0);
+                    else
+                      state|=ExitState;
+                  }
+              }
+            action_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+          }
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                {
+                  *reply_info.text='\0';
+                  state|=ExitState;
+                }
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            *reply_info.text='\0';
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static int
+          length;
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        length=XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (AreaIsActive(scroll_info,event.xkey))
+          {
+            /*
+              Move slider.
+            */
+            switch ((int) key_symbol)
+            {
+              case XK_Home:
+              case XK_KP_Home:
+              {
+                slider_info.id=0;
+                break;
+              }
+              case XK_Up:
+              case XK_KP_Up:
+              {
+                slider_info.id--;
+                break;
+              }
+              case XK_Down:
+              case XK_KP_Down:
+              {
+                slider_info.id++;
+                break;
+              }
+              case XK_Prior:
+              case XK_KP_Prior:
+              {
+                slider_info.id-=visible_colors;
+                break;
+              }
+              case XK_Next:
+              case XK_KP_Next:
+              {
+                slider_info.id+=visible_colors;
+                break;
+              }
+              case XK_End:
+              case XK_KP_End:
+              {
+                slider_info.id=(int) colors;
+                break;
+              }
+            }
+            state|=RedrawListState;
+            break;
+          }
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            /*
+              Read new color or glob patterm.
+            */
+            if (*reply_info.text == '\0')
+              break;
+            (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
+            state|=UpdateListState;
+            break;
+          }
+        if (key_symbol == XK_Control_L)
+          {
+            state|=ControlState;
+            break;
+          }
+        if (state & ControlState)
+          switch ((int) key_symbol)
+          {
+            case XK_u:
+            case XK_U:
+            {
+              /*
+                Erase the entire line of text.
+              */
+              *reply_info.text='\0';
+              reply_info.cursor=reply_info.text;
+              reply_info.marker=reply_info.text;
+              reply_info.highlight=MagickFalse;
+              break;
+            }
+            default:
+              break;
+          }
+        XEditText(display,&reply_info,key_symbol,command,state);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        state|=JumpListState;
+        status=XParseColor(display,windows->widget.map_info->colormap,
+          reply_info.text,&color);
+        if (status != False)
+          state|=RedrawActionState;
+        break;
+      }
+      case KeyRelease:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key release.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (key_symbol == XK_Control_L)
+          state&=(~ControlState);
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MapNotify:
+      {
+        mask&=(~CWX);
+        mask&=(~CWY);
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (slider_info.active)
+          {
+            /*
+              Move slider matte.
+            */
+            slider_info.y=event.xmotion.y-
+              ((slider_info.height+slider_info.bevel_width) >> 1)+1;
+            if (slider_info.y < slider_info.min_y)
+              slider_info.y=slider_info.min_y;
+            if (slider_info.y > slider_info.max_y)
+              slider_info.y=slider_info.max_y;
+            slider_info.id=0;
+            if (slider_info.y != slider_info.min_y)
+              slider_info.id=(int) ((colors*(slider_info.y-
+                slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
+            state|=RedrawListState;
+            break;
+          }
+        if (state & InactiveWidgetState)
+          break;
+        if (grab_info.raised == MatteIsActive(grab_info,event.xmotion))
+          {
+            /*
+              Grab button status changed.
+            */
+            grab_info.raised=!grab_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&grab_info);
+            break;
+          }
+        if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
+          {
+            /*
+              Reset button status changed.
+            */
+            reset_info.raised=!reset_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&reset_info);
+            break;
+          }
+        if (action_info.raised == MatteIsActive(action_info,event.xmotion))
+          {
+            /*
+              Action button status changed.
+            */
+            action_info.raised=action_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        break;
+      }
+      case SelectionClear:
+      {
+        reply_info.highlight=MagickFalse;
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        break;
+      }
+      case SelectionNotify:
+      {
+        Atom
+          type;
+
+        int
+          format;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        /*
+          Obtain response from primary selection.
+        */
+        if (event.xselection.property == (Atom) None)
+          break;
+        status=XGetWindowProperty(display,event.xselection.requestor,
+          event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
+          &format,&length,&after,&data);
+        if ((status != Success) || (type != XA_STRING) || (format == 32) ||
+            (length == 0))
+          break;
+        if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
+          (void) XBell(display,0);
+        else
+          {
+            /*
+              Insert primary selection in reply text.
+            */
+            *(data+length)='\0';
+            XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
+              state);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            state|=JumpListState;
+            state|=RedrawActionState;
+          }
+        (void) XFree((void *) data);
+        break;
+      }
+      case SelectionRequest:
+      {
+        XSelectionEvent
+          notify;
+
+        XSelectionRequestEvent
+          *request;
+
+        if (reply_info.highlight == MagickFalse)
+          break;
+        /*
+          Set primary selection.
+        */
+        request=(&(event.xselectionrequest));
+        (void) XChangeProperty(request->display,request->requestor,
+          request->property,request->target,8,PropModeReplace,
+          (unsigned char *) primary_selection,Extent(primary_selection));
+        notify.type=SelectionNotify;
+        notify.send_event=MagickTrue;
+        notify.display=request->display;
+        notify.requestor=request->requestor;
+        notify.selection=request->selection;
+        notify.target=request->target;
+        notify.time=request->time;
+        if (request->property == None)
+          notify.property=request->target;
+        else
+          notify.property=request->property;
+        (void) XSendEvent(request->display,request->requestor,False,
+          NoEventMask,(XEvent *) &notify);
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  /*
+    Free color list.
+  */
+  for (i=0; i < (int) colors; i++)
+    colorlist[i]=DestroyString(colorlist[i]);
+  if (colorlist != (char **) NULL)
+    colorlist=(char **) RelinquishMagickMemory(colorlist);
+  exception=DestroyExceptionInfo(exception);
+  if ((*reply == '\0') || (strchr(reply,'-') != (char *) NULL))
+    return;
+  status=XParseColor(display,windows->widget.map_info->colormap,reply,&color);
+  if (status != False)
+    return;
+  XNoticeWidget(display,windows,"Color is unknown to X server:",reply);
+  (void) CopyMagickString(reply,"gray",MaxTextExtent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C o m m a n d W i d g e t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XCommandWidget() maps a menu and returns the command pointed to by the user
+%  when the button is released.
+%
+%  The format of the XCommandWidget method is:
+%
+%      int XCommandWidget(Display *display,XWindows *windows,
+%        const char **selections,XEvent *event)
+%
+%  A description of each parameter follows:
+%
+%    o selection_number: Specifies the number of the selection that the
+%      user choose.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o selections: Specifies a pointer to one or more strings that comprise
+%      the choices in the menu.
+%
+%    o event: Specifies a pointer to a X11 XEvent structure.
+%
+*/
+MagickExport int XCommandWidget(Display *display,XWindows *windows,
+  const char **selections,XEvent *event)
+{
+#define tile_width 112
+#define tile_height 70
+
+  static const unsigned char
+    tile_bits[]=
+    {
+      0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x1e, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x1e, 0xbc, 0x9f, 0x03, 0x00, 0x3e, 0x00, 0xc0,
+      0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x0f, 0x80, 0x3f,
+      0x00, 0xf0, 0x1f, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0x1f,
+      0xe0, 0x3f, 0x00, 0xfc, 0x1f, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0xfc,
+      0xff, 0x1f, 0xf0, 0x3f, 0x00, 0xfe, 0x1f, 0xf8, 0x0f, 0x00, 0x00, 0x00,
+      0x1e, 0xfc, 0xfc, 0x3f, 0xf8, 0x3f, 0x00, 0xff, 0x1e, 0xfc, 0x0f, 0x00,
+      0x00, 0x00, 0x1e, 0x7c, 0xfc, 0x3e, 0xf8, 0x3c, 0x80, 0x1f, 0x1e, 0x7c,
+      0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c, 0xc0, 0x0f,
+      0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c, 0x7c, 0x3c,
+      0xc0, 0x07, 0x1e, 0x3e, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x78, 0x78, 0x3c,
+      0x7c, 0x7c, 0xc0, 0x0f, 0x1e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x78,
+      0x78, 0x3c, 0xfc, 0x7c, 0x80, 0x7f, 0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00,
+      0x1e, 0xf8, 0x78, 0x7c, 0xf8, 0xff, 0x00, 0xff, 0x1f, 0xf8, 0xff, 0x00,
+      0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xfe, 0x1f, 0xf8,
+      0xff, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xf0, 0xff, 0x07, 0xf8,
+      0x1f, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0xf8, 0x78, 0x7c, 0xc0, 0xef,
+      0x07, 0xe0, 0x1f, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x1e, 0x70, 0x40, 0x78,
+      0x00, 0xc7, 0x07, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+      0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x02, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
+      0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x60, 0x00, 0xc0, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xc0, 0x8f, 0x3f, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0x9f, 0x7f, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xe0, 0xdf,
+      0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x00,
+      0xe0, 0xdf, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0c,
+      0x78, 0x30, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
+      0x00, 0x0f, 0xf8, 0x70, 0xf0, 0xff, 0x7b, 0x00, 0x00, 0x1f, 0x00, 0xe0,
+      0x0f, 0x1e, 0x80, 0x0f, 0xf8, 0x78, 0xf0, 0xfd, 0xf9, 0x00, 0xc0, 0x1f,
+      0x00, 0xf8, 0x0f, 0x00, 0xe0, 0x1f, 0xf8, 0x7c, 0xf0, 0xfc, 0xf9, 0x00,
+      0xf0, 0x1f, 0x00, 0xfe, 0x0f, 0x00, 0xf0, 0x07, 0xf8, 0x3e, 0xf8, 0xfc,
+      0xf0, 0x01, 0xf8, 0x1f, 0x00, 0xff, 0x0f, 0x1e, 0xf0, 0x03, 0xf8, 0x3f,
+      0xf8, 0xf8, 0xf0, 0x01, 0xfc, 0x1f, 0x80, 0x7f, 0x0f, 0x1e, 0xf8, 0x00,
+      0xf8, 0x1f, 0x78, 0x18, 0xf0, 0x01, 0x7c, 0x1e, 0xc0, 0x0f, 0x0f, 0x1e,
+      0x7c, 0x00, 0xf0, 0x0f, 0x78, 0x00, 0xf0, 0x01, 0x3e, 0x1e, 0xe0, 0x07,
+      0x0f, 0x1e, 0x7c, 0x00, 0xf0, 0x07, 0x7c, 0x00, 0xe0, 0x01, 0x3e, 0x1e,
+      0xe0, 0x03, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x0f, 0x7c, 0x00, 0xe0, 0x03,
+      0x3e, 0x3e, 0xe0, 0x07, 0x0f, 0x1e, 0x1e, 0x00, 0xf0, 0x1f, 0x3c, 0x00,
+      0xe0, 0x03, 0x7e, 0x3e, 0xc0, 0x3f, 0x0f, 0x1e, 0x3e, 0x00, 0xf0, 0x1f,
+      0x3e, 0x00, 0xe0, 0x03, 0xfc, 0x7f, 0x80, 0xff, 0x0f, 0x1e, 0xfc, 0x00,
+      0xf0, 0x3e, 0x3e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xff, 0x0f, 0x1e,
+      0xfc, 0x07, 0xf0, 0x7c, 0x1e, 0x00, 0xc0, 0x03, 0xf8, 0xff, 0x03, 0xfc,
+      0x0f, 0x1e, 0xf8, 0x1f, 0xf0, 0xf8, 0x1e, 0x00, 0xc0, 0x03, 0xe0, 0xf7,
+      0x03, 0xf0, 0x0f, 0x1e, 0xe0, 0x3f, 0xf0, 0x78, 0x1c, 0x00, 0x80, 0x03,
+      0x80, 0xe3, 0x03, 0x00, 0x0f, 0x1e, 0xc0, 0x3f, 0xf0, 0x30, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0x3e, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x10,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+      0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+
+  int
+    id,
+    y;
+
+  register int
+    i;
+
+  static unsigned int
+    number_selections;
+
+  unsigned int
+    height;
+
+  size_t
+    state;
+
+  XFontStruct
+    *font_info;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  font_info=windows->command.font_info;
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  id=(~0);
+  state=DefaultState;
+  if (event == (XEvent *) NULL)
+    {
+      unsigned int
+        width;
+
+      XTextProperty
+        window_name;
+
+      XWindowChanges
+        window_changes;
+
+      /*
+        Determine command window attributes.
+      */
+      assert(selections != (const char **) NULL);
+      windows->command.width=0;
+      for (i=0; selections[i] != (char *) NULL; i++)
+      {
+        width=WidgetTextWidth(font_info,(char *) selections[i]);
+        if (width > windows->command.width)
+          windows->command.width=width;
+      }
+      number_selections=(unsigned int) i;
+      windows->command.width+=3*QuantumMargin+10;
+      if ((int) windows->command.width < (tile_width+QuantumMargin+10))
+        windows->command.width=(unsigned  int) (tile_width+QuantumMargin+10);
+      windows->command.height=(unsigned  int) (number_selections*
+        (((3*height) >> 1)+10)+tile_height+20);
+      windows->command.min_width=windows->command.width;
+      windows->command.min_height=windows->command.height;
+      XConstrainWindowPosition(display,&windows->command);
+      if (windows->command.id != (Window) NULL)
+        {
+          Status
+            status;
+
+          /*
+            Reconfigure command window.
+          */
+          status=XStringListToTextProperty(&windows->command.name,1,
+            &window_name);
+          if (status != False)
+            {
+              XSetWMName(display,windows->command.id,&window_name);
+              XSetWMIconName(display,windows->command.id,&window_name);
+              (void) XFree((void *) window_name.value);
+            }
+          window_changes.width=(int) windows->command.width;
+          window_changes.height=(int) windows->command.height;
+          (void) XReconfigureWMWindow(display,windows->command.id,
+            windows->command.screen,(unsigned int) (CWWidth | CWHeight),
+            &window_changes);
+        }
+      /*
+        Allocate selection info memory.
+      */
+      if (selection_info != (XWidgetInfo *) NULL)
+        selection_info=(XWidgetInfo *) RelinquishMagickMemory(selection_info);
+      selection_info=(XWidgetInfo *) AcquireQuantumMemory(number_selections,
+        sizeof(*selection_info));
+      if (selection_info == (XWidgetInfo *) NULL)
+        {
+          ThrowXWindowFatalException(ResourceLimitError,
+            "MemoryAllocationFailed","...");
+          return(id);
+        }
+      state|=UpdateConfigurationState | RedrawWidgetState;
+    }
+  /*
+    Wait for next event.
+  */
+  if (event != (XEvent *) NULL)
+    switch (event->type)
+    {
+      case ButtonPress:
+      {
+        for (i=0; i < (int) number_selections; i++)
+        {
+          if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
+            continue;
+          if (i >= (int) windows->command.data)
+            {
+              selection_info[i].raised=MagickFalse;
+              XDrawBeveledButton(display,&windows->command,&selection_info[i]);
+              break;
+            }
+          submenu_info=selection_info[i];
+          submenu_info.active=MagickTrue;
+          toggle_info.y=
+            submenu_info.y+(submenu_info.height >> 1)-(toggle_info.height >> 1);
+          id=i;
+          (void) XCheckWindowEvent(display,windows->widget.id,LeaveWindowMask,
+            event);
+          break;
+        }
+        break;
+      }
+      case ButtonRelease:
+      {
+        for (i=0; i < (int) number_selections; i++)
+        {
+          if (MatteIsActive(selection_info[i],event->xbutton) == MagickFalse)
+            continue;
+          id=i;
+          if (id >= (int) windows->command.data)
+            {
+              selection_info[id].raised=MagickTrue;
+              XDrawBeveledButton(display,&windows->command,&selection_info[id]);
+              break;
+            }
+          break;
+        }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, withdraw command widget.
+        */
+        if (event->xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event->xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        (void) XWithdrawWindow(display,windows->command.id,
+          windows->command.screen);
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event->xconfigure.window != windows->command.id)
+          break;
+        if (event->xconfigure.send_event != 0)
+          {
+            windows->command.x=event->xconfigure.x;
+            windows->command.y=event->xconfigure.y;
+          }
+        if ((event->xconfigure.width == (int) windows->command.width) &&
+            (event->xconfigure.height == (int) windows->command.height))
+          break;
+        windows->command.width=(unsigned int)
+          MagickMax(event->xconfigure.width,(int) windows->command.min_width);
+        windows->command.height=(unsigned int)
+          MagickMax(event->xconfigure.height,(int) windows->command.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case Expose:
+      {
+        if (event->xexpose.window != windows->command.id)
+          break;
+        if (event->xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Return the ID of the highlighted menu entry.
+        */
+        for ( ; ; )
+        {
+          for (i=0; i < (int) number_selections; i++)
+          {
+            if (i >= (int) windows->command.data)
+              {
+                if (selection_info[i].raised ==
+                    MatteIsActive(selection_info[i],event->xmotion))
+                  {
+                    /*
+                      Button status changed.
+                    */
+                    selection_info[i].raised=!selection_info[i].raised;
+                    XDrawBeveledButton(display,&windows->command,
+                      &selection_info[i]);
+                  }
+                continue;
+              }
+            if (MatteIsActive(selection_info[i],event->xmotion) == MagickFalse)
+              continue;
+            submenu_info=selection_info[i];
+            submenu_info.active=MagickTrue;
+            toggle_info.raised=MagickTrue;
+            toggle_info.y=submenu_info.y+(submenu_info.height >> 1)-
+              (toggle_info.height >> 1);
+            XDrawTriangleEast(display,&windows->command,&toggle_info);
+            id=i;
+          }
+          XDelay(display,SuspendTime);
+          if (XCheckMaskEvent(display,ButtonMotionMask,event) == MagickFalse)
+            break;
+          while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
+          toggle_info.raised=MagickFalse;
+          if (windows->command.data != 0)
+            XDrawTriangleEast(display,&windows->command,&toggle_info);
+        }
+        break;
+      }
+      case MapNotify:
+      {
+        windows->command.mapped=MagickTrue;
+        break;
+      }
+      case UnmapNotify:
+      {
+        windows->command.mapped=MagickFalse;
+        break;
+      }
+      default:
+        break;
+    }
+  if (state & UpdateConfigurationState)
+    {
+      /*
+        Initialize button information.
+      */
+      assert(selections != (const char **) NULL);
+      y=tile_height+20;
+      for (i=0; i < (int) number_selections; i++)
+      {
+        XGetWidgetInfo(selections[i],&selection_info[i]);
+        selection_info[i].center=MagickFalse;
+        selection_info[i].bevel_width--;
+        selection_info[i].height=(unsigned int) ((3*height) >> 1);
+        selection_info[i].x=(QuantumMargin >> 1)+4;
+        selection_info[i].width=(unsigned int)
+          (windows->command.width-(selection_info[i].x << 1));
+        selection_info[i].y=y;
+        y+=selection_info[i].height+(selection_info[i].bevel_width << 1)+6;
+      }
+      XGetWidgetInfo((char *) NULL,&toggle_info);
+      toggle_info.bevel_width--;
+      toggle_info.width=(unsigned int)
+        (((5*height) >> 3)-(toggle_info.bevel_width << 1));
+      toggle_info.height=toggle_info.width;
+      toggle_info.x=selection_info[0].x+selection_info[0].width-
+        toggle_info.width-(QuantumMargin >> 1);
+      if (windows->command.mapped)
+        (void) XClearWindow(display,windows->command.id);
+    }
+  if (state & RedrawWidgetState)
+    {
+      Pixmap
+        tile_pixmap;
+
+      /*
+        Draw command buttons.
+      */
+      tile_pixmap=XCreatePixmapFromBitmapData(display,windows->command.id,
+        (char *) tile_bits,tile_width,tile_height,1L,0L,1);
+      if (tile_pixmap != (Pixmap) NULL)
+        {
+          (void) XCopyPlane(display,tile_pixmap,windows->command.id,
+            windows->command.annotate_context,0,0,tile_width,tile_height,
+            (int) ((windows->command.width-tile_width) >> 1),10,1L);
+          (void) XFreePixmap(display,tile_pixmap);
+        }
+      for (i=0; i < (int) number_selections; i++)
+      {
+        XDrawBeveledButton(display,&windows->command,&selection_info[i]);
+        if (i >= (int) windows->command.data)
+          continue;
+        toggle_info.raised=i == id ? MagickTrue : MagickFalse;
+        toggle_info.y=selection_info[i].y+
+          (selection_info[i].height >> 1)-(toggle_info.height >> 1);
+        XDrawTriangleEast(display,&windows->command,&toggle_info);
+      }
+      XHighlightWidget(display,&windows->command,BorderOffset,BorderOffset);
+    }
+  return(id);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C o n f i r m W i d g e t                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XConfirmWidget() displays a Confirm widget with a notice to the user. The
+%  function returns -1 if Dismiss is pressed, 0 for Cancel, and 1 for Yes.
+%
+%  The format of the XConfirmWidget method is:
+%
+%      int XConfirmWidget(Display *display,XWindows *windows,
+%        const char *reason,const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o reason: Specifies the message to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the message.
+%
+*/
+MagickExport int XConfirmWidget(Display *display,XWindows *windows,
+  const char *reason,const char *description)
+{
+#define CancelButtonText  "Cancel"
+#define DismissButtonText  "Dismiss"
+#define YesButtonText  "Yes"
+
+  int
+    confirm,
+    x,
+    y;
+
+  Status
+    status;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    cancel_info,
+    dismiss_info,
+    yes_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Determine Confirm widget attributes.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(reason != (char *) NULL);
+  assert(description != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
+  XCheckRefreshWindows(display,windows);
+  font_info=windows->widget.font_info;
+  width=WidgetTextWidth(font_info,CancelButtonText);
+  if (WidgetTextWidth(font_info,DismissButtonText) > width)
+    width=WidgetTextWidth(font_info,DismissButtonText);
+  if (WidgetTextWidth(font_info,YesButtonText) > width)
+    width=WidgetTextWidth(font_info,YesButtonText);
+  width<<=1;
+  if (description != (char *) NULL)
+    if (WidgetTextWidth(font_info,(char *) description) > width)
+      width=WidgetTextWidth(font_info,(char *) description);
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position Confirm widget.
+  */
+  windows->widget.width=(unsigned int) (width+9*QuantumMargin);
+  windows->widget.min_width=(unsigned int) (9*QuantumMargin+
+    WidgetTextWidth(font_info,CancelButtonText)+
+    WidgetTextWidth(font_info,DismissButtonText)+
+    WidgetTextWidth(font_info,YesButtonText));
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int) (12*height);
+  windows->widget.min_height=(unsigned int) (7*height);
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Confirm widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Confirm",MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
+    (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  confirm=0;
+  state=UpdateConfigurationState;
+  XSetCursorState(display,windows,MagickTrue);
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=(unsigned int) QuantumMargin+
+          WidgetTextWidth(font_info,CancelButtonText);
+        cancel_info.height=(unsigned int) ((3*height) >> 1);
+        cancel_info.x=(int) (windows->widget.width-cancel_info.width-
+          QuantumMargin);
+        cancel_info.y=(int) (windows->widget.height-(cancel_info.height << 1));
+        dismiss_info=cancel_info;
+        dismiss_info.text=(char *) DismissButtonText;
+        if (LocaleCompare(description,"Do you want to save it") == 0)
+          dismiss_info.text=(char *) "Don't Save";
+        dismiss_info.width=(unsigned int) QuantumMargin+
+          WidgetTextWidth(font_info,dismiss_info.text);
+        dismiss_info.x=(int)
+          ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
+        yes_info=cancel_info;
+        yes_info.text=(char *) YesButtonText;
+        if (LocaleCompare(description,"Do you want to save it") == 0)
+          yes_info.text=(char *) "Save";
+        yes_info.width=(unsigned int) QuantumMargin+
+          WidgetTextWidth(font_info,yes_info.text);
+        if (yes_info.width < cancel_info.width)
+          yes_info.width=cancel_info.width;
+        yes_info.x=QuantumMargin;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Confirm widget.
+        */
+        width=WidgetTextWidth(font_info,(char *) reason);
+        x=(int) ((windows->widget.width >> 1)-(width >> 1));
+        y=(int) ((windows->widget.height >> 1)-(height << 1));
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
+        if (description != (char *) NULL)
+          {
+            char
+              question[MaxTextExtent];
+
+            (void) CopyMagickString(question,description,MaxTextExtent);
+            (void) ConcatenateMagickString(question,"?",MaxTextExtent);
+            width=WidgetTextWidth(font_info,question);
+            x=(int) ((windows->widget.width >> 1)-(width >> 1));
+            y+=height;
+            (void) XDrawString(display,windows->widget.id,
+              windows->widget.annotate_context,x,y,question,Extent(question));
+          }
+        XDrawBeveledButton(display,&windows->widget,&cancel_info);
+        XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+        XDrawBeveledButton(display,&windows->widget,&yes_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~RedrawWidgetState);
+      }
+    /*
+      Wait for next event.
+    */
+    (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed No button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        if (MatteIsActive(dismiss_info,event.xbutton))
+          {
+            /*
+              User pressed Dismiss button.
+            */
+            dismiss_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            break;
+          }
+        if (MatteIsActive(yes_info,event.xbutton))
+          {
+            /*
+              User pressed Yes button.
+            */
+            yes_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&yes_info);
+            break;
+          }
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                {
+                  confirm=0;
+                  state|=ExitState;
+                }
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+          }
+        if (dismiss_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(dismiss_info,event.xbutton))
+                {
+                  confirm=(-1);
+                  state|=ExitState;
+                }
+            dismiss_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+          }
+        if (yes_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(yes_info,event.xbutton))
+                {
+                  confirm=1;
+                  state|=ExitState;
+                }
+            yes_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&yes_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            yes_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&yes_info);
+            confirm=1;
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (state & InactiveWidgetState)
+          break;
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
+          {
+            /*
+              Dismiss button status changed.
+            */
+            dismiss_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            break;
+          }
+        if (yes_info.raised == MatteIsActive(yes_info,event.xmotion))
+          {
+            /*
+              Yes button status changed.
+            */
+            yes_info.raised=yes_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&yes_info);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  return(confirm);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D i a l o g W i d g e t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDialogWidget() displays a Dialog widget with a query to the user.  The user
+%  keys a reply and presses the Ok or Cancel button to exit.  The typed text is
+%  returned as the reply function parameter.
+%
+%  The format of the XDialogWidget method is:
+%
+%      int XDialogWidget(Display *display,XWindows *windows,const char *action,
+%        const char *query,char *reply)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o action: Specifies a pointer to the action of this widget.
+%
+%    o query: Specifies a pointer to the query to present to the user.
+%
+%    o reply: the response from the user is returned in this parameter.
+%
+*/
+MagickExport int XDialogWidget(Display *display,XWindows *windows,
+  const char *action,const char *query,char *reply)
+{
+#define CancelButtonText  "Cancel"
+
+  char
+    primary_selection[MaxTextExtent];
+
+  int
+    x;
+
+  register int
+    i;
+
+  static MagickBooleanType
+    raised = MagickFalse;
+
+  Status
+    status;
+
+  unsigned int
+    anomaly,
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    action_info,
+    cancel_info,
+    reply_info,
+    special_info,
+    text_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Determine Dialog widget attributes.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(action != (char *) NULL);
+  assert(query != (char *) NULL);
+  assert(reply != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
+  XCheckRefreshWindows(display,windows);
+  font_info=windows->widget.font_info;
+  width=WidgetTextWidth(font_info,(char *) action);
+  if (WidgetTextWidth(font_info,CancelButtonText) > width)
+    width=WidgetTextWidth(font_info,CancelButtonText);
+  width+=(3*QuantumMargin) >> 1;
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position Dialog widget.
+  */
+  windows->widget.width=(unsigned int) MagickMax((int) (2*width),(int)
+    WidgetTextWidth(font_info,(char *) query));
+  if (windows->widget.width < WidgetTextWidth(font_info,reply))
+    windows->widget.width=WidgetTextWidth(font_info,reply);
+  windows->widget.width+=6*QuantumMargin;
+  windows->widget.min_width=(unsigned int)
+    (width+28*XTextWidth(font_info,"#",1)+4*QuantumMargin);
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int) (7*height+(QuantumMargin << 1));
+  windows->widget.min_height=windows->widget.height;
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Dialog widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Dialog",MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
+    (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  anomaly=(LocaleCompare(action,"Background") == 0) ||
+    (LocaleCompare(action,"New") == 0) ||
+    (LocaleCompare(action,"Quantize") == 0) ||
+    (LocaleCompare(action,"Resize") == 0) ||
+    (LocaleCompare(action,"Save") == 0) ||
+    (LocaleCompare(action,"Shade") == 0);
+  state=UpdateConfigurationState;
+  XSetCursorState(display,windows,MagickTrue);
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=width;
+        cancel_info.height=(unsigned int) ((3*height) >> 1);
+        cancel_info.x=(int)
+          (windows->widget.width-cancel_info.width-((3*QuantumMargin) >> 1));
+        cancel_info.y=(int)
+          (windows->widget.height-cancel_info.height-((3*QuantumMargin) >> 1));
+        XGetWidgetInfo(action,&action_info);
+        action_info.width=width;
+        action_info.height=(unsigned int) ((3*height) >> 1);
+        action_info.x=cancel_info.x-(cancel_info.width+QuantumMargin+
+          (action_info.bevel_width << 1));
+        action_info.y=cancel_info.y;
+        /*
+          Initialize reply information.
+        */
+        XGetWidgetInfo(reply,&reply_info);
+        reply_info.raised=MagickFalse;
+        reply_info.bevel_width--;
+        reply_info.width=windows->widget.width-(3*QuantumMargin);
+        reply_info.height=height << 1;
+        reply_info.x=(3*QuantumMargin) >> 1;
+        reply_info.y=action_info.y-reply_info.height-QuantumMargin;
+        /*
+          Initialize option information.
+        */
+        XGetWidgetInfo("Dither",&special_info);
+        special_info.raised=raised;
+        special_info.bevel_width--;
+        special_info.width=(unsigned int) QuantumMargin >> 1;
+        special_info.height=(unsigned int) QuantumMargin >> 1;
+        special_info.x=reply_info.x;
+        special_info.y=action_info.y+action_info.height-special_info.height;
+        if (LocaleCompare(action,"Background") == 0)
+          special_info.text=(char *) "Backdrop";
+        if (LocaleCompare(action,"New") == 0)
+          special_info.text=(char *) "Gradation";
+        if (LocaleCompare(action,"Resize") == 0)
+          special_info.text=(char *) "Constrain ratio";
+        if (LocaleCompare(action,"Save") == 0)
+          special_info.text=(char *) "Non-progressive";
+        if (LocaleCompare(action,"Shade") == 0)
+          special_info.text=(char *) "Color shading";
+        /*
+          Initialize text information.
+        */
+        XGetWidgetInfo(query,&text_info);
+        text_info.width=reply_info.width;
+        text_info.height=height;
+        text_info.x=reply_info.x-(QuantumMargin >> 1);
+        text_info.y=QuantumMargin;
+        text_info.center=MagickFalse;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Dialog widget.
+        */
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawBeveledMatte(display,&windows->widget,&reply_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        if (anomaly)
+          XDrawBeveledButton(display,&windows->widget,&special_info);
+        XDrawBeveledButton(display,&windows->widget,&action_info);
+        XDrawBeveledButton(display,&windows->widget,&cancel_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~RedrawWidgetState);
+      }
+    /*
+      Wait for next event.
+    */
+    (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (anomaly)
+          if (MatteIsActive(special_info,event.xbutton))
+            {
+              /*
+                Option button status changed.
+              */
+              special_info.raised=!special_info.raised;
+              XDrawBeveledButton(display,&windows->widget,&special_info);
+              break;
+            }
+        if (MatteIsActive(action_info,event.xbutton))
+          {
+            /*
+              User pressed Action button.
+            */
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed Cancel button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        if (event.xbutton.button != Button2)
+          {
+            static Time
+              click_time;
+
+            /*
+              Move text cursor to position of button press.
+            */
+            x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
+            for (i=1; i <= Extent(reply_info.marker); i++)
+              if (XTextWidth(font_info,reply_info.marker,i) > x)
+                break;
+            reply_info.cursor=reply_info.marker+i-1;
+            if (event.xbutton.time > (click_time+DoubleClick))
+              reply_info.highlight=MagickFalse;
+            else
+              {
+                /*
+                  Become the XA_PRIMARY selection owner.
+                */
+                (void) CopyMagickString(primary_selection,reply_info.text,
+                  MaxTextExtent);
+                (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
+                  event.xbutton.time);
+                reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
+                  windows->widget.id ? MagickTrue : MagickFalse;
+              }
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            click_time=event.xbutton.time;
+            break;
+          }
+        /*
+          Request primary selection.
+        */
+        (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
+          windows->widget.id,event.xbutton.time);
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (action_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(action_info,event.xbutton))
+                state|=ExitState;
+            action_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+          }
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                {
+                  *reply_info.text='\0';
+                  state|=ExitState;
+                }
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            *reply_info.text='\0';
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static int
+          length;
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        length=XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            state|=ExitState;
+            break;
+          }
+        if (key_symbol == XK_Control_L)
+          {
+            state|=ControlState;
+            break;
+          }
+        if (state & ControlState)
+          switch ((int) key_symbol)
+          {
+            case XK_u:
+            case XK_U:
+            {
+              /*
+                Erase the entire line of text.
+              */
+              *reply_info.text='\0';
+              reply_info.cursor=reply_info.text;
+              reply_info.marker=reply_info.text;
+              reply_info.highlight=MagickFalse;
+              break;
+            }
+            default:
+              break;
+          }
+        XEditText(display,&reply_info,key_symbol,command,state);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        break;
+      }
+      case KeyRelease:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key release.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (key_symbol == XK_Control_L)
+          state&=(~ControlState);
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (state & InactiveWidgetState)
+          break;
+        if (action_info.raised == MatteIsActive(action_info,event.xmotion))
+          {
+            /*
+              Action button status changed.
+            */
+            action_info.raised=action_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        break;
+      }
+      case SelectionClear:
+      {
+        reply_info.highlight=MagickFalse;
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        break;
+      }
+      case SelectionNotify:
+      {
+        Atom
+          type;
+
+        int
+          format;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        /*
+          Obtain response from primary selection.
+        */
+        if (event.xselection.property == (Atom) None)
+          break;
+        status=XGetWindowProperty(display,event.xselection.requestor,
+          event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
+          &format,&length,&after,&data);
+        if ((status != Success) || (type != XA_STRING) || (format == 32) ||
+            (length == 0))
+          break;
+        if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
+          (void) XBell(display,0);
+        else
+          {
+            /*
+              Insert primary selection in reply text.
+            */
+            *(data+length)='\0';
+            XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
+              state);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+          }
+        (void) XFree((void *) data);
+        break;
+      }
+      case SelectionRequest:
+      {
+        XSelectionEvent
+          notify;
+
+        XSelectionRequestEvent
+          *request;
+
+        if (reply_info.highlight == MagickFalse)
+          break;
+        /*
+          Set primary selection.
+        */
+        request=(&(event.xselectionrequest));
+        (void) XChangeProperty(request->display,request->requestor,
+          request->property,request->target,8,PropModeReplace,
+          (unsigned char *) primary_selection,Extent(primary_selection));
+        notify.type=SelectionNotify;
+        notify.display=request->display;
+        notify.requestor=request->requestor;
+        notify.selection=request->selection;
+        notify.target=request->target;
+        notify.time=request->time;
+        if (request->property == None)
+          notify.property=request->target;
+        else
+          notify.property=request->property;
+        (void) XSendEvent(request->display,request->requestor,False,0,
+          (XEvent *) &notify);
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  if (anomaly)
+    if (special_info.raised)
+      if (*reply != '\0')
+        raised=MagickTrue;
+  return(raised == MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X F i l e B r o w s e r W i d g e t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XFileBrowserWidget() displays a File Browser widget with a file query to the
+%  user.  The user keys a reply and presses the Action or Cancel button to
+%  exit.  The typed text is returned as the reply function parameter.
+%
+%  The format of the XFileBrowserWidget method is:
+%
+%      void XFileBrowserWidget(Display *display,XWindows *windows,
+%        const char *action,char *reply)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o action: Specifies a pointer to the action of this widget.
+%
+%    o reply: the response from the user is returned in this parameter.
+%
+*/
+MagickExport void XFileBrowserWidget(Display *display,XWindows *windows,
+  const char *action,char *reply)
+{
+#define CancelButtonText  "Cancel"
+#define DirectoryText  "Directory:"
+#define FilenameText  "File name:"
+#define GrabButtonText  "Grab"
+#define FormatButtonText  "Format"
+#define HomeButtonText  "Home"
+#define UpButtonText  "Up"
+
+  char
+    *directory,
+    **filelist,
+    home_directory[MaxTextExtent],
+    primary_selection[MaxTextExtent],
+    text[MaxTextExtent],
+    working_path[MaxTextExtent];
+
+  int
+    x,
+    y;
+
+  register ssize_t
+    i;
+
+  static char
+    glob_pattern[MaxTextExtent] = "*",
+    format[MaxTextExtent] = "miff";
+
+  static MagickStatusType
+    mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
+
+  Status
+    status;
+
+  unsigned int
+    anomaly,
+    height,
+    text_width,
+    visible_files,
+    width;
+
+  size_t
+    delay,
+    files,
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    action_info,
+    cancel_info,
+    expose_info,
+    special_info,
+    list_info,
+    home_info,
+    north_info,
+    reply_info,
+    scroll_info,
+    selection_info,
+    slider_info,
+    south_info,
+    text_info,
+    up_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Read filelist from current directory.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(action != (char *) NULL);
+  assert(reply != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  directory=getcwd(home_directory,MaxTextExtent);
+  (void) directory;
+  (void) CopyMagickString(working_path,home_directory,MaxTextExtent);
+  filelist=ListFiles(working_path,glob_pattern,&files);
+  if (filelist == (char **) NULL)
+    {
+      /*
+        Directory read failed.
+      */
+      XNoticeWidget(display,windows,"Unable to read directory:",working_path);
+      (void) XDialogWidget(display,windows,action,"Enter filename:",reply);
+      return;
+    }
+  /*
+    Determine File Browser widget attributes.
+  */
+  font_info=windows->widget.font_info;
+  text_width=0;
+  for (i=0; i < (ssize_t) files; i++)
+    if (WidgetTextWidth(font_info,filelist[i]) > text_width)
+      text_width=WidgetTextWidth(font_info,filelist[i]);
+  width=WidgetTextWidth(font_info,(char *) action);
+  if (WidgetTextWidth(font_info,GrabButtonText) > width)
+    width=WidgetTextWidth(font_info,GrabButtonText);
+  if (WidgetTextWidth(font_info,FormatButtonText) > width)
+    width=WidgetTextWidth(font_info,FormatButtonText);
+  if (WidgetTextWidth(font_info,CancelButtonText) > width)
+    width=WidgetTextWidth(font_info,CancelButtonText);
+  if (WidgetTextWidth(font_info,HomeButtonText) > width)
+    width=WidgetTextWidth(font_info,HomeButtonText);
+  if (WidgetTextWidth(font_info,UpButtonText) > width)
+    width=WidgetTextWidth(font_info,UpButtonText);
+  width+=QuantumMargin;
+  if (WidgetTextWidth(font_info,DirectoryText) > width)
+    width=WidgetTextWidth(font_info,DirectoryText);
+  if (WidgetTextWidth(font_info,FilenameText) > width)
+    width=WidgetTextWidth(font_info,FilenameText);
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position File Browser widget.
+  */
+  windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
+    6*QuantumMargin;
+  windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int)
+    (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
+  windows->widget.min_height=(unsigned int)
+    (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map File Browser widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Browse and Select a File",
+    MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,
+    windows->widget.screen,mask,&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  XGetWidgetInfo((char *) NULL,&slider_info);
+  XGetWidgetInfo((char *) NULL,&north_info);
+  XGetWidgetInfo((char *) NULL,&south_info);
+  XGetWidgetInfo((char *) NULL,&expose_info);
+  visible_files=0;
+  anomaly=(LocaleCompare(action,"Composite") == 0) ||
+    (LocaleCompare(action,"Open") == 0) || (LocaleCompare(action,"Map") == 0);
+  *reply='\0';
+  delay=SuspendTime << 2;
+  state=UpdateConfigurationState;
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        int
+          id;
+
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=width;
+        cancel_info.height=(unsigned int) ((3*height) >> 1);
+        cancel_info.x=(int)
+          (windows->widget.width-cancel_info.width-QuantumMargin-2);
+        cancel_info.y=(int)
+          (windows->widget.height-cancel_info.height-QuantumMargin);
+        XGetWidgetInfo(action,&action_info);
+        action_info.width=width;
+        action_info.height=(unsigned int) ((3*height) >> 1);
+        action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
+          (action_info.bevel_width << 1));
+        action_info.y=cancel_info.y;
+        XGetWidgetInfo(GrabButtonText,&special_info);
+        special_info.width=width;
+        special_info.height=(unsigned int) ((3*height) >> 1);
+        special_info.x=action_info.x-(action_info.width+(QuantumMargin >> 1)+
+          (special_info.bevel_width << 1));
+        special_info.y=action_info.y;
+        if (anomaly == MagickFalse)
+          {
+            register char
+              *p;
+
+            special_info.text=(char *) FormatButtonText;
+            p=reply+Extent(reply)-1;
+            while ((p > (reply+1)) && (*(p-1) != '.'))
+              p--;
+            if ((p > (reply+1)) && (*(p-1) == '.'))
+              (void) CopyMagickString(format,p,MaxTextExtent);
+          }
+        XGetWidgetInfo(UpButtonText,&up_info);
+        up_info.width=width;
+        up_info.height=(unsigned int) ((3*height) >> 1);
+        up_info.x=QuantumMargin;
+        up_info.y=((5*QuantumMargin) >> 1)+height;
+        XGetWidgetInfo(HomeButtonText,&home_info);
+        home_info.width=width;
+        home_info.height=(unsigned int) ((3*height) >> 1);
+        home_info.x=QuantumMargin;
+        home_info.y=up_info.y+up_info.height+QuantumMargin;
+        /*
+          Initialize reply information.
+        */
+        XGetWidgetInfo(reply,&reply_info);
+        reply_info.raised=MagickFalse;
+        reply_info.bevel_width--;
+        reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
+        reply_info.height=height << 1;
+        reply_info.x=(int) (width+(QuantumMargin << 1));
+        reply_info.y=action_info.y-reply_info.height-QuantumMargin;
+        /*
+          Initialize scroll information.
+        */
+        XGetWidgetInfo((char *) NULL,&scroll_info);
+        scroll_info.bevel_width--;
+        scroll_info.width=height;
+        scroll_info.height=(unsigned int)
+          (reply_info.y-up_info.y-(QuantumMargin >> 1));
+        scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
+        scroll_info.y=up_info.y-reply_info.bevel_width;
+        scroll_info.raised=MagickFalse;
+        scroll_info.trough=MagickTrue;
+        north_info=scroll_info;
+        north_info.raised=MagickTrue;
+        north_info.width-=(north_info.bevel_width << 1);
+        north_info.height=north_info.width-1;
+        north_info.x+=north_info.bevel_width;
+        north_info.y+=north_info.bevel_width;
+        south_info=north_info;
+        south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
+          south_info.height;
+        id=slider_info.id;
+        slider_info=north_info;
+        slider_info.id=id;
+        slider_info.width-=2;
+        slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
+          slider_info.bevel_width+2;
+        slider_info.height=scroll_info.height-((slider_info.min_y-
+          scroll_info.y+1) << 1)+4;
+        visible_files=scroll_info.height/(height+(height >> 3));
+        if (files > visible_files)
+          slider_info.height=(unsigned int)
+            ((visible_files*slider_info.height)/files);
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.x=scroll_info.x+slider_info.bevel_width+1;
+        slider_info.y=slider_info.min_y;
+        expose_info=scroll_info;
+        expose_info.y=slider_info.y;
+        /*
+          Initialize list information.
+        */
+        XGetWidgetInfo((char *) NULL,&list_info);
+        list_info.raised=MagickFalse;
+        list_info.bevel_width--;
+        list_info.width=(unsigned int)
+          (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
+        list_info.height=scroll_info.height;
+        list_info.x=reply_info.x;
+        list_info.y=scroll_info.y;
+        if (windows->widget.mapped == MagickFalse)
+          state|=JumpListState;
+        /*
+          Initialize text information.
+        */
+        *text='\0';
+        XGetWidgetInfo(text,&text_info);
+        text_info.center=MagickFalse;
+        text_info.width=reply_info.width;
+        text_info.height=height;
+        text_info.x=list_info.x-(QuantumMargin >> 1);
+        text_info.y=QuantumMargin;
+        /*
+          Initialize selection information.
+        */
+        XGetWidgetInfo((char *) NULL,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.width=list_info.width;
+        selection_info.height=(unsigned int) ((9*height) >> 3);
+        selection_info.x=list_info.x;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw File Browser window.
+        */
+        x=QuantumMargin;
+        y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,DirectoryText,
+          Extent(DirectoryText));
+        (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
+        (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
+          MaxTextExtent);
+        (void) ConcatenateMagickString(text_info.text,glob_pattern,
+          MaxTextExtent);
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawBeveledButton(display,&windows->widget,&up_info);
+        XDrawBeveledButton(display,&windows->widget,&home_info);
+        XDrawBeveledMatte(display,&windows->widget,&list_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        x=QuantumMargin;
+        y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,FilenameText,
+          Extent(FilenameText));
+        XDrawBeveledMatte(display,&windows->widget,&reply_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        XDrawBeveledButton(display,&windows->widget,&special_info);
+        XDrawBeveledButton(display,&windows->widget,&action_info);
+        XDrawBeveledButton(display,&windows->widget,&cancel_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        selection_info.id=(~0);
+        state|=RedrawListState;
+        state&=(~RedrawWidgetState);
+      }
+    if (state & UpdateListState)
+      {
+        char
+          **checklist;
+
+        size_t
+          number_files;
+
+        /*
+          Update file list.
+        */
+        checklist=ListFiles(working_path,glob_pattern,&number_files);
+        if (checklist == (char **) NULL)
+          {
+            /*
+              Reply is a filename, exit.
+            */
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        for (i=0; i < (ssize_t) files; i++)
+          filelist[i]=DestroyString(filelist[i]);
+        if (filelist != (char **) NULL)
+          filelist=(char **) RelinquishMagickMemory(filelist);
+        filelist=checklist;
+        files=number_files;
+        /*
+          Update file list.
+        */
+        slider_info.height=
+          scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
+        if (files > visible_files)
+          slider_info.height=(unsigned int)
+            ((visible_files*slider_info.height)/files);
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        expose_info.y=slider_info.y;
+        selection_info.id=(~0);
+        list_info.id=(~0);
+        state|=RedrawListState;
+        /*
+          Redraw directory name & reply.
+        */
+        if (IsGlob(reply_info.text) == MagickFalse)
+          {
+            *reply_info.text='\0';
+            reply_info.cursor=reply_info.text;
+          }
+        (void) CopyMagickString(text_info.text,working_path,MaxTextExtent);
+        (void) ConcatenateMagickString(text_info.text,DirectorySeparator,
+          MaxTextExtent);
+        (void) ConcatenateMagickString(text_info.text,glob_pattern,
+          MaxTextExtent);
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~UpdateListState);
+      }
+    if (state & JumpListState)
+      {
+        /*
+          Jump scroll to match user filename.
+        */
+        list_info.id=(~0);
+        for (i=0; i < (ssize_t) files; i++)
+          if (LocaleCompare(filelist[i],reply) >= 0)
+            {
+              list_info.id=(int)
+                (LocaleCompare(filelist[i],reply) == 0 ? i : ~0);
+              break;
+            }
+        if ((i < (ssize_t) slider_info.id) ||
+            (i >= (ssize_t) (slider_info.id+visible_files)))
+          slider_info.id=(int) i-(visible_files >> 1);
+        selection_info.id=(~0);
+        state|=RedrawListState;
+        state&=(~JumpListState);
+      }
+    if (state & RedrawListState)
+      {
+        /*
+          Determine slider id and position.
+        */
+        if (slider_info.id >= (int) (files-visible_files))
+          slider_info.id=(int) (files-visible_files);
+        if ((slider_info.id < 0) || (files <= visible_files))
+          slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        if (files > 0)
+          slider_info.y+=(int) (slider_info.id*(slider_info.max_y-
+            slider_info.min_y+1)/files);
+        if (slider_info.id != selection_info.id)
+          {
+            /*
+              Redraw scroll bar and file names.
+            */
+            selection_info.id=slider_info.id;
+            selection_info.y=list_info.y+(height >> 3)+2;
+            for (i=0; i < (ssize_t) visible_files; i++)
+            {
+              selection_info.raised=(int) (slider_info.id+i) != list_info.id ?
+                MagickTrue : MagickFalse;
+              selection_info.text=(char *) NULL;
+              if ((slider_info.id+i) < (ssize_t) files)
+                selection_info.text=filelist[slider_info.id+i];
+              XDrawWidgetText(display,&windows->widget,&selection_info);
+              selection_info.y+=(int) selection_info.height;
+            }
+            /*
+              Update slider.
+            */
+            if (slider_info.y > expose_info.y)
+              {
+                expose_info.height=(unsigned int) slider_info.y-expose_info.y;
+                expose_info.y=slider_info.y-expose_info.height-
+                  slider_info.bevel_width-1;
+              }
+            else
+              {
+                expose_info.height=(unsigned int) expose_info.y-slider_info.y;
+                expose_info.y=slider_info.y+slider_info.height+
+                  slider_info.bevel_width+1;
+              }
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+            XDrawMatte(display,&windows->widget,&expose_info);
+            XDrawBeveledButton(display,&windows->widget,&slider_info);
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+            expose_info.y=slider_info.y;
+          }
+        state&=(~RedrawListState);
+      }
+    /*
+      Wait for next event.
+    */
+    if (north_info.raised && south_info.raised)
+      (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    else
+      {
+        /*
+          Brief delay before advancing scroll bar.
+        */
+        XDelay(display,delay);
+        delay=SuspendTime;
+        (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
+        if (north_info.raised == MagickFalse)
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              slider_info.id--;
+              state|=RedrawListState;
+            }
+        if (south_info.raised == MagickFalse)
+          if (slider_info.id < (int) files)
+            {
+              /*
+                Move slider down.
+              */
+              slider_info.id++;
+              state|=RedrawListState;
+            }
+        if (event.type != ButtonRelease)
+          continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(slider_info,event.xbutton))
+          {
+            /*
+              Track slider.
+            */
+            slider_info.active=MagickTrue;
+            break;
+          }
+        if (MatteIsActive(north_info,event.xbutton))
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              north_info.raised=MagickFalse;
+              slider_info.id--;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(south_info,event.xbutton))
+          if (slider_info.id < (int) files)
+            {
+              /*
+                Move slider down.
+              */
+              south_info.raised=MagickFalse;
+              slider_info.id++;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(scroll_info,event.xbutton))
+          {
+            /*
+              Move slider.
+            */
+            if (event.xbutton.y < slider_info.y)
+              slider_info.id-=(visible_files-1);
+            else
+              slider_info.id+=(visible_files-1);
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(list_info,event.xbutton))
+          {
+            int
+              id;
+
+            /*
+              User pressed file matte.
+            */
+            id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
+              selection_info.height;
+            if (id >= (int) files)
+              break;
+            (void) CopyMagickString(reply_info.text,filelist[id],MaxTextExtent);
+            reply_info.highlight=MagickFalse;
+            reply_info.marker=reply_info.text;
+            reply_info.cursor=reply_info.text+Extent(reply_info.text);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            if (id == list_info.id)
+              {
+                register char
+                  *p;
+
+                p=reply_info.text+strlen(reply_info.text)-1;
+                if (*p == *DirectorySeparator)
+                  ChopPathComponents(reply_info.text,1);
+                (void) ConcatenateMagickString(working_path,DirectorySeparator,
+                  MaxTextExtent);
+                (void) ConcatenateMagickString(working_path,reply_info.text,
+                  MaxTextExtent);
+                *reply='\0';
+                state|=UpdateListState;
+              }
+            selection_info.id=(~0);
+            list_info.id=id;
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(up_info,event.xbutton))
+          {
+            /*
+              User pressed Up button.
+            */
+            up_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&up_info);
+            break;
+          }
+        if (MatteIsActive(home_info,event.xbutton))
+          {
+            /*
+              User pressed Home button.
+            */
+            home_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&home_info);
+            break;
+          }
+        if (MatteIsActive(special_info,event.xbutton))
+          {
+            /*
+              User pressed Special button.
+            */
+            special_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&special_info);
+            break;
+          }
+        if (MatteIsActive(action_info,event.xbutton))
+          {
+            /*
+              User pressed action button.
+            */
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed Cancel button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        if (event.xbutton.button != Button2)
+          {
+            static Time
+              click_time;
+
+            /*
+              Move text cursor to position of button press.
+            */
+            x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
+            for (i=1; i <= (ssize_t) Extent(reply_info.marker); i++)
+              if (XTextWidth(font_info,reply_info.marker,(int) i) > x)
+                break;
+            reply_info.cursor=reply_info.marker+i-1;
+            if (event.xbutton.time > (click_time+DoubleClick))
+              reply_info.highlight=MagickFalse;
+            else
+              {
+                /*
+                  Become the XA_PRIMARY selection owner.
+                */
+                (void) CopyMagickString(primary_selection,reply_info.text,
+                  MaxTextExtent);
+                (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
+                  event.xbutton.time);
+                reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
+                  windows->widget.id ? MagickTrue : MagickFalse;
+              }
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            click_time=event.xbutton.time;
+            break;
+          }
+        /*
+          Request primary selection.
+        */
+        (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
+          windows->widget.id,event.xbutton.time);
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (north_info.raised == MagickFalse)
+          {
+            /*
+              User released up button.
+            */
+            delay=SuspendTime << 2;
+            north_info.raised=MagickTrue;
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+          }
+        if (south_info.raised == MagickFalse)
+          {
+            /*
+              User released down button.
+            */
+            delay=SuspendTime << 2;
+            south_info.raised=MagickTrue;
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+          }
+        if (slider_info.active)
+          {
+            /*
+              Stop tracking slider.
+            */
+            slider_info.active=MagickFalse;
+            break;
+          }
+        if (up_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(up_info,event.xbutton))
+                {
+                  ChopPathComponents(working_path,1);
+                  if (*working_path == '\0')
+                    (void) CopyMagickString(working_path,DirectorySeparator,
+                      MaxTextExtent);
+                  state|=UpdateListState;
+                }
+            up_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&up_info);
+          }
+        if (home_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(home_info,event.xbutton))
+                {
+                  (void) CopyMagickString(working_path,home_directory,
+                    MaxTextExtent);
+                  state|=UpdateListState;
+                }
+            home_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&home_info);
+          }
+        if (special_info.raised == MagickFalse)
+          {
+            if (anomaly == MagickFalse)
+              {
+                char
+                  **formats;
+
+                ExceptionInfo
+                  *exception;
+
+                size_t
+                  number_formats;
+
+                /*
+                  Let user select image format.
+                */
+                exception=AcquireExceptionInfo();
+                formats=GetMagickList("*",&number_formats,exception);
+                exception=DestroyExceptionInfo(exception);
+                (void) XCheckDefineCursor(display,windows->widget.id,
+                  windows->widget.busy_cursor);
+                windows->popup.x=windows->widget.x+60;
+                windows->popup.y=windows->widget.y+60;
+                XListBrowserWidget(display,windows,&windows->popup,
+                  (const char **) formats,"Select","Select image format type:",
+                  format);
+                XSetCursorState(display,windows,MagickTrue);
+                (void) XCheckDefineCursor(display,windows->widget.id,
+                  windows->widget.cursor);
+                LocaleLower(format);
+                AppendImageFormat(format,reply_info.text);
+                reply_info.cursor=reply_info.text+Extent(reply_info.text);
+                XDrawMatteText(display,&windows->widget,&reply_info);
+                special_info.raised=MagickTrue;
+                XDrawBeveledButton(display,&windows->widget,&special_info);
+                for (i=0; i < (ssize_t) number_formats; i++)
+                  formats[i]=DestroyString(formats[i]);
+                formats=(char **) RelinquishMagickMemory(formats);
+                break;
+              }
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(special_info,event.xbutton))
+                {
+                  (void) CopyMagickString(working_path,"x:",MaxTextExtent);
+                  state|=ExitState;
+                }
+            special_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&special_info);
+          }
+        if (action_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              {
+                if (MatteIsActive(action_info,event.xbutton))
+                  {
+                    if (*reply_info.text == '\0')
+                      (void) XBell(display,0);
+                    else
+                      state|=ExitState;
+                  }
+              }
+            action_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+          }
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                {
+                  *reply_info.text='\0';
+                  *reply='\0';
+                  state|=ExitState;
+                }
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            *reply_info.text='\0';
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static int
+          length;
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        length=XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (AreaIsActive(scroll_info,event.xkey))
+          {
+            /*
+              Move slider.
+            */
+            switch ((int) key_symbol)
+            {
+              case XK_Home:
+              case XK_KP_Home:
+              {
+                slider_info.id=0;
+                break;
+              }
+              case XK_Up:
+              case XK_KP_Up:
+              {
+                slider_info.id--;
+                break;
+              }
+              case XK_Down:
+              case XK_KP_Down:
+              {
+                slider_info.id++;
+                break;
+              }
+              case XK_Prior:
+              case XK_KP_Prior:
+              {
+                slider_info.id-=visible_files;
+                break;
+              }
+              case XK_Next:
+              case XK_KP_Next:
+              {
+                slider_info.id+=visible_files;
+                break;
+              }
+              case XK_End:
+              case XK_KP_End:
+              {
+                slider_info.id=(int) files;
+                break;
+              }
+            }
+            state|=RedrawListState;
+            break;
+          }
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            /*
+              Read new directory or glob patterm.
+            */
+            if (*reply_info.text == '\0')
+              break;
+            if (IsGlob(reply_info.text))
+              (void) CopyMagickString(glob_pattern,reply_info.text,
+                MaxTextExtent);
+            else
+              {
+                (void) ConcatenateMagickString(working_path,DirectorySeparator,
+                  MaxTextExtent);
+                (void) ConcatenateMagickString(working_path,reply_info.text,
+                  MaxTextExtent);
+                if (*working_path == '~')
+                  ExpandFilename(working_path);
+                *reply='\0';
+              }
+            state|=UpdateListState;
+            break;
+          }
+        if (key_symbol == XK_Control_L)
+          {
+            state|=ControlState;
+            break;
+          }
+        if (state & ControlState)
+          switch ((int) key_symbol)
+          {
+            case XK_u:
+            case XK_U:
+            {
+              /*
+                Erase the entire line of text.
+              */
+              *reply_info.text='\0';
+              reply_info.cursor=reply_info.text;
+              reply_info.marker=reply_info.text;
+              reply_info.highlight=MagickFalse;
+              break;
+            }
+            default:
+              break;
+          }
+        XEditText(display,&reply_info,key_symbol,command,state);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        state|=JumpListState;
+        break;
+      }
+      case KeyRelease:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key release.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (key_symbol == XK_Control_L)
+          state&=(~ControlState);
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MapNotify:
+      {
+        mask&=(~CWX);
+        mask&=(~CWY);
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (slider_info.active)
+          {
+            /*
+              Move slider matte.
+            */
+            slider_info.y=event.xmotion.y-
+              ((slider_info.height+slider_info.bevel_width) >> 1)+1;
+            if (slider_info.y < slider_info.min_y)
+              slider_info.y=slider_info.min_y;
+            if (slider_info.y > slider_info.max_y)
+              slider_info.y=slider_info.max_y;
+            slider_info.id=0;
+            if (slider_info.y != slider_info.min_y)
+              slider_info.id=(int) ((files*(slider_info.y-slider_info.min_y+1))/
+                (slider_info.max_y-slider_info.min_y+1));
+            state|=RedrawListState;
+            break;
+          }
+        if (state & InactiveWidgetState)
+          break;
+        if (up_info.raised == MatteIsActive(up_info,event.xmotion))
+          {
+            /*
+              Up button status changed.
+            */
+            up_info.raised=!up_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&up_info);
+            break;
+          }
+        if (home_info.raised == MatteIsActive(home_info,event.xmotion))
+          {
+            /*
+              Home button status changed.
+            */
+            home_info.raised=!home_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&home_info);
+            break;
+          }
+        if (special_info.raised == MatteIsActive(special_info,event.xmotion))
+          {
+            /*
+              Grab button status changed.
+            */
+            special_info.raised=!special_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&special_info);
+            break;
+          }
+        if (action_info.raised == MatteIsActive(action_info,event.xmotion))
+          {
+            /*
+              Action button status changed.
+            */
+            action_info.raised=action_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        break;
+      }
+      case SelectionClear:
+      {
+        reply_info.highlight=MagickFalse;
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        break;
+      }
+      case SelectionNotify:
+      {
+        Atom
+          type;
+
+        int
+          format;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        /*
+          Obtain response from primary selection.
+        */
+        if (event.xselection.property == (Atom) None)
+          break;
+        status=XGetWindowProperty(display,event.xselection.requestor,
+          event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
+          &format,&length,&after,&data);
+        if ((status != Success) || (type != XA_STRING) || (format == 32) ||
+            (length == 0))
+          break;
+        if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
+          (void) XBell(display,0);
+        else
+          {
+            /*
+              Insert primary selection in reply text.
+            */
+            *(data+length)='\0';
+            XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
+              state);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            state|=JumpListState;
+            state|=RedrawActionState;
+          }
+        (void) XFree((void *) data);
+        break;
+      }
+      case SelectionRequest:
+      {
+        XSelectionEvent
+          notify;
+
+        XSelectionRequestEvent
+          *request;
+
+        if (reply_info.highlight == MagickFalse)
+          break;
+        /*
+          Set primary selection.
+        */
+        request=(&(event.xselectionrequest));
+        (void) XChangeProperty(request->display,request->requestor,
+          request->property,request->target,8,PropModeReplace,
+          (unsigned char *) primary_selection,Extent(primary_selection));
+        notify.type=SelectionNotify;
+        notify.display=request->display;
+        notify.requestor=request->requestor;
+        notify.selection=request->selection;
+        notify.target=request->target;
+        notify.time=request->time;
+        if (request->property == None)
+          notify.property=request->target;
+        else
+          notify.property=request->property;
+        (void) XSendEvent(request->display,request->requestor,False,0,
+          (XEvent *) &notify);
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  /*
+    Free file list.
+  */
+  for (i=0; i < (ssize_t) files; i++)
+    filelist[i]=DestroyString(filelist[i]);
+  if (filelist != (char **) NULL)
+    filelist=(char **) RelinquishMagickMemory(filelist);
+  if (*reply != '\0')
+    {
+      (void) ConcatenateMagickString(working_path,DirectorySeparator,
+        MaxTextExtent);
+      (void) ConcatenateMagickString(working_path,reply,MaxTextExtent);
+    }
+  (void) CopyMagickString(reply,working_path,MaxTextExtent);
+  if (*reply == '~')
+    ExpandFilename(reply);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X F o n t B r o w s e r W i d g e t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XFontBrowserWidget() displays a Font Browser widget with a font query to the
+%  user.  The user keys a reply and presses the Action or Cancel button to
+%  exit.  The typed text is returned as the reply function parameter.
+%
+%  The format of the XFontBrowserWidget method is:
+%
+%      void XFontBrowserWidget(Display *display,XWindows *windows,
+%        const char *action,char *reply)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o action: Specifies a pointer to the action of this widget.
+%
+%    o reply: the response from the user is returned in this parameter.
+%
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static int FontCompare(const void *x,const void *y)
+{
+  register char
+    *p,
+    *q;
+
+  p=(char *) *((char **) x);
+  q=(char *) *((char **) y);
+  while ((*p != '\0') && (*q != '\0') && (*p == *q))
+  {
+    p++;
+    q++;
+  }
+  return(*p-(*q));
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+MagickExport void XFontBrowserWidget(Display *display,XWindows *windows,
+  const char *action,char *reply)
+{
+#define BackButtonText  "Back"
+#define CancelButtonText  "Cancel"
+#define FontnameText  "Name:"
+#define FontPatternText  "Pattern:"
+#define ResetButtonText  "Reset"
+
+  char
+    back_pattern[MaxTextExtent],
+    **fontlist,
+    **listhead,
+    primary_selection[MaxTextExtent],
+    reset_pattern[MaxTextExtent],
+    text[MaxTextExtent];
+
+  int
+    fonts,
+    x,
+    y;
+
+  register int
+    i;
+
+  static char
+    glob_pattern[MaxTextExtent] = "*";
+
+  static MagickStatusType
+    mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
+
+  Status
+    status;
+
+  unsigned int
+    height,
+    text_width,
+    visible_fonts,
+    width;
+
+  size_t
+    delay,
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    action_info,
+    back_info,
+    cancel_info,
+    expose_info,
+    list_info,
+    mode_info,
+    north_info,
+    reply_info,
+    reset_info,
+    scroll_info,
+    selection_info,
+    slider_info,
+    south_info,
+    text_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Get font list and sort in ascending order.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(action != (char *) NULL);
+  assert(reply != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
+  (void) CopyMagickString(reset_pattern,"*",MaxTextExtent);
+  fontlist=XListFonts(display,glob_pattern,32767,&fonts);
+  if (fonts == 0)
+    {
+      /*
+        Pattern failed, obtain all the fonts.
+      */
+      XNoticeWidget(display,windows,"Unable to obtain fonts names:",
+        glob_pattern);
+      (void) CopyMagickString(glob_pattern,"*",MaxTextExtent);
+      fontlist=XListFonts(display,glob_pattern,32767,&fonts);
+      if (fontlist == (char **) NULL)
+        {
+          XNoticeWidget(display,windows,"Unable to obtain fonts names:",
+            glob_pattern);
+          return;
+        }
+    }
+  /*
+    Sort font list in ascending order.
+  */
+  listhead=fontlist;
+  fontlist=(char **) AcquireQuantumMemory((size_t) fonts,sizeof(*fontlist));
+  if (fontlist == (char **) NULL)
+    {
+      XNoticeWidget(display,windows,"MemoryAllocationFailed",
+        "UnableToViewFonts");
+      return;
+    }
+  for (i=0; i < fonts; i++)
+    fontlist[i]=listhead[i];
+  qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
+  /*
+    Determine Font Browser widget attributes.
+  */
+  font_info=windows->widget.font_info;
+  text_width=0;
+  for (i=0; i < fonts; i++)
+    if (WidgetTextWidth(font_info,fontlist[i]) > text_width)
+      text_width=WidgetTextWidth(font_info,fontlist[i]);
+  width=WidgetTextWidth(font_info,(char *) action);
+  if (WidgetTextWidth(font_info,CancelButtonText) > width)
+    width=WidgetTextWidth(font_info,CancelButtonText);
+  if (WidgetTextWidth(font_info,ResetButtonText) > width)
+    width=WidgetTextWidth(font_info,ResetButtonText);
+  if (WidgetTextWidth(font_info,BackButtonText) > width)
+    width=WidgetTextWidth(font_info,BackButtonText);
+  width+=QuantumMargin;
+  if (WidgetTextWidth(font_info,FontPatternText) > width)
+    width=WidgetTextWidth(font_info,FontPatternText);
+  if (WidgetTextWidth(font_info,FontnameText) > width)
+    width=WidgetTextWidth(font_info,FontnameText);
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position Font Browser widget.
+  */
+  windows->widget.width=width+MagickMin((int) text_width,(int) MaxTextWidth)+
+    6*QuantumMargin;
+  windows->widget.min_width=width+MinTextWidth+4*QuantumMargin;
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int)
+    (((85*height) >> 2)+((13*QuantumMargin) >> 1)+4);
+  windows->widget.min_height=(unsigned int)
+    (((27*height) >> 1)+((13*QuantumMargin) >> 1)+4);
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Font Browser widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Browse and Select a Font",
+    MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,
+    windows->widget.screen,mask,&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  XGetWidgetInfo((char *) NULL,&slider_info);
+  XGetWidgetInfo((char *) NULL,&north_info);
+  XGetWidgetInfo((char *) NULL,&south_info);
+  XGetWidgetInfo((char *) NULL,&expose_info);
+  visible_fonts=0;
+  delay=SuspendTime << 2;
+  state=UpdateConfigurationState;
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        int
+          id;
+
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=width;
+        cancel_info.height=(unsigned int) ((3*height) >> 1);
+        cancel_info.x=(int)
+          (windows->widget.width-cancel_info.width-QuantumMargin-2);
+        cancel_info.y=(int)
+          (windows->widget.height-cancel_info.height-QuantumMargin);
+        XGetWidgetInfo(action,&action_info);
+        action_info.width=width;
+        action_info.height=(unsigned int) ((3*height) >> 1);
+        action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
+          (action_info.bevel_width << 1));
+        action_info.y=cancel_info.y;
+        XGetWidgetInfo(BackButtonText,&back_info);
+        back_info.width=width;
+        back_info.height=(unsigned int) ((3*height) >> 1);
+        back_info.x=QuantumMargin;
+        back_info.y=((5*QuantumMargin) >> 1)+height;
+        XGetWidgetInfo(ResetButtonText,&reset_info);
+        reset_info.width=width;
+        reset_info.height=(unsigned int) ((3*height) >> 1);
+        reset_info.x=QuantumMargin;
+        reset_info.y=back_info.y+back_info.height+QuantumMargin;
+        /*
+          Initialize reply information.
+        */
+        XGetWidgetInfo(reply,&reply_info);
+        reply_info.raised=MagickFalse;
+        reply_info.bevel_width--;
+        reply_info.width=windows->widget.width-width-((6*QuantumMargin) >> 1);
+        reply_info.height=height << 1;
+        reply_info.x=(int) (width+(QuantumMargin << 1));
+        reply_info.y=action_info.y-(action_info.height << 1)-QuantumMargin;
+        /*
+          Initialize mode information.
+        */
+        XGetWidgetInfo(reply,&mode_info);
+        mode_info.bevel_width=0;
+        mode_info.width=(unsigned int)
+          (action_info.x-reply_info.x-QuantumMargin);
+        mode_info.height=action_info.height << 1;
+        mode_info.x=reply_info.x;
+        mode_info.y=action_info.y-action_info.height+action_info.bevel_width;
+        /*
+          Initialize scroll information.
+        */
+        XGetWidgetInfo((char *) NULL,&scroll_info);
+        scroll_info.bevel_width--;
+        scroll_info.width=height;
+        scroll_info.height=(unsigned int)
+          (reply_info.y-back_info.y-(QuantumMargin >> 1));
+        scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
+        scroll_info.y=back_info.y-reply_info.bevel_width;
+        scroll_info.raised=MagickFalse;
+        scroll_info.trough=MagickTrue;
+        north_info=scroll_info;
+        north_info.raised=MagickTrue;
+        north_info.width-=(north_info.bevel_width << 1);
+        north_info.height=north_info.width-1;
+        north_info.x+=north_info.bevel_width;
+        north_info.y+=north_info.bevel_width;
+        south_info=north_info;
+        south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
+          south_info.height;
+        id=slider_info.id;
+        slider_info=north_info;
+        slider_info.id=id;
+        slider_info.width-=2;
+        slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
+          slider_info.bevel_width+2;
+        slider_info.height=scroll_info.height-((slider_info.min_y-
+          scroll_info.y+1) << 1)+4;
+        visible_fonts=scroll_info.height/(height+(height >> 3));
+        if (fonts > (int) visible_fonts)
+          slider_info.height=(visible_fonts*slider_info.height)/fonts;
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.x=scroll_info.x+slider_info.bevel_width+1;
+        slider_info.y=slider_info.min_y;
+        expose_info=scroll_info;
+        expose_info.y=slider_info.y;
+        /*
+          Initialize list information.
+        */
+        XGetWidgetInfo((char *) NULL,&list_info);
+        list_info.raised=MagickFalse;
+        list_info.bevel_width--;
+        list_info.width=(unsigned int)
+          (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
+        list_info.height=scroll_info.height;
+        list_info.x=reply_info.x;
+        list_info.y=scroll_info.y;
+        if (windows->widget.mapped == MagickFalse)
+          state|=JumpListState;
+        /*
+          Initialize text information.
+        */
+        *text='\0';
+        XGetWidgetInfo(text,&text_info);
+        text_info.center=MagickFalse;
+        text_info.width=reply_info.width;
+        text_info.height=height;
+        text_info.x=list_info.x-(QuantumMargin >> 1);
+        text_info.y=QuantumMargin;
+        /*
+          Initialize selection information.
+        */
+        XGetWidgetInfo((char *) NULL,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.width=list_info.width;
+        selection_info.height=(unsigned int) ((9*height) >> 3);
+        selection_info.x=list_info.x;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Font Browser window.
+        */
+        x=QuantumMargin;
+        y=text_info.y+((text_info.height-height) >> 1)+font_info->ascent;
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,FontPatternText,
+          Extent(FontPatternText));
+        (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawBeveledButton(display,&windows->widget,&back_info);
+        XDrawBeveledButton(display,&windows->widget,&reset_info);
+        XDrawBeveledMatte(display,&windows->widget,&list_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        x=QuantumMargin;
+        y=reply_info.y+((reply_info.height-height) >> 1)+font_info->ascent;
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,FontnameText,
+          Extent(FontnameText));
+        XDrawBeveledMatte(display,&windows->widget,&reply_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        XDrawBeveledButton(display,&windows->widget,&action_info);
+        XDrawBeveledButton(display,&windows->widget,&cancel_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        selection_info.id=(~0);
+        state|=RedrawActionState;
+        state|=RedrawListState;
+        state&=(~RedrawWidgetState);
+      }
+    if (state & UpdateListState)
+      {
+        char
+          **checklist;
+
+        int
+          number_fonts;
+
+        /*
+          Update font list.
+        */
+        checklist=XListFonts(display,glob_pattern,32767,&number_fonts);
+        if (checklist == (char **) NULL)
+          {
+            if ((strchr(glob_pattern,'*') == (char *) NULL) &&
+                (strchr(glob_pattern,'?') == (char *) NULL))
+              {
+                /*
+                  Might be a scaleable font-- exit.
+                */
+                (void) CopyMagickString(reply,glob_pattern,MaxTextExtent);
+                (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
+                action_info.raised=MagickFalse;
+                XDrawBeveledButton(display,&windows->widget,&action_info);
+                break;
+              }
+            (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
+            (void) XBell(display,0);
+          }
+        else
+          if (number_fonts == 1)
+            {
+              /*
+                Reply is a single font name-- exit.
+              */
+              (void) CopyMagickString(reply,checklist[0],MaxTextExtent);
+              (void) CopyMagickString(glob_pattern,back_pattern,MaxTextExtent);
+              (void) XFreeFontNames(checklist);
+              action_info.raised=MagickFalse;
+              XDrawBeveledButton(display,&windows->widget,&action_info);
+              break;
+            }
+          else
+            {
+              (void) XFreeFontNames(listhead);
+              fontlist=(char **) RelinquishMagickMemory(fontlist);
+              fontlist=checklist;
+              fonts=number_fonts;
+            }
+        /*
+          Sort font list in ascending order.
+        */
+        listhead=fontlist;
+        fontlist=(char **) AcquireQuantumMemory((size_t) fonts,
+          sizeof(*fontlist));
+        if (fontlist == (char **) NULL)
+          {
+            XNoticeWidget(display,windows,"MemoryAllocationFailed",
+              "UnableToViewFonts");
+            return;
+          }
+        for (i=0; i < fonts; i++)
+          fontlist[i]=listhead[i];
+        qsort((void *) fontlist,(size_t) fonts,sizeof(*fontlist),FontCompare);
+        slider_info.height=
+          scroll_info.height-((slider_info.min_y-scroll_info.y+1) << 1)+1;
+        if (fonts > (int) visible_fonts)
+          slider_info.height=(visible_fonts*slider_info.height)/fonts;
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        expose_info.y=slider_info.y;
+        selection_info.id=(~0);
+        list_info.id=(~0);
+        state|=RedrawListState;
+        /*
+          Redraw font name & reply.
+        */
+        *reply_info.text='\0';
+        reply_info.cursor=reply_info.text;
+        (void) CopyMagickString(text_info.text,glob_pattern,MaxTextExtent);
+        XDrawWidgetText(display,&windows->widget,&text_info);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~UpdateListState);
+      }
+    if (state & JumpListState)
+      {
+        /*
+          Jump scroll to match user font.
+        */
+        list_info.id=(~0);
+        for (i=0; i < fonts; i++)
+          if (LocaleCompare(fontlist[i],reply) >= 0)
+            {
+              list_info.id=LocaleCompare(fontlist[i],reply) == 0 ? i : ~0;
+              break;
+            }
+        if ((i < slider_info.id) || (i >= (int) (slider_info.id+visible_fonts)))
+          slider_info.id=i-(visible_fonts >> 1);
+        selection_info.id=(~0);
+        state|=RedrawListState;
+        state&=(~JumpListState);
+      }
+    if (state & RedrawListState)
+      {
+        /*
+          Determine slider id and position.
+        */
+        if (slider_info.id >= (int) (fonts-visible_fonts))
+          slider_info.id=fonts-visible_fonts;
+        if ((slider_info.id < 0) || (fonts <= (int) visible_fonts))
+          slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        if (fonts > 0)
+          slider_info.y+=
+            slider_info.id*(slider_info.max_y-slider_info.min_y+1)/fonts;
+        if (slider_info.id != selection_info.id)
+          {
+            /*
+              Redraw scroll bar and file names.
+            */
+            selection_info.id=slider_info.id;
+            selection_info.y=list_info.y+(height >> 3)+2;
+            for (i=0; i < (int) visible_fonts; i++)
+            {
+              selection_info.raised=(slider_info.id+i) != list_info.id ?
+                MagickTrue : MagickFalse;
+              selection_info.text=(char *) NULL;
+              if ((slider_info.id+i) < fonts)
+                selection_info.text=fontlist[slider_info.id+i];
+              XDrawWidgetText(display,&windows->widget,&selection_info);
+              selection_info.y+=(int) selection_info.height;
+            }
+            /*
+              Update slider.
+            */
+            if (slider_info.y > expose_info.y)
+              {
+                expose_info.height=(unsigned int) slider_info.y-expose_info.y;
+                expose_info.y=slider_info.y-expose_info.height-
+                  slider_info.bevel_width-1;
+              }
+            else
+              {
+                expose_info.height=(unsigned int) expose_info.y-slider_info.y;
+                expose_info.y=slider_info.y+slider_info.height+
+                  slider_info.bevel_width+1;
+              }
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+            XDrawMatte(display,&windows->widget,&expose_info);
+            XDrawBeveledButton(display,&windows->widget,&slider_info);
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+            expose_info.y=slider_info.y;
+          }
+        state&=(~RedrawListState);
+      }
+    if (state & RedrawActionState)
+      {
+        XFontStruct
+          *save_info;
+
+        /*
+          Display the selected font in a drawing area.
+        */
+        save_info=windows->widget.font_info;
+        font_info=XLoadQueryFont(display,reply_info.text);
+        if (font_info != (XFontStruct *) NULL)
+          {
+            windows->widget.font_info=font_info;
+            (void) XSetFont(display,windows->widget.widget_context,
+              font_info->fid);
+          }
+        XDrawBeveledButton(display,&windows->widget,&mode_info);
+        windows->widget.font_info=save_info;
+        if (font_info != (XFontStruct *) NULL)
+          {
+            (void) XSetFont(display,windows->widget.widget_context,
+              windows->widget.font_info->fid);
+            (void) XFreeFont(display,font_info);
+          }
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        state&=(~RedrawActionState);
+      }
+    /*
+      Wait for next event.
+    */
+    if (north_info.raised && south_info.raised)
+      (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    else
+      {
+        /*
+          Brief delay before advancing scroll bar.
+        */
+        XDelay(display,delay);
+        delay=SuspendTime;
+        (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
+        if (north_info.raised == MagickFalse)
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              slider_info.id--;
+              state|=RedrawListState;
+            }
+        if (south_info.raised == MagickFalse)
+          if (slider_info.id < fonts)
+            {
+              /*
+                Move slider down.
+              */
+              slider_info.id++;
+              state|=RedrawListState;
+            }
+        if (event.type != ButtonRelease)
+          continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(slider_info,event.xbutton))
+          {
+            /*
+              Track slider.
+            */
+            slider_info.active=MagickTrue;
+            break;
+          }
+        if (MatteIsActive(north_info,event.xbutton))
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              north_info.raised=MagickFalse;
+              slider_info.id--;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(south_info,event.xbutton))
+          if (slider_info.id < fonts)
+            {
+              /*
+                Move slider down.
+              */
+              south_info.raised=MagickFalse;
+              slider_info.id++;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(scroll_info,event.xbutton))
+          {
+            /*
+              Move slider.
+            */
+            if (event.xbutton.y < slider_info.y)
+              slider_info.id-=(visible_fonts-1);
+            else
+              slider_info.id+=(visible_fonts-1);
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(list_info,event.xbutton))
+          {
+            int
+              id;
+
+            /*
+              User pressed list matte.
+            */
+            id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
+              selection_info.height;
+            if (id >= (int) fonts)
+              break;
+            (void) CopyMagickString(reply_info.text,fontlist[id],MaxTextExtent);
+            reply_info.highlight=MagickFalse;
+            reply_info.marker=reply_info.text;
+            reply_info.cursor=reply_info.text+Extent(reply_info.text);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            state|=RedrawActionState;
+            if (id == list_info.id)
+              {
+                (void) CopyMagickString(glob_pattern,reply_info.text,
+                  MaxTextExtent);
+                state|=UpdateListState;
+              }
+            selection_info.id=(~0);
+            list_info.id=id;
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(back_info,event.xbutton))
+          {
+            /*
+              User pressed Back button.
+            */
+            back_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&back_info);
+            break;
+          }
+        if (MatteIsActive(reset_info,event.xbutton))
+          {
+            /*
+              User pressed Reset button.
+            */
+            reset_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&reset_info);
+            break;
+          }
+        if (MatteIsActive(action_info,event.xbutton))
+          {
+            /*
+              User pressed action button.
+            */
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed Cancel button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        if (event.xbutton.button != Button2)
+          {
+            static Time
+              click_time;
+
+            /*
+              Move text cursor to position of button press.
+            */
+            x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
+            for (i=1; i <= Extent(reply_info.marker); i++)
+              if (XTextWidth(font_info,reply_info.marker,i) > x)
+                break;
+            reply_info.cursor=reply_info.marker+i-1;
+            if (event.xbutton.time > (click_time+DoubleClick))
+              reply_info.highlight=MagickFalse;
+            else
+              {
+                /*
+                  Become the XA_PRIMARY selection owner.
+                */
+                (void) CopyMagickString(primary_selection,reply_info.text,
+                  MaxTextExtent);
+                (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
+                  event.xbutton.time);
+                reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
+                  windows->widget.id ? MagickTrue : MagickFalse;
+              }
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            click_time=event.xbutton.time;
+            break;
+          }
+        /*
+          Request primary selection.
+        */
+        (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
+          windows->widget.id,event.xbutton.time);
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (north_info.raised == MagickFalse)
+          {
+            /*
+              User released up button.
+            */
+            delay=SuspendTime << 2;
+            north_info.raised=MagickTrue;
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+          }
+        if (south_info.raised == MagickFalse)
+          {
+            /*
+              User released down button.
+            */
+            delay=SuspendTime << 2;
+            south_info.raised=MagickTrue;
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+          }
+        if (slider_info.active)
+          {
+            /*
+              Stop tracking slider.
+            */
+            slider_info.active=MagickFalse;
+            break;
+          }
+        if (back_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(back_info,event.xbutton))
+                {
+                  (void) CopyMagickString(glob_pattern,back_pattern,
+                    MaxTextExtent);
+                  state|=UpdateListState;
+                }
+            back_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&back_info);
+          }
+        if (reset_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(reset_info,event.xbutton))
+                {
+                  (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
+                  (void) CopyMagickString(glob_pattern,reset_pattern,MaxTextExtent);
+                  state|=UpdateListState;
+                }
+            reset_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&reset_info);
+          }
+        if (action_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              {
+                if (MatteIsActive(action_info,event.xbutton))
+                  {
+                    if (*reply_info.text == '\0')
+                      (void) XBell(display,0);
+                    else
+                      state|=ExitState;
+                  }
+              }
+            action_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+          }
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                {
+                  *reply_info.text='\0';
+                  state|=ExitState;
+                }
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            *reply_info.text='\0';
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static int
+          length;
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        length=XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (AreaIsActive(scroll_info,event.xkey))
+          {
+            /*
+              Move slider.
+            */
+            switch ((int) key_symbol)
+            {
+              case XK_Home:
+              case XK_KP_Home:
+              {
+                slider_info.id=0;
+                break;
+              }
+              case XK_Up:
+              case XK_KP_Up:
+              {
+                slider_info.id--;
+                break;
+              }
+              case XK_Down:
+              case XK_KP_Down:
+              {
+                slider_info.id++;
+                break;
+              }
+              case XK_Prior:
+              case XK_KP_Prior:
+              {
+                slider_info.id-=visible_fonts;
+                break;
+              }
+              case XK_Next:
+              case XK_KP_Next:
+              {
+                slider_info.id+=visible_fonts;
+                break;
+              }
+              case XK_End:
+              case XK_KP_End:
+              {
+                slider_info.id=fonts;
+                break;
+              }
+            }
+            state|=RedrawListState;
+            break;
+          }
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            /*
+              Read new font or glob patterm.
+            */
+            if (*reply_info.text == '\0')
+              break;
+            (void) CopyMagickString(back_pattern,glob_pattern,MaxTextExtent);
+            (void) CopyMagickString(glob_pattern,reply_info.text,MaxTextExtent);
+            state|=UpdateListState;
+            break;
+          }
+        if (key_symbol == XK_Control_L)
+          {
+            state|=ControlState;
+            break;
+          }
+        if (state & ControlState)
+          switch ((int) key_symbol)
+          {
+            case XK_u:
+            case XK_U:
+            {
+              /*
+                Erase the entire line of text.
+              */
+              *reply_info.text='\0';
+              reply_info.cursor=reply_info.text;
+              reply_info.marker=reply_info.text;
+              reply_info.highlight=MagickFalse;
+              break;
+            }
+            default:
+              break;
+          }
+        XEditText(display,&reply_info,key_symbol,command,state);
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        state|=JumpListState;
+        break;
+      }
+      case KeyRelease:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key release.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (key_symbol == XK_Control_L)
+          state&=(~ControlState);
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MapNotify:
+      {
+        mask&=(~CWX);
+        mask&=(~CWY);
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (slider_info.active)
+          {
+            /*
+              Move slider matte.
+            */
+            slider_info.y=event.xmotion.y-
+              ((slider_info.height+slider_info.bevel_width) >> 1)+1;
+            if (slider_info.y < slider_info.min_y)
+              slider_info.y=slider_info.min_y;
+            if (slider_info.y > slider_info.max_y)
+              slider_info.y=slider_info.max_y;
+            slider_info.id=0;
+            if (slider_info.y != slider_info.min_y)
+              slider_info.id=(fonts*(slider_info.y-slider_info.min_y+1))/
+                (slider_info.max_y-slider_info.min_y+1);
+            state|=RedrawListState;
+            break;
+          }
+        if (state & InactiveWidgetState)
+          break;
+        if (back_info.raised == MatteIsActive(back_info,event.xmotion))
+          {
+            /*
+              Back button status changed.
+            */
+            back_info.raised=!back_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&back_info);
+            break;
+          }
+        if (reset_info.raised == MatteIsActive(reset_info,event.xmotion))
+          {
+            /*
+              Reset button status changed.
+            */
+            reset_info.raised=!reset_info.raised;
+            XDrawBeveledButton(display,&windows->widget,&reset_info);
+            break;
+          }
+        if (action_info.raised == MatteIsActive(action_info,event.xmotion))
+          {
+            /*
+              Action button status changed.
+            */
+            action_info.raised=action_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&action_info);
+            break;
+          }
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        break;
+      }
+      case SelectionClear:
+      {
+        reply_info.highlight=MagickFalse;
+        XDrawMatteText(display,&windows->widget,&reply_info);
+        break;
+      }
+      case SelectionNotify:
+      {
+        Atom
+          type;
+
+        int
+          format;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        /*
+          Obtain response from primary selection.
+        */
+        if (event.xselection.property == (Atom) None)
+          break;
+        status=XGetWindowProperty(display,event.xselection.requestor,
+          event.xselection.property,0L,2047L,MagickTrue,XA_STRING,&type,
+          &format,&length,&after,&data);
+        if ((status != Success) || (type != XA_STRING) || (format == 32) ||
+            (length == 0))
+          break;
+        if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
+          (void) XBell(display,0);
+        else
+          {
+            /*
+              Insert primary selection in reply text.
+            */
+            *(data+length)='\0';
+            XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
+              state);
+            XDrawMatteText(display,&windows->widget,&reply_info);
+            state|=JumpListState;
+            state|=RedrawActionState;
+          }
+        (void) XFree((void *) data);
+        break;
+      }
+      case SelectionRequest:
+      {
+        XSelectionEvent
+          notify;
+
+        XSelectionRequestEvent
+          *request;
+
+        /*
+          Set XA_PRIMARY selection.
+        */
+        request=(&(event.xselectionrequest));
+        (void) XChangeProperty(request->display,request->requestor,
+          request->property,request->target,8,PropModeReplace,
+          (unsigned char *) primary_selection,Extent(primary_selection));
+        notify.type=SelectionNotify;
+        notify.display=request->display;
+        notify.requestor=request->requestor;
+        notify.selection=request->selection;
+        notify.target=request->target;
+        notify.time=request->time;
+        if (request->property == None)
+          notify.property=request->target;
+        else
+          notify.property=request->property;
+        (void) XSendEvent(request->display,request->requestor,False,0,
+          (XEvent *) &notify);
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  /*
+    Free font list.
+  */
+  (void) XFreeFontNames(listhead);
+  fontlist=(char **) RelinquishMagickMemory(fontlist);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X I n f o W i d g e t                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XInfoWidget() displays text in the Info widget.  The purpose is to inform
+%  the user that what activity is currently being performed (e.g. reading
+%  an image, rotating an image, etc.).
+%
+%  The format of the XInfoWidget method is:
+%
+%      void XInfoWidget(Display *display,XWindows *windows,const char *activity)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o activity: This character string reflects the current activity and is
+%      displayed in the Info widget.
+%
+*/
+MagickExport void XInfoWidget(Display *display,XWindows *windows,
+  const char *activity)
+{
+  unsigned int
+    height,
+    margin,
+    width;
+
+  XFontStruct
+    *font_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Map Info widget.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(activity != (char *) NULL);
+  font_info=windows->info.font_info;
+  width=WidgetTextWidth(font_info,(char *) activity)+((3*QuantumMargin) >> 1)+4;
+  height=(unsigned int) (((6*(font_info->ascent+font_info->descent)) >> 2)+4);
+  if ((windows->info.width != width) || (windows->info.height != height))
+    {
+      /*
+        Size Info widget to accommodate the activity text.
+      */
+      windows->info.width=width;
+      windows->info.height=height;
+      window_changes.width=(int) width;
+      window_changes.height=(int) height;
+      (void) XReconfigureWMWindow(display,windows->info.id,windows->info.screen,
+        (unsigned int) (CWWidth | CWHeight),&window_changes);
+    }
+  if (windows->info.mapped == MagickFalse)
+    {
+      (void) XMapRaised(display,windows->info.id);
+      windows->info.mapped=MagickTrue;
+    }
+  /*
+    Initialize Info matte information.
+  */
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  XGetWidgetInfo(activity,&monitor_info);
+  monitor_info.bevel_width--;
+  margin=monitor_info.bevel_width+((windows->info.height-height) >> 1)-2;
+  monitor_info.center=MagickFalse;
+  monitor_info.x=(int) margin;
+  monitor_info.y=(int) margin;
+  monitor_info.width=windows->info.width-(margin << 1);
+  monitor_info.height=windows->info.height-(margin << 1)+1;
+  /*
+    Draw Info widget.
+  */
+  monitor_info.raised=MagickFalse;
+  XDrawBeveledMatte(display,&windows->info,&monitor_info);
+  monitor_info.raised=MagickTrue;
+  XDrawWidgetText(display,&windows->info,&monitor_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X L i s t B r o w s e r W i d g e t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XListBrowserWidget() displays a List Browser widget with a query to the
+%  user.  The user keys a reply or select a reply from the list.  Finally, the
+%  user presses the Action or Cancel button to exit.  The typed text is
+%  returned as the reply function parameter.
+%
+%  The format of the XListBrowserWidget method is:
+%
+%      void XListBrowserWidget(Display *display,XWindows *windows,
+%        XWindowInfo *window_info,const char **list,const char *action,
+%        const char *query,char *reply)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o list: Specifies a pointer to an array of strings.  The user can
+%      select from these strings as a possible reply value.
+%
+%    o action: Specifies a pointer to the action of this widget.
+%
+%    o query: Specifies a pointer to the query to present to the user.
+%
+%    o reply: the response from the user is returned in this parameter.
+%
+*/
+MagickExport void XListBrowserWidget(Display *display,XWindows *windows,
+  XWindowInfo *window_info,const char **list,const char *action,
+  const char *query,char *reply)
+{
+#define CancelButtonText  "Cancel"
+
+  char
+    primary_selection[MaxTextExtent];
+
+  int
+    x;
+
+  register int
+    i;
+
+  static MagickStatusType
+    mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
+
+  Status
+    status;
+
+  unsigned int
+    entries,
+    height,
+    text_width,
+    visible_entries,
+    width;
+
+  size_t
+    delay,
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    action_info,
+    cancel_info,
+    expose_info,
+    list_info,
+    north_info,
+    reply_info,
+    scroll_info,
+    selection_info,
+    slider_info,
+    south_info,
+    text_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Count the number of entries in the list.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(window_info != (XWindowInfo *) NULL);
+  assert(list != (const char **) NULL);
+  assert(action != (char *) NULL);
+  assert(query != (char *) NULL);
+  assert(reply != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",action);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  if (list == (const char **) NULL)
+    {
+      XNoticeWidget(display,windows,"No text to browse:",(char *) NULL);
+      return;
+    }
+  for (entries=0; ; entries++)
+    if (list[entries] == (char *) NULL)
+      break;
+  /*
+    Determine Font Browser widget attributes.
+  */
+  font_info=window_info->font_info;
+  text_width=WidgetTextWidth(font_info,(char *) query);
+  for (i=0; i < (int) entries; i++)
+    if (WidgetTextWidth(font_info,(char *) list[i]) > text_width)
+      text_width=WidgetTextWidth(font_info,(char *) list[i]);
+  width=WidgetTextWidth(font_info,(char *) action);
+  if (WidgetTextWidth(font_info,CancelButtonText) > width)
+    width=WidgetTextWidth(font_info,CancelButtonText);
+  width+=QuantumMargin;
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position List Browser widget.
+  */
+  window_info->width=(unsigned int) MagickMin((int) text_width,(int)
+    MaxTextWidth)+((9*QuantumMargin) >> 1);
+  window_info->min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
+  if (window_info->width < window_info->min_width)
+    window_info->width=window_info->min_width;
+  window_info->height=(unsigned int)
+    (((81*height) >> 2)+((13*QuantumMargin) >> 1)+4);
+  window_info->min_height=(unsigned int)
+    (((23*height) >> 1)+((13*QuantumMargin) >> 1)+4);
+  if (window_info->height < window_info->min_height)
+    window_info->height=window_info->min_height;
+  XConstrainWindowPosition(display,window_info);
+  /*
+    Map List Browser widget.
+  */
+  (void) CopyMagickString(window_info->name,"Browse",MaxTextExtent);
+  status=XStringListToTextProperty(&window_info->name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,window_info->id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) window_info->width;
+  window_changes.height=(int) window_info->height;
+  window_changes.x=window_info->x;
+  window_changes.y=window_info->y;
+  (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,mask,
+    &window_changes);
+  (void) XMapRaised(display,window_info->id);
+  window_info->mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  XGetWidgetInfo((char *) NULL,&slider_info);
+  XGetWidgetInfo((char *) NULL,&north_info);
+  XGetWidgetInfo((char *) NULL,&south_info);
+  XGetWidgetInfo((char *) NULL,&expose_info);
+  visible_entries=0;
+  delay=SuspendTime << 2;
+  state=UpdateConfigurationState;
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        int
+          id;
+
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=width;
+        cancel_info.height=(unsigned int) ((3*height) >> 1);
+        cancel_info.x=(int)
+          (window_info->width-cancel_info.width-QuantumMargin-2);
+        cancel_info.y=(int)
+          (window_info->height-cancel_info.height-QuantumMargin);
+        XGetWidgetInfo(action,&action_info);
+        action_info.width=width;
+        action_info.height=(unsigned int) ((3*height) >> 1);
+        action_info.x=cancel_info.x-(cancel_info.width+(QuantumMargin >> 1)+
+          (action_info.bevel_width << 1));
+        action_info.y=cancel_info.y;
+        /*
+          Initialize reply information.
+        */
+        XGetWidgetInfo(reply,&reply_info);
+        reply_info.raised=MagickFalse;
+        reply_info.bevel_width--;
+        reply_info.width=window_info->width-((4*QuantumMargin) >> 1);
+        reply_info.height=height << 1;
+        reply_info.x=QuantumMargin;
+        reply_info.y=action_info.y-reply_info.height-QuantumMargin;
+        /*
+          Initialize scroll information.
+        */
+        XGetWidgetInfo((char *) NULL,&scroll_info);
+        scroll_info.bevel_width--;
+        scroll_info.width=height;
+        scroll_info.height=(unsigned int)
+          (reply_info.y-((6*QuantumMargin) >> 1)-height);
+        scroll_info.x=reply_info.x+(reply_info.width-scroll_info.width);
+        scroll_info.y=((5*QuantumMargin) >> 1)+height-reply_info.bevel_width;
+        scroll_info.raised=MagickFalse;
+        scroll_info.trough=MagickTrue;
+        north_info=scroll_info;
+        north_info.raised=MagickTrue;
+        north_info.width-=(north_info.bevel_width << 1);
+        north_info.height=north_info.width-1;
+        north_info.x+=north_info.bevel_width;
+        north_info.y+=north_info.bevel_width;
+        south_info=north_info;
+        south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
+          south_info.height;
+        id=slider_info.id;
+        slider_info=north_info;
+        slider_info.id=id;
+        slider_info.width-=2;
+        slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
+          slider_info.bevel_width+2;
+        slider_info.height=scroll_info.height-((slider_info.min_y-
+          scroll_info.y+1) << 1)+4;
+        visible_entries=scroll_info.height/(height+(height >> 3));
+        if (entries > visible_entries)
+          slider_info.height=(visible_entries*slider_info.height)/entries;
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.x=scroll_info.x+slider_info.bevel_width+1;
+        slider_info.y=slider_info.min_y;
+        expose_info=scroll_info;
+        expose_info.y=slider_info.y;
+        /*
+          Initialize list information.
+        */
+        XGetWidgetInfo((char *) NULL,&list_info);
+        list_info.raised=MagickFalse;
+        list_info.bevel_width--;
+        list_info.width=(unsigned int)
+          (scroll_info.x-reply_info.x-(QuantumMargin >> 1));
+        list_info.height=scroll_info.height;
+        list_info.x=reply_info.x;
+        list_info.y=scroll_info.y;
+        if (window_info->mapped == MagickFalse)
+          for (i=0; i < (int) entries; i++)
+            if (LocaleCompare(list[i],reply) == 0)
+              {
+                list_info.id=i;
+                slider_info.id=i-(visible_entries >> 1);
+                if (slider_info.id < 0)
+                  slider_info.id=0;
+              }
+        /*
+          Initialize text information.
+        */
+        XGetWidgetInfo(query,&text_info);
+        text_info.width=reply_info.width;
+        text_info.height=height;
+        text_info.x=list_info.x-(QuantumMargin >> 1);
+        text_info.y=QuantumMargin;
+        /*
+          Initialize selection information.
+        */
+        XGetWidgetInfo((char *) NULL,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.width=list_info.width;
+        selection_info.height=(unsigned int) ((9*height) >> 3);
+        selection_info.x=list_info.x;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw List Browser window.
+        */
+        XDrawWidgetText(display,window_info,&text_info);
+        XDrawBeveledMatte(display,window_info,&list_info);
+        XDrawBeveledMatte(display,window_info,&scroll_info);
+        XDrawTriangleNorth(display,window_info,&north_info);
+        XDrawBeveledButton(display,window_info,&slider_info);
+        XDrawTriangleSouth(display,window_info,&south_info);
+        XDrawBeveledMatte(display,window_info,&reply_info);
+        XDrawMatteText(display,window_info,&reply_info);
+        XDrawBeveledButton(display,window_info,&action_info);
+        XDrawBeveledButton(display,window_info,&cancel_info);
+        XHighlightWidget(display,window_info,BorderOffset,BorderOffset);
+        selection_info.id=(~0);
+        state|=RedrawActionState;
+        state|=RedrawListState;
+        state&=(~RedrawWidgetState);
+      }
+    if (state & RedrawListState)
+      {
+        /*
+          Determine slider id and position.
+        */
+        if (slider_info.id >= (int) (entries-visible_entries))
+          slider_info.id=(int) (entries-visible_entries);
+        if ((slider_info.id < 0) || (entries <= visible_entries))
+          slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        if (entries > 0)
+          slider_info.y+=
+            slider_info.id*(slider_info.max_y-slider_info.min_y+1)/entries;
+        if (slider_info.id != selection_info.id)
+          {
+            /*
+              Redraw scroll bar and file names.
+            */
+            selection_info.id=slider_info.id;
+            selection_info.y=list_info.y+(height >> 3)+2;
+            for (i=0; i < (int) visible_entries; i++)
+            {
+              selection_info.raised=(slider_info.id+i) != list_info.id ?
+                MagickTrue : MagickFalse;
+              selection_info.text=(char *) NULL;
+              if ((slider_info.id+i) < (int) entries)
+                selection_info.text=(char *) list[slider_info.id+i];
+              XDrawWidgetText(display,window_info,&selection_info);
+              selection_info.y+=(int) selection_info.height;
+            }
+            /*
+              Update slider.
+            */
+            if (slider_info.y > expose_info.y)
+              {
+                expose_info.height=(unsigned int) slider_info.y-expose_info.y;
+                expose_info.y=slider_info.y-expose_info.height-
+                  slider_info.bevel_width-1;
+              }
+            else
+              {
+                expose_info.height=(unsigned int) expose_info.y-slider_info.y;
+                expose_info.y=slider_info.y+slider_info.height+
+                  slider_info.bevel_width+1;
+              }
+            XDrawTriangleNorth(display,window_info,&north_info);
+            XDrawMatte(display,window_info,&expose_info);
+            XDrawBeveledButton(display,window_info,&slider_info);
+            XDrawTriangleSouth(display,window_info,&south_info);
+            expose_info.y=slider_info.y;
+          }
+        state&=(~RedrawListState);
+      }
+    /*
+      Wait for next event.
+    */
+    if (north_info.raised && south_info.raised)
+      (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    else
+      {
+        /*
+          Brief delay before advancing scroll bar.
+        */
+        XDelay(display,delay);
+        delay=SuspendTime;
+        (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
+        if (north_info.raised == MagickFalse)
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              slider_info.id--;
+              state|=RedrawListState;
+            }
+        if (south_info.raised == MagickFalse)
+          if (slider_info.id < (int) entries)
+            {
+              /*
+                Move slider down.
+              */
+              slider_info.id++;
+              state|=RedrawListState;
+            }
+        if (event.type != ButtonRelease)
+          continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(slider_info,event.xbutton))
+          {
+            /*
+              Track slider.
+            */
+            slider_info.active=MagickTrue;
+            break;
+          }
+        if (MatteIsActive(north_info,event.xbutton))
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              north_info.raised=MagickFalse;
+              slider_info.id--;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(south_info,event.xbutton))
+          if (slider_info.id < (int) entries)
+            {
+              /*
+                Move slider down.
+              */
+              south_info.raised=MagickFalse;
+              slider_info.id++;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(scroll_info,event.xbutton))
+          {
+            /*
+              Move slider.
+            */
+            if (event.xbutton.y < slider_info.y)
+              slider_info.id-=(visible_entries-1);
+            else
+              slider_info.id+=(visible_entries-1);
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(list_info,event.xbutton))
+          {
+            int
+              id;
+
+            /*
+              User pressed list matte.
+            */
+            id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
+              selection_info.height;
+            if (id >= (int) entries)
+              break;
+            (void) CopyMagickString(reply_info.text,list[id],MaxTextExtent);
+            reply_info.highlight=MagickFalse;
+            reply_info.marker=reply_info.text;
+            reply_info.cursor=reply_info.text+Extent(reply_info.text);
+            XDrawMatteText(display,window_info,&reply_info);
+            selection_info.id=(~0);
+            if (id == list_info.id)
+              {
+                action_info.raised=MagickFalse;
+                XDrawBeveledButton(display,window_info,&action_info);
+                state|=ExitState;
+              }
+            list_info.id=id;
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(action_info,event.xbutton))
+          {
+            /*
+              User pressed action button.
+            */
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,window_info,&action_info);
+            break;
+          }
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed Cancel button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,window_info,&cancel_info);
+            break;
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        if (event.xbutton.button != Button2)
+          {
+            static Time
+              click_time;
+
+            /*
+              Move text cursor to position of button press.
+            */
+            x=event.xbutton.x-reply_info.x-(QuantumMargin >> 2);
+            for (i=1; i <= Extent(reply_info.marker); i++)
+              if (XTextWidth(font_info,reply_info.marker,i) > x)
+                break;
+            reply_info.cursor=reply_info.marker+i-1;
+            if (event.xbutton.time > (click_time+DoubleClick))
+              reply_info.highlight=MagickFalse;
+            else
+              {
+                /*
+                  Become the XA_PRIMARY selection owner.
+                */
+                (void) CopyMagickString(primary_selection,reply_info.text,
+                  MaxTextExtent);
+                (void) XSetSelectionOwner(display,XA_PRIMARY,window_info->id,
+                  event.xbutton.time);
+                reply_info.highlight=XGetSelectionOwner(display,XA_PRIMARY) ==
+                  window_info->id ? MagickTrue : MagickFalse;
+              }
+            XDrawMatteText(display,window_info,&reply_info);
+            click_time=event.xbutton.time;
+            break;
+          }
+        /*
+          Request primary selection.
+        */
+        (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
+          window_info->id,event.xbutton.time);
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (window_info->mapped == MagickFalse)
+          break;
+        if (north_info.raised == MagickFalse)
+          {
+            /*
+              User released up button.
+            */
+            delay=SuspendTime << 2;
+            north_info.raised=MagickTrue;
+            XDrawTriangleNorth(display,window_info,&north_info);
+          }
+        if (south_info.raised == MagickFalse)
+          {
+            /*
+              User released down button.
+            */
+            delay=SuspendTime << 2;
+            south_info.raised=MagickTrue;
+            XDrawTriangleSouth(display,window_info,&south_info);
+          }
+        if (slider_info.active)
+          {
+            /*
+              Stop tracking slider.
+            */
+            slider_info.active=MagickFalse;
+            break;
+          }
+        if (action_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == window_info->id)
+              {
+                if (MatteIsActive(action_info,event.xbutton))
+                  {
+                    if (*reply_info.text == '\0')
+                      (void) XBell(display,0);
+                    else
+                      state|=ExitState;
+                  }
+              }
+            action_info.raised=MagickTrue;
+            XDrawBeveledButton(display,window_info,&action_info);
+          }
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == window_info->id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                {
+                  *reply_info.text='\0';
+                  state|=ExitState;
+                }
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,window_info,&cancel_info);
+          }
+        if (MatteIsActive(reply_info,event.xbutton) == MagickFalse)
+          break;
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == window_info->id)
+          {
+            *reply_info.text='\0';
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != window_info->id)
+          break;
+        if ((event.xconfigure.width == (int) window_info->width) &&
+            (event.xconfigure.height == (int) window_info->height))
+          break;
+        window_info->width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) window_info->min_width);
+        window_info->height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) window_info->min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != window_info->id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != window_info->id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static int
+          length;
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != window_info->id)
+          break;
+        length=XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if (AreaIsActive(scroll_info,event.xkey))
+          {
+            /*
+              Move slider.
+            */
+            switch ((int) key_symbol)
+            {
+              case XK_Home:
+              case XK_KP_Home:
+              {
+                slider_info.id=0;
+                break;
+              }
+              case XK_Up:
+              case XK_KP_Up:
+              {
+                slider_info.id--;
+                break;
+              }
+              case XK_Down:
+              case XK_KP_Down:
+              {
+                slider_info.id++;
+                break;
+              }
+              case XK_Prior:
+              case XK_KP_Prior:
+              {
+                slider_info.id-=visible_entries;
+                break;
+              }
+              case XK_Next:
+              case XK_KP_Next:
+              {
+                slider_info.id+=visible_entries;
+                break;
+              }
+              case XK_End:
+              case XK_KP_End:
+              {
+                slider_info.id=(int) entries;
+                break;
+              }
+            }
+            state|=RedrawListState;
+            break;
+          }
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            /*
+              Read new entry.
+            */
+            if (*reply_info.text == '\0')
+              break;
+            action_info.raised=MagickFalse;
+            XDrawBeveledButton(display,window_info,&action_info);
+            state|=ExitState;
+            break;
+          }
+        if (key_symbol == XK_Control_L)
+          {
+            state|=ControlState;
+            break;
+          }
+        if (state & ControlState)
+          switch ((int) key_symbol)
+          {
+            case XK_u:
+            case XK_U:
+            {
+              /*
+                Erase the entire line of text.
+              */
+              *reply_info.text='\0';
+              reply_info.cursor=reply_info.text;
+              reply_info.marker=reply_info.text;
+              reply_info.highlight=MagickFalse;
+              break;
+            }
+            default:
+              break;
+          }
+        XEditText(display,&reply_info,key_symbol,command,state);
+        XDrawMatteText(display,window_info,&reply_info);
+        break;
+      }
+      case KeyRelease:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key release.
+        */
+        if (event.xkey.window != window_info->id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if (key_symbol == XK_Control_L)
+          state&=(~ControlState);
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != window_info->id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MapNotify:
+      {
+        mask&=(~CWX);
+        mask&=(~CWY);
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (slider_info.active)
+          {
+            /*
+              Move slider matte.
+            */
+            slider_info.y=event.xmotion.y-
+              ((slider_info.height+slider_info.bevel_width) >> 1)+1;
+            if (slider_info.y < slider_info.min_y)
+              slider_info.y=slider_info.min_y;
+            if (slider_info.y > slider_info.max_y)
+              slider_info.y=slider_info.max_y;
+            slider_info.id=0;
+            if (slider_info.y != slider_info.min_y)
+              slider_info.id=(int) ((entries*(slider_info.y-
+                slider_info.min_y+1))/(slider_info.max_y-slider_info.min_y+1));
+            state|=RedrawListState;
+            break;
+          }
+        if (state & InactiveWidgetState)
+          break;
+        if (action_info.raised == MatteIsActive(action_info,event.xmotion))
+          {
+            /*
+              Action button status changed.
+            */
+            action_info.raised=action_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,window_info,&action_info);
+            break;
+          }
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=cancel_info.raised == MagickFalse ?
+              MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,window_info,&cancel_info);
+            break;
+          }
+        break;
+      }
+      case SelectionClear:
+      {
+        reply_info.highlight=MagickFalse;
+        XDrawMatteText(display,window_info,&reply_info);
+        break;
+      }
+      case SelectionNotify:
+      {
+        Atom
+          type;
+
+        int
+          format;
+
+        unsigned char
+          *data;
+
+        unsigned long
+          after,
+          length;
+
+        /*
+          Obtain response from primary selection.
+        */
+        if (event.xselection.property == (Atom) None)
+          break;
+        status=XGetWindowProperty(display,
+          event.xselection.requestor,event.xselection.property,0L,2047L,
+          MagickTrue,XA_STRING,&type,&format,&length,&after,&data);
+        if ((status != Success) || (type != XA_STRING) || (format == 32) ||
+            (length == 0))
+          break;
+        if ((Extent(reply_info.text)+length) >= (MaxTextExtent-1))
+          (void) XBell(display,0);
+        else
+          {
+            /*
+              Insert primary selection in reply text.
+            */
+            *(data+length)='\0';
+            XEditText(display,&reply_info,(KeySym) XK_Insert,(char *) data,
+              state);
+            XDrawMatteText(display,window_info,&reply_info);
+            state|=RedrawActionState;
+          }
+        (void) XFree((void *) data);
+        break;
+      }
+      case SelectionRequest:
+      {
+        XSelectionEvent
+          notify;
+
+        XSelectionRequestEvent
+          *request;
+
+        if (reply_info.highlight == MagickFalse)
+          break;
+        /*
+          Set primary selection.
+        */
+        request=(&(event.xselectionrequest));
+        (void) XChangeProperty(request->display,request->requestor,
+          request->property,request->target,8,PropModeReplace,
+          (unsigned char *) primary_selection,Extent(primary_selection));
+        notify.type=SelectionNotify;
+        notify.send_event=MagickTrue;
+        notify.display=request->display;
+        notify.requestor=request->requestor;
+        notify.selection=request->selection;
+        notify.target=request->target;
+        notify.time=request->time;
+        if (request->property == None)
+          notify.property=request->target;
+        else
+          notify.property=request->property;
+        (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
+          (XEvent *) &notify);
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,window_info->id,window_info->screen);
+  XCheckRefreshWindows(display,windows);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M e n u W i d g e t                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMenuWidget() maps a menu and returns the command pointed to by the user
+%  when the button is released.
+%
+%  The format of the XMenuWidget method is:
+%
+%      int XMenuWidget(Display *display,XWindows *windows,const char *title,
+%        const char **selections,char *item)
+%
+%  A description of each parameter follows:
+%
+%    o selection_number: Specifies the number of the selection that the
+%      user choose.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o title: Specifies a character string that describes the menu selections.
+%
+%    o selections: Specifies a pointer to one or more strings that comprise
+%      the choices in the menu.
+%
+%    o item: Specifies a character array.  The item selected from the menu
+%      is returned here.
+%
+*/
+MagickExport int XMenuWidget(Display *display,XWindows *windows,
+  const char *title,const char **selections,char *item)
+{
+  Cursor
+    cursor;
+
+  int
+    id,
+    x,
+    y;
+
+  unsigned int
+    height,
+    number_selections,
+    title_height,
+    top_offset,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XSetWindowAttributes
+    window_attributes;
+
+  XWidgetInfo
+    highlight_info,
+    menu_info,
+    selection_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Determine Menu widget attributes.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(title != (char *) NULL);
+  assert(selections != (const char **) NULL);
+  assert(item != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
+  font_info=windows->widget.font_info;
+  windows->widget.width=submenu_info.active == 0 ?
+    WidgetTextWidth(font_info,(char *) title) : 0;
+  for (id=0; selections[id] != (char *) NULL; id++)
+  {
+    width=WidgetTextWidth(font_info,(char *) selections[id]);
+    if (width > windows->widget.width)
+      windows->widget.width=width;
+  }
+  number_selections=(unsigned int) id;
+  XGetWidgetInfo((char *) NULL,&menu_info);
+  title_height=(unsigned int) (submenu_info.active == 0 ?
+    (3*(font_info->descent+font_info->ascent) >> 1)+5 : 2);
+  width=WidgetTextWidth(font_info,(char *) title);
+  height=(unsigned int) ((3*(font_info->ascent+font_info->descent)) >> 1);
+  /*
+    Position Menu widget.
+  */
+  windows->widget.width+=QuantumMargin+(menu_info.bevel_width << 1);
+  top_offset=title_height+menu_info.bevel_width-1;
+  windows->widget.height=top_offset+number_selections*height+4;
+  windows->widget.min_width=windows->widget.width;
+  windows->widget.min_height=windows->widget.height;
+  XQueryPosition(display,windows->widget.root,&x,&y);
+  windows->widget.x=x-(QuantumMargin >> 1);
+  if (submenu_info.active != 0)
+    {
+      windows->widget.x=
+        windows->command.x+windows->command.width-QuantumMargin;
+      toggle_info.raised=MagickTrue;
+      XDrawTriangleEast(display,&windows->command,&toggle_info);
+    }
+  windows->widget.y=submenu_info.active == 0 ? y-(int)
+    ((3*title_height) >> 2) : y;
+  if (submenu_info.active != 0)
+    windows->widget.y=windows->command.y+submenu_info.y;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Menu widget.
+  */
+  window_attributes.override_redirect=MagickTrue;
+  (void) XChangeWindowAttributes(display,windows->widget.id,
+    (size_t) CWOverrideRedirect,&window_attributes);
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
+    (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  selection_info.height=height;
+  cursor=XCreateFontCursor(display,XC_right_ptr);
+  (void) XCheckDefineCursor(display,windows->image.id,cursor);
+  (void) XCheckDefineCursor(display,windows->command.id,cursor);
+  (void) XCheckDefineCursor(display,windows->widget.id,cursor);
+  state=UpdateConfigurationState;
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        /*
+          Initialize selection information.
+        */
+        XGetWidgetInfo((char *) NULL,&menu_info);
+        menu_info.bevel_width--;
+        menu_info.width=windows->widget.width-((menu_info.bevel_width) << 1);
+        menu_info.height=windows->widget.height-((menu_info.bevel_width) << 1);
+        menu_info.x=(int) menu_info.bevel_width;
+        menu_info.y=(int) menu_info.bevel_width;
+        XGetWidgetInfo((char *) NULL,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.width=menu_info.width;
+        selection_info.height=height;
+        selection_info.x=menu_info.x;
+        highlight_info=selection_info;
+        highlight_info.bevel_width--;
+        highlight_info.width-=(highlight_info.bevel_width << 1);
+        highlight_info.height-=(highlight_info.bevel_width << 1);
+        highlight_info.x+=highlight_info.bevel_width;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Menu widget.
+        */
+        if (submenu_info.active == 0)
+          {
+            y=(int) title_height;
+            XSetBevelColor(display,&windows->widget,MagickFalse);
+            (void) XDrawLine(display,windows->widget.id,
+              windows->widget.widget_context,selection_info.x,y-1,
+              (int) selection_info.width,y-1);
+            XSetBevelColor(display,&windows->widget,MagickTrue);
+            (void) XDrawLine(display,windows->widget.id,
+              windows->widget.widget_context,selection_info.x,y,
+              (int) selection_info.width,y);
+            (void) XSetFillStyle(display,windows->widget.widget_context,
+              FillSolid);
+          }
+        /*
+          Draw menu selections.
+        */
+        selection_info.center=MagickTrue;
+        selection_info.y=(int) menu_info.bevel_width;
+        selection_info.text=(char *) title;
+        if (submenu_info.active == 0)
+          XDrawWidgetText(display,&windows->widget,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.y=(int) top_offset;
+        for (id=0; id < (int) number_selections; id++)
+        {
+          selection_info.text=(char *) selections[id];
+          XDrawWidgetText(display,&windows->widget,&selection_info);
+          highlight_info.y=selection_info.y+highlight_info.bevel_width;
+          if (id == selection_info.id)
+            XDrawBevel(display,&windows->widget,&highlight_info);
+          selection_info.y+=(int) selection_info.height;
+        }
+        XDrawBevel(display,&windows->widget,&menu_info);
+        state&=(~RedrawWidgetState);
+      }
+    if (number_selections > 2)
+      {
+        /*
+          Redraw Menu line.
+        */
+        y=(int) (top_offset+selection_info.height*(number_selections-1));
+        XSetBevelColor(display,&windows->widget,MagickFalse);
+        (void) XDrawLine(display,windows->widget.id,
+          windows->widget.widget_context,selection_info.x,y-1,
+          (int) selection_info.width,y-1);
+        XSetBevelColor(display,&windows->widget,MagickTrue);
+        (void) XDrawLine(display,windows->widget.id,
+          windows->widget.widget_context,selection_info.x,y,
+          (int) selection_info.width,y);
+        (void) XSetFillStyle(display,windows->widget.widget_context,FillSolid);
+      }
+    /*
+      Wait for next event.
+    */
+    (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (event.xbutton.window != windows->widget.id)
+          {
+            /*
+              exit menu.
+            */
+            if (event.xbutton.window == windows->command.id)
+              (void) XPutBackEvent(display,&event);
+            selection_info.id=(~0);
+            *item='\0';
+            state|=ExitState;
+            break;
+          }
+        state&=(~InactiveWidgetState);
+        id=(event.xbutton.y-top_offset)/(int) selection_info.height;
+        selection_info.id=id;
+        if ((id < 0) || (id >= (int) number_selections))
+          break;
+        /*
+          Highlight this selection.
+        */
+        selection_info.y=(int) (top_offset+id*selection_info.height);
+        selection_info.text=(char *) selections[id];
+        XDrawWidgetText(display,&windows->widget,&selection_info);
+        highlight_info.y=selection_info.y+highlight_info.bevel_width;
+        XDrawBevel(display,&windows->widget,&highlight_info);
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (event.xbutton.window == windows->command.id)
+          if ((state & InactiveWidgetState) == 0)
+            break;
+        /*
+          exit menu.
+        */
+        XSetCursorState(display,windows,MagickFalse);
+        *item='\0';
+        state|=ExitState;
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        if (event.xcrossing.state == 0)
+          break;
+        state&=(~InactiveWidgetState);
+        id=((event.xcrossing.y-top_offset)/(int) selection_info.height);
+        if ((selection_info.id >= 0) &&
+            (selection_info.id < (int) number_selections))
+          {
+            /*
+              Unhighlight last selection.
+            */
+            if (id == selection_info.id)
+              break;
+            selection_info.y=(int)
+              (top_offset+selection_info.id*selection_info.height);
+            selection_info.text=(char *) selections[selection_info.id];
+            XDrawWidgetText(display,&windows->widget,&selection_info);
+          }
+        if ((id < 0) || (id >= (int) number_selections))
+          break;
+        /*
+          Highlight this selection.
+        */
+        selection_info.id=id;
+        selection_info.y=(int)
+          (top_offset+selection_info.id*selection_info.height);
+        selection_info.text=(char *) selections[selection_info.id];
+        XDrawWidgetText(display,&windows->widget,&selection_info);
+        highlight_info.y=selection_info.y+highlight_info.bevel_width;
+        XDrawBevel(display,&windows->widget,&highlight_info);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        id=selection_info.id;
+        if ((id < 0) || (id >= (int) number_selections))
+          break;
+        /*
+          Unhighlight last selection.
+        */
+        selection_info.y=(int) (top_offset+id*selection_info.height);
+        selection_info.id=(~0);
+        selection_info.text=(char *) selections[id];
+        XDrawWidgetText(display,&windows->widget,&selection_info);
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (submenu_info.active != 0)
+          if (event.xmotion.window == windows->command.id)
+            {
+              if ((state & InactiveWidgetState) == 0)
+                {
+                  if (MatteIsActive(submenu_info,event.xmotion) == MagickFalse)
+                    {
+                      selection_info.id=(~0);
+                        *item='\0';
+                      state|=ExitState;
+                      break;
+                    }
+                }
+              else
+                if (WindowIsActive(windows->command,event.xmotion))
+                  {
+                    selection_info.id=(~0);
+                    *item='\0';
+                    state|=ExitState;
+                    break;
+                  }
+            }
+        if (event.xmotion.window != windows->widget.id)
+          break;
+        if (state & InactiveWidgetState)
+          break;
+        id=(event.xmotion.y-top_offset)/(int) selection_info.height;
+        if ((selection_info.id >= 0) &&
+            (selection_info.id < (int) number_selections))
+          {
+            /*
+              Unhighlight last selection.
+            */
+            if (id == selection_info.id)
+              break;
+            selection_info.y=(int)
+              (top_offset+selection_info.id*selection_info.height);
+            selection_info.text=(char *) selections[selection_info.id];
+            XDrawWidgetText(display,&windows->widget,&selection_info);
+          }
+        selection_info.id=id;
+        if ((id < 0) || (id >= (int) number_selections))
+          break;
+        /*
+          Highlight this selection.
+        */
+        selection_info.y=(int) (top_offset+id*selection_info.height);
+        selection_info.text=(char *) selections[id];
+        XDrawWidgetText(display,&windows->widget,&selection_info);
+        highlight_info.y=selection_info.y+highlight_info.bevel_width;
+        XDrawBevel(display,&windows->widget,&highlight_info);
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  (void) XFreeCursor(display,cursor);
+  window_attributes.override_redirect=MagickFalse;
+  (void) XChangeWindowAttributes(display,windows->widget.id,
+    (size_t) CWOverrideRedirect,&window_attributes);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  if (submenu_info.active != 0)
+    {
+      submenu_info.active=MagickFalse;
+      toggle_info.raised=MagickFalse;
+      XDrawTriangleEast(display,&windows->command,&toggle_info);
+    }
+  if ((selection_info.id < 0) || (selection_info.id >= (int) number_selections))
+    return(~0);
+  (void) CopyMagickString(item,selections[selection_info.id],MaxTextExtent);
+  return(selection_info.id);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X N o t i c e W i d g e t                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XNoticeWidget() displays a Notice widget with a notice to the user.  The
+%  function returns when the user presses the "Dismiss" button.
+%
+%  The format of the XNoticeWidget method is:
+%
+%      void XNoticeWidget(Display *display,XWindows *windows,
+%        const char *reason,const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o reason: Specifies the message to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the message.
+%
+*/
+MagickExport void XNoticeWidget(Display *display,XWindows *windows,
+  const char *reason,const char *description)
+{
+#define DismissButtonText  "Dismiss"
+#define Timeout  8
+
+  const char
+    *text;
+
+  int
+    x,
+    y;
+
+  Status
+    status;
+
+  time_t
+    timer;
+
+  unsigned int
+    height,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    dismiss_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Determine Notice widget attributes.
+  */
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(reason != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",reason);
+  XDelay(display,SuspendTime << 3);  /* avoid surpise with delay */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  font_info=windows->widget.font_info;
+  width=WidgetTextWidth(font_info,DismissButtonText);
+  text=GetLocaleExceptionMessage(XServerError,reason);
+  if (text != (char *) NULL)
+    if (WidgetTextWidth(font_info,(char *) text) > width)
+      width=WidgetTextWidth(font_info,(char *) text);
+  if (description != (char *) NULL)
+    {
+      text=GetLocaleExceptionMessage(XServerError,description);
+      if (text != (char *) NULL)
+        if (WidgetTextWidth(font_info,(char *) text) > width)
+          width=WidgetTextWidth(font_info,(char *) text);
+    }
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position Notice widget.
+  */
+  windows->widget.width=width+4*QuantumMargin;
+  windows->widget.min_width=width+QuantumMargin;
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int) (12*height);
+  windows->widget.min_height=(unsigned int) (7*height);
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Notice widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Notice",MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
+    (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  (void) XBell(display,0);
+  /*
+    Respond to X events.
+  */
+  timer=time((time_t *) NULL)+Timeout;
+  state=UpdateConfigurationState;
+  do
+  {
+    if (time((time_t *) NULL) > timer)
+      break;
+    if (state & UpdateConfigurationState)
+      {
+        /*
+          Initialize Dismiss button information.
+        */
+        XGetWidgetInfo(DismissButtonText,&dismiss_info);
+        dismiss_info.width=(unsigned int) QuantumMargin+
+          WidgetTextWidth(font_info,DismissButtonText);
+        dismiss_info.height=(unsigned int) ((3*height) >> 1);
+        dismiss_info.x=(int)
+          ((windows->widget.width >> 1)-(dismiss_info.width >> 1));
+        dismiss_info.y=(int)
+          (windows->widget.height-(dismiss_info.height << 1));
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Notice widget.
+        */
+        width=WidgetTextWidth(font_info,(char *) reason);
+        x=(int) ((windows->widget.width >> 1)-(width >> 1));
+        y=(int) ((windows->widget.height >> 1)-(height << 1));
+        (void) XDrawString(display,windows->widget.id,
+          windows->widget.annotate_context,x,y,(char *) reason,Extent(reason));
+        if (description != (char *) NULL)
+          {
+            width=WidgetTextWidth(font_info,(char *) description);
+            x=(int) ((windows->widget.width >> 1)-(width >> 1));
+            y+=height;
+            (void) XDrawString(display,windows->widget.id,
+              windows->widget.annotate_context,x,y,(char *) description,
+              Extent(description));
+          }
+        XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~RedrawWidgetState);
+      }
+    /*
+      Wait for next event.
+    */
+    if (XCheckIfEvent(display,&event,XScreenEvent,(char *) windows) == MagickFalse)
+      {
+        /*
+          Do not block if delay > 0.
+        */
+        XDelay(display,SuspendTime << 2);
+        continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(dismiss_info,event.xbutton))
+          {
+            /*
+              User pressed Dismiss button.
+            */
+            dismiss_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            break;
+          }
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (dismiss_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(dismiss_info,event.xbutton))
+                state|=ExitState;
+            dismiss_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            dismiss_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (state & InactiveWidgetState)
+          break;
+        if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
+          {
+            /*
+              Dismiss button status changed.
+            */
+            dismiss_info.raised=
+              dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X P r e f e r e n c e s W i d g e t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XPreferencesWidget() displays a Preferences widget with program preferences.
+%  If the user presses the Apply button, the preferences are stored in a
+%  configuration file in the users' home directory.
+%
+%  The format of the XPreferencesWidget method is:
+%
+%      MagickBooleanType XPreferencesWidget(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+*/
+MagickExport MagickBooleanType XPreferencesWidget(Display *display,
+  XResourceInfo *resource_info,XWindows *windows)
+{
+#define ApplyButtonText  "Apply"
+#define CacheButtonText  "%lu mega-bytes of memory in the undo edit cache   "
+#define CancelButtonText  "Cancel"
+#define NumberPreferences  8
+
+  static const char
+    *Preferences[] =
+    {
+      "display image centered on a backdrop",
+      "confirm on program exit",
+      "confirm on image edits",
+      "correct image for display gamma",
+      "display warning messages",
+      "apply Floyd/Steinberg error diffusion to image",
+      "use a shared colormap for colormapped X visuals",
+      "display images as an X server pixmap"
+    };
+
+  char
+    cache[MaxTextExtent];
+
+  int
+    x,
+    y;
+
+  register int
+    i;
+
+  Status
+    status;
+
+  unsigned int
+    height,
+    text_width,
+    width;
+
+  size_t
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    apply_info,
+    cache_info,
+    cancel_info,
+    preferences_info[NumberPreferences];
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Determine Preferences widget attributes.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(windows != (XWindows *) NULL);
+  XCheckRefreshWindows(display,windows);
+  font_info=windows->widget.font_info;
+  text_width=WidgetTextWidth(font_info,CacheButtonText);
+  for (i=0; i < NumberPreferences; i++)
+    if (WidgetTextWidth(font_info,(char *) Preferences[i]) > text_width)
+      text_width=WidgetTextWidth(font_info,(char *) Preferences[i]);
+  width=WidgetTextWidth(font_info,ApplyButtonText);
+  if (WidgetTextWidth(font_info,CancelButtonText) > width)
+    width=WidgetTextWidth(font_info,CancelButtonText);
+  width+=(unsigned int) QuantumMargin;
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  /*
+    Position Preferences widget.
+  */
+  windows->widget.width=(unsigned int) (MagickMax((int) (width << 1),
+    (int) text_width)+6*QuantumMargin);
+  windows->widget.min_width=(width << 1)+QuantumMargin;
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int)
+    (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
+  windows->widget.min_height=(unsigned int)
+    (7*height+NumberPreferences*(height+(QuantumMargin >> 1)));
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Preferences widget.
+  */
+  (void) CopyMagickString(windows->widget.name,"Preferences",MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,windows->widget.screen,
+    (unsigned int) (CWWidth | CWHeight | CWX | CWY),&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  state=UpdateConfigurationState;
+  XSetCursorState(display,windows,MagickTrue);
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(CancelButtonText,&cancel_info);
+        cancel_info.width=width;
+        cancel_info.height=(unsigned int) (3*height) >> 1;
+        cancel_info.x=(int) windows->widget.width-cancel_info.width-
+          (QuantumMargin << 1);
+        cancel_info.y=(int) windows->widget.height-
+          cancel_info.height-QuantumMargin;
+        XGetWidgetInfo(ApplyButtonText,&apply_info);
+        apply_info.width=width;
+        apply_info.height=(unsigned int) (3*height) >> 1;
+        apply_info.x=QuantumMargin << 1;
+        apply_info.y=cancel_info.y;
+        y=(int) (height << 1);
+        for (i=0; i < NumberPreferences; i++)
+        {
+          XGetWidgetInfo(Preferences[i],&preferences_info[i]);
+          preferences_info[i].bevel_width--;
+          preferences_info[i].width=(unsigned int) QuantumMargin >> 1;
+          preferences_info[i].height=(unsigned int) QuantumMargin >> 1;
+          preferences_info[i].x=QuantumMargin << 1;
+          preferences_info[i].y=y;
+          y+=height+(QuantumMargin >> 1);
+        }
+        preferences_info[0].raised=resource_info->backdrop ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        preferences_info[1].raised=resource_info->confirm_exit ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        preferences_info[2].raised=resource_info->confirm_edit ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        preferences_info[3].raised=resource_info->gamma_correct ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        preferences_info[4].raised=resource_info->display_warnings ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        preferences_info[5].raised=resource_info->quantize_info->dither ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        preferences_info[6].raised=resource_info->colormap !=
+          SharedColormap ? MagickTrue : MagickFalse;
+        preferences_info[7].raised=resource_info->use_pixmap ==
+          MagickFalse ? MagickTrue : MagickFalse;
+        (void) FormatLocaleString(cache,MaxTextExtent,CacheButtonText,
+          (unsigned long) resource_info->undo_cache);
+        XGetWidgetInfo(cache,&cache_info);
+        cache_info.bevel_width--;
+        cache_info.width=(unsigned int) QuantumMargin >> 1;
+        cache_info.height=(unsigned int) QuantumMargin >> 1;
+        cache_info.x=QuantumMargin << 1;
+        cache_info.y=y;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Preferences widget.
+        */
+        XDrawBeveledButton(display,&windows->widget,&apply_info);
+        XDrawBeveledButton(display,&windows->widget,&cancel_info);
+        for (i=0; i < NumberPreferences; i++)
+          XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
+        XDrawTriangleEast(display,&windows->widget,&cache_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        state&=(~RedrawWidgetState);
+      }
+    /*
+      Wait for next event.
+    */
+    (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(apply_info,event.xbutton))
+          {
+            /*
+              User pressed Apply button.
+            */
+            apply_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&apply_info);
+            break;
+          }
+        if (MatteIsActive(cancel_info,event.xbutton))
+          {
+            /*
+              User pressed Cancel button.
+            */
+            cancel_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        for (i=0; i < NumberPreferences; i++)
+          if (MatteIsActive(preferences_info[i],event.xbutton))
+            {
+              /*
+                User pressed a Preferences button.
+              */
+              preferences_info[i].raised=preferences_info[i].raised ==
+                MagickFalse ? MagickTrue : MagickFalse;
+              XDrawBeveledButton(display,&windows->widget,&preferences_info[i]);
+              break;
+            }
+        if (MatteIsActive(cache_info,event.xbutton))
+          {
+            /*
+              User pressed Cache button.
+            */
+            x=cache_info.x+cache_info.width+cache_info.bevel_width+
+              (QuantumMargin >> 1);
+            y=cache_info.y+((cache_info.height-height) >> 1);
+            width=WidgetTextWidth(font_info,cache);
+            (void) XClearArea(display,windows->widget.id,x,y,width,height,
+              False);
+            resource_info->undo_cache<<=1;
+            if (resource_info->undo_cache > 256)
+              resource_info->undo_cache=1;
+            (void) FormatLocaleString(cache,MaxTextExtent,CacheButtonText,
+              (unsigned long) resource_info->undo_cache);
+            cache_info.raised=MagickFalse;
+            XDrawTriangleEast(display,&windows->widget,&cache_info);
+            break;
+          }
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (apply_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(apply_info,event.xbutton))
+                state|=ExitState;
+            apply_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&apply_info);
+            apply_info.raised=MagickFalse;
+          }
+        if (cancel_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(cancel_info,event.xbutton))
+                state|=ExitState;
+            cancel_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+          }
+        if (cache_info.raised == MagickFalse)
+          {
+            cache_info.raised=MagickTrue;
+            XDrawTriangleEast(display,&windows->widget,&cache_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        (void) XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            apply_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&apply_info);
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (state & InactiveWidgetState)
+          break;
+        if (apply_info.raised == MatteIsActive(apply_info,event.xmotion))
+          {
+            /*
+              Apply button status changed.
+            */
+            apply_info.raised=
+              apply_info.raised == MagickFalse ? MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&apply_info);
+            break;
+          }
+        if (cancel_info.raised == MatteIsActive(cancel_info,event.xmotion))
+          {
+            /*
+              Cancel button status changed.
+            */
+            cancel_info.raised=
+              cancel_info.raised == MagickFalse ? MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&cancel_info);
+            break;
+          }
+        break;
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+  if (apply_info.raised)
+    return(MagickFalse);
+  /*
+    Save user preferences to the client configuration file.
+  */
+  resource_info->backdrop=
+    preferences_info[0].raised == MagickFalse ? MagickTrue : MagickFalse;
+  resource_info->confirm_exit=
+    preferences_info[1].raised == MagickFalse ? MagickTrue : MagickFalse;
+  resource_info->confirm_edit=
+    preferences_info[2].raised == MagickFalse ? MagickTrue : MagickFalse;
+  resource_info->gamma_correct=
+    preferences_info[3].raised == MagickFalse ? MagickTrue : MagickFalse;
+  resource_info->display_warnings=
+     preferences_info[4].raised == MagickFalse ? MagickTrue : MagickFalse;
+  resource_info->quantize_info->dither=
+    preferences_info[5].raised == MagickFalse ? MagickTrue : MagickFalse;
+  resource_info->colormap=SharedColormap;
+  if (preferences_info[6].raised)
+    resource_info->colormap=PrivateColormap;
+  resource_info->use_pixmap=
+    preferences_info[7].raised == MagickFalse ? MagickTrue : MagickFalse;
+  XUserPreferences(resource_info);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X P r o g r e s s M o n i t o r W i d g e t                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XProgressMonitorWidget() displays the progress a task is making in
+%  completing a task.  A span of zero toggles the active status.  An inactive
+%  state disables the progress monitor.
+%
+%  The format of the XProgressMonitorWidget method is:
+%
+%      void XProgressMonitorWidget(Display *display,XWindows *windows,
+%        const char *task,const MagickOffsetType offset,
+%        const MagickSizeType span)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o task: Identifies the task in progress.
+%
+%    o offset: Specifies the offset position within the span which represents
+%      how much progress has been made in completing a task.
+%
+%    o span: Specifies the span relative to completing a task.
+%
+*/
+MagickExport void XProgressMonitorWidget(Display *display,XWindows *windows,
+  const char *task,const MagickOffsetType offset,const MagickSizeType span)
+{
+  unsigned int
+    width;
+
+  XEvent
+    event;
+
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(task != (const char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",task);
+  if (span == 0)
+    return;
+  /*
+    Update image windows if there is a pending expose event.
+  */
+  while (XCheckTypedWindowEvent(display,windows->command.id,Expose,&event))
+    (void) XCommandWidget(display,windows,(const char **) NULL,&event);
+  while (XCheckTypedWindowEvent(display,windows->image.id,Expose,&event))
+    XRefreshWindow(display,&windows->image,&event);
+  while (XCheckTypedWindowEvent(display,windows->info.id,Expose,&event))
+    if (monitor_info.text != (char *) NULL)
+      XInfoWidget(display,windows,monitor_info.text);
+  /*
+    Draw progress monitor bar to represent percent completion of a task.
+  */
+  if ((windows->info.mapped == MagickFalse) || (task != monitor_info.text))
+    XInfoWidget(display,windows,task);
+  width=(unsigned int) (((offset+1)*(windows->info.width-
+    (2*monitor_info.x)))/span);
+  if (width < monitor_info.width)
+    {
+      monitor_info.raised=MagickTrue;
+      XDrawWidgetText(display,&windows->info,&monitor_info);
+      monitor_info.raised=MagickFalse;
+    }
+  monitor_info.width=width;
+  XDrawWidgetText(display,&windows->info,&monitor_info);
+  (void) XFlush(display);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X T e x t V i e w W i d g e t                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XTextViewWidget() displays text in a Text View widget.
+%
+%  The format of the XTextViewWidget method is:
+%
+%      void XTextViewWidget(Display *display,const XResourceInfo *resource_info,
+%        XWindows *windows,const MagickBooleanType mono,const char *title,
+%        const char **textlist)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o window: Specifies a pointer to a XWindows structure.
+%
+%    o mono:  Use mono-spaced font when displaying text.
+%
+%    o title: This character string is displayed at the top of the widget
+%      window.
+%
+%    o textlist: This string list is displayed within the Text View widget.
+%
+*/
+MagickExport void XTextViewWidget(Display *display,
+  const XResourceInfo *resource_info,XWindows *windows,
+  const MagickBooleanType mono,const char *title,const char **textlist)
+{
+#define DismissButtonText  "Dismiss"
+
+  char
+    primary_selection[MaxTextExtent];
+
+  register int
+    i;
+
+  static MagickStatusType
+    mask = (MagickStatusType) (CWWidth | CWHeight | CWX | CWY);
+
+  Status
+    status;
+
+  unsigned int
+    height,
+    lines,
+    text_width,
+    visible_lines,
+    width;
+
+  size_t
+    delay,
+    state;
+
+  XEvent
+    event;
+
+  XFontStruct
+    *font_info,
+    *text_info;
+
+  XTextProperty
+    window_name;
+
+  XWidgetInfo
+    dismiss_info,
+    expose_info,
+    list_info,
+    north_info,
+    scroll_info,
+    selection_info,
+    slider_info,
+    south_info;
+
+  XWindowChanges
+    window_changes;
+
+  /*
+    Convert text string to a text list.
+  */
+  assert(display != (Display *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(title != (const char *) NULL);
+  assert(textlist != (const char **) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",title);
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  if (textlist == (const char **) NULL)
+    {
+      XNoticeWidget(display,windows,"No text to view:",(char *) NULL);
+      return;
+    }
+  /*
+    Determine Text View widget attributes.
+  */
+  font_info=windows->widget.font_info;
+  text_info=(XFontStruct *) NULL;
+  if (mono != MagickFalse)
+    text_info=XBestFont(display,resource_info,MagickTrue);
+  if (text_info == (XFontStruct *) NULL)
+    text_info=windows->widget.font_info;
+  text_width=0;
+  for (i=0; textlist[i] != (char *) NULL; i++)
+    if (WidgetTextWidth(text_info,(char *) textlist[i]) > text_width)
+      text_width=(unsigned int) XTextWidth(text_info,(char *) textlist[i],
+        MagickMin(Extent(textlist[i]),160));
+  lines=(unsigned int) i;
+  width=WidgetTextWidth(font_info,DismissButtonText);
+  width+=QuantumMargin;
+  height=(unsigned int) (text_info->ascent+text_info->descent);
+  /*
+    Position Text View widget.
+  */
+  windows->widget.width=(unsigned int) (MagickMin((int) text_width,
+    (int) MaxTextWidth)+5*QuantumMargin);
+  windows->widget.min_width=(unsigned int) (MinTextWidth+4*QuantumMargin);
+  if (windows->widget.width < windows->widget.min_width)
+    windows->widget.width=windows->widget.min_width;
+  windows->widget.height=(unsigned int) (MagickMin(MagickMax((int) lines,3),32)*
+    height+((13*height) >> 1)+((9*QuantumMargin) >> 1));
+  windows->widget.min_height=(unsigned int) (3*height+((13*height) >> 1)+((9*
+    QuantumMargin) >> 1));
+  if (windows->widget.height < windows->widget.min_height)
+    windows->widget.height=windows->widget.min_height;
+  XConstrainWindowPosition(display,&windows->widget);
+  /*
+    Map Text View widget.
+  */
+  (void) CopyMagickString(windows->widget.name,title,MaxTextExtent);
+  status=XStringListToTextProperty(&windows->widget.name,1,&window_name);
+  if (status != False)
+    {
+      XSetWMName(display,windows->widget.id,&window_name);
+      XSetWMIconName(display,windows->widget.id,&window_name);
+      (void) XFree((void *) window_name.value);
+    }
+  window_changes.width=(int) windows->widget.width;
+  window_changes.height=(int) windows->widget.height;
+  window_changes.x=windows->widget.x;
+  window_changes.y=windows->widget.y;
+  (void) XReconfigureWMWindow(display,windows->widget.id,
+    windows->widget.screen,(unsigned int) mask,&window_changes);
+  (void) XMapRaised(display,windows->widget.id);
+  windows->widget.mapped=MagickFalse;
+  /*
+    Respond to X events.
+  */
+  XGetWidgetInfo((char *) NULL,&slider_info);
+  XGetWidgetInfo((char *) NULL,&north_info);
+  XGetWidgetInfo((char *) NULL,&south_info);
+  XGetWidgetInfo((char *) NULL,&expose_info);
+  visible_lines=0;
+  delay=SuspendTime << 2;
+  height=(unsigned int) (font_info->ascent+font_info->descent);
+  state=UpdateConfigurationState;
+  do
+  {
+    if (state & UpdateConfigurationState)
+      {
+        int
+          id;
+
+        /*
+          Initialize button information.
+        */
+        XGetWidgetInfo(DismissButtonText,&dismiss_info);
+        dismiss_info.width=width;
+        dismiss_info.height=(unsigned int) ((3*height) >> 1);
+        dismiss_info.x=(int) windows->widget.width-dismiss_info.width-
+          QuantumMargin-2;
+        dismiss_info.y=(int) windows->widget.height-dismiss_info.height-
+          QuantumMargin;
+        /*
+          Initialize scroll information.
+        */
+        XGetWidgetInfo((char *) NULL,&scroll_info);
+        scroll_info.bevel_width--;
+        scroll_info.width=height;
+        scroll_info.height=(unsigned int) (dismiss_info.y-((5*QuantumMargin) >>
+          1));
+        scroll_info.x=(int) windows->widget.width-QuantumMargin-
+          scroll_info.width;
+        scroll_info.y=(3*QuantumMargin) >> 1;
+        scroll_info.raised=MagickFalse;
+        scroll_info.trough=MagickTrue;
+        north_info=scroll_info;
+        north_info.raised=MagickTrue;
+        north_info.width-=(north_info.bevel_width << 1);
+        north_info.height=north_info.width-1;
+        north_info.x+=north_info.bevel_width;
+        north_info.y+=north_info.bevel_width;
+        south_info=north_info;
+        south_info.y=scroll_info.y+scroll_info.height-scroll_info.bevel_width-
+          south_info.height;
+        id=slider_info.id;
+        slider_info=north_info;
+        slider_info.id=id;
+        slider_info.width-=2;
+        slider_info.min_y=north_info.y+north_info.height+north_info.bevel_width+
+          slider_info.bevel_width+2;
+        slider_info.height=scroll_info.height-((slider_info.min_y-
+          scroll_info.y+1) << 1)+4;
+        visible_lines=scroll_info.height/(text_info->ascent+text_info->descent+
+          ((text_info->ascent+text_info->descent) >> 3));
+        if (lines > visible_lines)
+          slider_info.height=(unsigned int) (visible_lines*slider_info.height)/
+            lines;
+        slider_info.max_y=south_info.y-south_info.bevel_width-
+          slider_info.bevel_width-2;
+        slider_info.x=scroll_info.x+slider_info.bevel_width+1;
+        slider_info.y=slider_info.min_y;
+        expose_info=scroll_info;
+        expose_info.y=slider_info.y;
+        /*
+          Initialize list information.
+        */
+        XGetWidgetInfo((char *) NULL,&list_info);
+        list_info.raised=MagickFalse;
+        list_info.bevel_width--;
+        list_info.width=(unsigned int) scroll_info.x-((3*QuantumMargin) >> 1);
+        list_info.height=scroll_info.height;
+        list_info.x=QuantumMargin;
+        list_info.y=scroll_info.y;
+        /*
+          Initialize selection information.
+        */
+        XGetWidgetInfo((char *) NULL,&selection_info);
+        selection_info.center=MagickFalse;
+        selection_info.width=list_info.width;
+        selection_info.height=(unsigned int)
+          (9*(text_info->ascent+text_info->descent)) >> 3;
+        selection_info.x=list_info.x;
+        state&=(~UpdateConfigurationState);
+      }
+    if (state & RedrawWidgetState)
+      {
+        /*
+          Redraw Text View window.
+        */
+        XDrawBeveledMatte(display,&windows->widget,&list_info);
+        XDrawBeveledMatte(display,&windows->widget,&scroll_info);
+        XDrawTriangleNorth(display,&windows->widget,&north_info);
+        XDrawBeveledButton(display,&windows->widget,&slider_info);
+        XDrawTriangleSouth(display,&windows->widget,&south_info);
+        XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+        XHighlightWidget(display,&windows->widget,BorderOffset,BorderOffset);
+        selection_info.id=(~0);
+        state|=RedrawListState;
+        state&=(~RedrawWidgetState);
+      }
+    if (state & RedrawListState)
+      {
+        /*
+          Determine slider id and position.
+        */
+        if (slider_info.id >= (int) (lines-visible_lines))
+          slider_info.id=(int) lines-visible_lines;
+        if ((slider_info.id < 0) || (lines <= visible_lines))
+          slider_info.id=0;
+        slider_info.y=slider_info.min_y;
+        if (lines != 0)
+          slider_info.y+=
+            slider_info.id*(slider_info.max_y-slider_info.min_y+1)/lines;
+        if (slider_info.id != selection_info.id)
+          {
+            /*
+              Redraw scroll bar and text.
+            */
+            windows->widget.font_info=text_info;
+            (void) XSetFont(display,windows->widget.annotate_context,
+              text_info->fid);
+            (void) XSetFont(display,windows->widget.highlight_context,
+              text_info->fid);
+            selection_info.id=slider_info.id;
+            selection_info.y=list_info.y+(height >> 3)+2;
+            for (i=0; i < (int) visible_lines; i++)
+            {
+              selection_info.raised=
+                (slider_info.id+i) != list_info.id ? MagickTrue : MagickFalse;
+              selection_info.text=(char *) NULL;
+              if ((slider_info.id+i) < (int) lines)
+                selection_info.text=(char *) textlist[slider_info.id+i];
+              XDrawWidgetText(display,&windows->widget,&selection_info);
+              selection_info.y+=(int) selection_info.height;
+            }
+            windows->widget.font_info=font_info;
+            (void) XSetFont(display,windows->widget.annotate_context,
+              font_info->fid);
+            (void) XSetFont(display,windows->widget.highlight_context,
+              font_info->fid);
+            /*
+              Update slider.
+            */
+            if (slider_info.y > expose_info.y)
+              {
+                expose_info.height=(unsigned int) slider_info.y-expose_info.y;
+                expose_info.y=slider_info.y-expose_info.height-
+                  slider_info.bevel_width-1;
+              }
+            else
+              {
+                expose_info.height=(unsigned int) expose_info.y-slider_info.y;
+                expose_info.y=slider_info.y+slider_info.height+
+                  slider_info.bevel_width+1;
+              }
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+            XDrawMatte(display,&windows->widget,&expose_info);
+            XDrawBeveledButton(display,&windows->widget,&slider_info);
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+            expose_info.y=slider_info.y;
+          }
+        state&=(~RedrawListState);
+      }
+    /*
+      Wait for next event.
+    */
+    if (north_info.raised && south_info.raised)
+      (void) XIfEvent(display,&event,XScreenEvent,(char *) windows);
+    else
+      {
+        /*
+          Brief delay before advancing scroll bar.
+        */
+        XDelay(display,delay);
+        delay=SuspendTime;
+        (void) XCheckIfEvent(display,&event,XScreenEvent,(char *) windows);
+        if (north_info.raised == MagickFalse)
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              slider_info.id--;
+              state|=RedrawListState;
+            }
+        if (south_info.raised == MagickFalse)
+          if (slider_info.id < (int) lines)
+            {
+              /*
+                Move slider down.
+              */
+              slider_info.id++;
+              state|=RedrawListState;
+            }
+        if (event.type != ButtonRelease)
+          continue;
+      }
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        if (MatteIsActive(slider_info,event.xbutton))
+          {
+            /*
+              Track slider.
+            */
+            slider_info.active=MagickTrue;
+            break;
+          }
+        if (MatteIsActive(north_info,event.xbutton))
+          if (slider_info.id > 0)
+            {
+              /*
+                Move slider up.
+              */
+              north_info.raised=MagickFalse;
+              slider_info.id--;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(south_info,event.xbutton))
+          if (slider_info.id < (int) lines)
+            {
+              /*
+                Move slider down.
+              */
+              south_info.raised=MagickFalse;
+              slider_info.id++;
+              state|=RedrawListState;
+              break;
+            }
+        if (MatteIsActive(scroll_info,event.xbutton))
+          {
+            /*
+              Move slider.
+            */
+            if (event.xbutton.y < slider_info.y)
+              slider_info.id-=(visible_lines-1);
+            else
+              slider_info.id+=(visible_lines-1);
+            state|=RedrawListState;
+            break;
+          }
+        if (MatteIsActive(dismiss_info,event.xbutton))
+          {
+            /*
+              User pressed Dismiss button.
+            */
+            dismiss_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            break;
+          }
+        if (MatteIsActive(list_info,event.xbutton))
+          {
+            int
+              id;
+
+            static Time
+              click_time;
+
+            /*
+              User pressed list matte.
+            */
+            id=slider_info.id+(event.xbutton.y-(list_info.y+(height >> 1))+1)/
+              selection_info.height;
+            if (id >= (int) lines)
+              break;
+            if (id != list_info.id)
+              {
+                list_info.id=id;
+                click_time=event.xbutton.time;
+                break;
+              }
+            list_info.id=id;
+            if (event.xbutton.time >= (click_time+DoubleClick))
+              {
+                click_time=event.xbutton.time;
+                break;
+              }
+            click_time=event.xbutton.time;
+            /*
+              Become the XA_PRIMARY selection owner.
+            */
+            (void) CopyMagickString(primary_selection,textlist[list_info.id],
+              MaxTextExtent);
+            (void) XSetSelectionOwner(display,XA_PRIMARY,windows->widget.id,
+              event.xbutton.time);
+            if (XGetSelectionOwner(display,XA_PRIMARY) != windows->widget.id)
+              break;
+            selection_info.id=(~0);
+            list_info.id=id;
+            state|=RedrawListState;
+            break;
+          }
+        break;
+      }
+      case ButtonRelease:
+      {
+        if (windows->widget.mapped == MagickFalse)
+          break;
+        if (north_info.raised == MagickFalse)
+          {
+            /*
+              User released up button.
+            */
+            delay=SuspendTime << 2;
+            north_info.raised=MagickTrue;
+            XDrawTriangleNorth(display,&windows->widget,&north_info);
+          }
+        if (south_info.raised == MagickFalse)
+          {
+            /*
+              User released down button.
+            */
+            delay=SuspendTime << 2;
+            south_info.raised=MagickTrue;
+            XDrawTriangleSouth(display,&windows->widget,&south_info);
+          }
+        if (slider_info.active)
+          {
+            /*
+              Stop tracking slider.
+            */
+            slider_info.active=MagickFalse;
+            break;
+          }
+        if (dismiss_info.raised == MagickFalse)
+          {
+            if (event.xbutton.window == windows->widget.id)
+              if (MatteIsActive(dismiss_info,event.xbutton))
+                state|=ExitState;
+            dismiss_info.raised=MagickTrue;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+          }
+        break;
+      }
+      case ClientMessage:
+      {
+        /*
+          If client window delete message, exit.
+        */
+        if (event.xclient.message_type != windows->wm_protocols)
+          break;
+        if (*event.xclient.data.l == (int) windows->wm_take_focus)
+          {
+            (void) XSetInputFocus(display,event.xclient.window,RevertToParent,
+              (Time) event.xclient.data.l[1]);
+            break;
+          }
+        if (*event.xclient.data.l != (int) windows->wm_delete_window)
+          break;
+        if (event.xclient.window == windows->widget.id)
+          {
+            state|=ExitState;
+            break;
+          }
+        break;
+      }
+      case ConfigureNotify:
+      {
+        /*
+          Update widget configuration.
+        */
+        if (event.xconfigure.window != windows->widget.id)
+          break;
+        if ((event.xconfigure.width == (int) windows->widget.width) &&
+            (event.xconfigure.height == (int) windows->widget.height))
+          break;
+        windows->widget.width=(unsigned int)
+          MagickMax(event.xconfigure.width,(int) windows->widget.min_width);
+        windows->widget.height=(unsigned int)
+          MagickMax(event.xconfigure.height,(int) windows->widget.min_height);
+        state|=UpdateConfigurationState;
+        break;
+      }
+      case EnterNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state&=(~InactiveWidgetState);
+        break;
+      }
+      case Expose:
+      {
+        if (event.xexpose.window != windows->widget.id)
+          break;
+        if (event.xexpose.count != 0)
+          break;
+        state|=RedrawWidgetState;
+        break;
+      }
+      case KeyPress:
+      {
+        static char
+          command[MaxTextExtent];
+
+        static int
+          length;
+
+        static KeySym
+          key_symbol;
+
+        /*
+          Respond to a user key press.
+        */
+        if (event.xkey.window != windows->widget.id)
+          break;
+        length=XLookupString((XKeyEvent *) &event.xkey,command,
+          (int) sizeof(command),&key_symbol,(XComposeStatus *) NULL);
+        *(command+length)='\0';
+        if ((key_symbol == XK_Return) || (key_symbol == XK_KP_Enter))
+          {
+            dismiss_info.raised=MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            state|=ExitState;
+            break;
+          }
+        if (AreaIsActive(scroll_info,event.xkey))
+          {
+            /*
+              Move slider.
+            */
+            switch ((int) key_symbol)
+            {
+              case XK_Home:
+              case XK_KP_Home:
+              {
+                slider_info.id=0;
+                break;
+              }
+              case XK_Up:
+              case XK_KP_Up:
+              {
+                slider_info.id--;
+                break;
+              }
+              case XK_Down:
+              case XK_KP_Down:
+              {
+                slider_info.id++;
+                break;
+              }
+              case XK_Prior:
+              case XK_KP_Prior:
+              {
+                slider_info.id-=visible_lines;
+                break;
+              }
+              case XK_Next:
+              case XK_KP_Next:
+              {
+                slider_info.id+=visible_lines;
+                break;
+              }
+              case XK_End:
+              case XK_KP_End:
+              {
+                slider_info.id=(int) lines;
+                break;
+              }
+            }
+            state|=RedrawListState;
+            break;
+          }
+        break;
+      }
+      case KeyRelease:
+        break;
+      case LeaveNotify:
+      {
+        if (event.xcrossing.window != windows->widget.id)
+          break;
+        state|=InactiveWidgetState;
+        break;
+      }
+      case MapNotify:
+      {
+        mask&=(~CWX);
+        mask&=(~CWY);
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        if (slider_info.active)
+          {
+            /*
+              Move slider matte.
+            */
+            slider_info.y=event.xmotion.y-
+              ((slider_info.height+slider_info.bevel_width) >> 1)+1;
+            if (slider_info.y < slider_info.min_y)
+              slider_info.y=slider_info.min_y;
+            if (slider_info.y > slider_info.max_y)
+              slider_info.y=slider_info.max_y;
+            slider_info.id=0;
+            if (slider_info.y != slider_info.min_y)
+              slider_info.id=(int) (lines*(slider_info.y-slider_info.min_y+1))/
+                (slider_info.max_y-slider_info.min_y+1);
+            state|=RedrawListState;
+            break;
+          }
+        if (state & InactiveWidgetState)
+          break;
+        if (dismiss_info.raised == MatteIsActive(dismiss_info,event.xmotion))
+          {
+            /*
+              Dismiss button status changed.
+            */
+            dismiss_info.raised=
+              dismiss_info.raised == MagickFalse ? MagickTrue : MagickFalse;
+            XDrawBeveledButton(display,&windows->widget,&dismiss_info);
+            break;
+          }
+        break;
+      }
+      case SelectionClear:
+      {
+        list_info.id=(~0);
+        selection_info.id=(~0);
+        state|=RedrawListState;
+        break;
+      }
+      case SelectionRequest:
+      {
+        XSelectionEvent
+          notify;
+
+        XSelectionRequestEvent
+          *request;
+
+        if (list_info.id == (~0))
+          break;
+        /*
+          Set primary selection.
+        */
+        request=(&(event.xselectionrequest));
+        (void) XChangeProperty(request->display,request->requestor,
+          request->property,request->target,8,PropModeReplace,
+          (unsigned char *) primary_selection,Extent(primary_selection));
+        notify.type=SelectionNotify;
+        notify.send_event=MagickTrue;
+        notify.display=request->display;
+        notify.requestor=request->requestor;
+        notify.selection=request->selection;
+        notify.target=request->target;
+        notify.time=request->time;
+        if (request->property == None)
+          notify.property=request->target;
+        else
+          notify.property=request->property;
+        (void) XSendEvent(request->display,request->requestor,False,NoEventMask,
+          (XEvent *) &notify);
+      }
+      default:
+        break;
+    }
+  } while ((state & ExitState) == 0);
+  if (text_info != windows->widget.font_info)
+    (void) XFreeFont(display,text_info);
+  XSetCursorState(display,windows,MagickFalse);
+  (void) XWithdrawWindow(display,windows->widget.id,windows->widget.screen);
+  XCheckRefreshWindows(display,windows);
+}
+#endif
diff --git a/MagickCore/widget.h b/MagickCore/widget.h
new file mode 100644
index 0000000..bcfced2
--- /dev/null
+++ b/MagickCore/widget.h
@@ -0,0 +1,58 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore X11 widget methods.
+*/
+#ifndef _MAGICKCORE_WIDGET_H
+#define _MAGICKCORE_WIDGET_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+
+#include "MagickCore/xwindow-private.h"
+
+extern MagickExport int
+  XCommandWidget(Display *,XWindows *,const char **,XEvent *),
+  XConfirmWidget(Display *,XWindows *,const char *,const char *),
+  XDialogWidget(Display *,XWindows *,const char *,const char *,char *),
+  XMenuWidget(Display *,XWindows *,const char *,const char **,char *);
+
+extern MagickExport MagickBooleanType
+  XPreferencesWidget(Display *,XResourceInfo *,XWindows *);
+
+extern MagickExport void
+  DestroyXWidget(void),
+  XColorBrowserWidget(Display *,XWindows *,const char *,char *),
+  XFileBrowserWidget(Display *,XWindows *,const char *,char *),
+  XFontBrowserWidget(Display *,XWindows *,const char *,char *),
+  XInfoWidget(Display *,XWindows *,const char *),
+  XListBrowserWidget(Display *,XWindows *,XWindowInfo *,const char **,
+    const char *,const char *,char *),
+  XNoticeWidget(Display *,XWindows *,const char *,const char *),
+  XProgressMonitorWidget(Display *,XWindows *,const char *,
+    const MagickOffsetType,const MagickSizeType),
+  XTextViewWidget(Display *,const XResourceInfo *,XWindows *,
+    const MagickBooleanType,const char *,const char **);
+
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/xml-tree.c b/MagickCore/xml-tree.c
new file mode 100644
index 0000000..f7395c5
--- /dev/null
+++ b/MagickCore/xml-tree.c
@@ -0,0 +1,2583 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%                             X   X  M   M  L                                 %
+%                              X X   MM MM  L                                 %
+%                               X    M M M  L                                 %
+%                              X X   M   M  L                                 %
+%                             X   X  M   M  LLLLL                             %
+%                                                                             %
+%                         TTTTT  RRRR   EEEEE  EEEEE                          %
+%                           T    R   R  E      E                              %
+%                           T    RRRR   EEE    EEE                            %
+%                           T    R R    E      E                              %
+%                           T    R  R   EEEEE  EEEEE                          %
+%                                                                             %
+%                                                                             %
+%                              XML Tree Methods                               %
+%                                                                             %
+%                              Software Design                                %
+%                                John Cristy                                  %
+%                               December 2004                                 %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  This module implements the standard handy xml-tree methods for storing and
+%  retrieving nodes and attributes from an XML string.
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/log.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/semaphore.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/token-private.h"
+#include "MagickCore/xml-tree.h"
+#include "MagickCore/utility.h"
+
+/*
+  Define declarations.
+*/
+#define NumberPredefinedEntities  10
+#define XMLWhitespace "\t\r\n "
+
+/*
+  Typedef declarations.
+*/
+struct _XMLTreeInfo
+{
+  char
+    *tag,
+    **attributes,
+    *content;
+
+  size_t
+    offset;
+
+  XMLTreeInfo
+    *parent,
+    *next,
+    *sibling,
+    *ordered,
+    *child;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+typedef struct _XMLTreeRoot
+  XMLTreeRoot;
+
+struct _XMLTreeRoot
+{
+  struct _XMLTreeInfo
+    root;
+
+  XMLTreeInfo
+    *node;
+
+  MagickBooleanType
+    standalone;
+
+  char
+    ***processing_instructions,
+    **entities,
+    ***attributes;
+
+  MagickBooleanType
+    debug;
+
+  SemaphoreInfo
+    *semaphore;
+
+  size_t
+    signature;
+};
+
+/*
+  Global declarations.
+*/
+static char
+  *sentinel[] = { (char *) NULL };
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A d d C h i l d T o X M L T r e e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AddChildToXMLTree() adds a child tag at an offset relative to the start of
+%  the parent tag's character content.  Return the child tag.
+%
+%  The format of the AddChildToXMLTree method is:
+%
+%      XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,const char *tag,
+%        const size_t offset)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o tag: the tag.
+%
+%    o offset: the tag offset.
+%
+*/
+MagickExport XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,
+  const char *tag,const size_t offset)
+{
+  XMLTreeInfo
+    *child;
+
+  if (xml_info == (XMLTreeInfo *) NULL)
+    return((XMLTreeInfo *) NULL);
+  child=(XMLTreeInfo *) AcquireMagickMemory(sizeof(*child));
+  if (child == (XMLTreeInfo *) NULL)
+    return((XMLTreeInfo *) NULL);
+  (void) ResetMagickMemory(child,0,sizeof(*child));
+  child->tag=ConstantString(tag);
+  child->attributes=sentinel;
+  child->content=ConstantString("");
+  child->debug=IsEventLogging();
+  child->signature=MagickSignature;
+  return(InsertTagIntoXMLTree(xml_info,child,offset));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   A d d P a t h T o X M L T r e e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  AddPathToXMLTree() adds a child tag at an offset relative to the start of
+%  the parent tag's character content.  This method returns the child tag.
+%
+%  The format of the AddPathToXMLTree method is:
+%
+%      XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,const char *path,
+%        const size_t offset)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o path: the path.
+%
+%    o offset: the tag offset.
+%
+*/
+MagickExport XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,
+  const char *path,const size_t offset)
+{
+  char
+    **components,
+    subnode[MaxTextExtent],
+    tag[MaxTextExtent];
+
+  register ssize_t
+    i;
+
+  size_t
+    number_components;
+
+  ssize_t
+    j;
+
+  XMLTreeInfo
+    *child,
+    *node;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  node=xml_info;
+  components=GetPathComponents(path,&number_components);
+  if (components == (char **) NULL)
+    return((XMLTreeInfo *) NULL);
+  for (i=0; i < (ssize_t) number_components; i++)
+  {
+    GetPathComponent(components[i],SubimagePath,subnode);
+    GetPathComponent(components[i],CanonicalPath,tag);
+    child=GetXMLTreeChild(node,tag);
+    if (child == (XMLTreeInfo *) NULL)
+      child=AddChildToXMLTree(node,tag,offset);
+    node=child;
+    if (node == (XMLTreeInfo *) NULL)
+      break;
+    for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--)
+    {
+      node=GetXMLTreeOrdered(node);
+      if (node == (XMLTreeInfo *) NULL)
+        break;
+    }
+    if (node == (XMLTreeInfo *) NULL)
+      break;
+    components[i]=DestroyString(components[i]);
+  }
+  for ( ; i < (ssize_t) number_components; i++)
+    components[i]=DestroyString(components[i]);
+  components=(char **) RelinquishMagickMemory(components);
+  return(node);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C a n o n i c a l X M L C o n t e n t                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  CanonicalXMLContent() converts text to canonical XML content by converting
+%  to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding
+%  as base-64 as required.
+%
+%  The format of the CanonicalXMLContent method is:
+%
+%
+%      char *CanonicalXMLContent(const char *content,
+%        const MagickBooleanType pedantic)
+%
+%  A description of each parameter follows:
+%
+%    o content: the content.
+%
+%    o pedantic: if true, replace newlines and tabs with their respective
+%      entities.
+%
+*/
+MagickExport char *CanonicalXMLContent(const char *content,
+  const MagickBooleanType pedantic)
+{
+  char
+    *base64,
+    *canonical_content;
+
+  register const unsigned char
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    extent,
+    length;
+
+  unsigned char
+    *utf8;
+
+  utf8=ConvertLatin1ToUTF8((const unsigned char *) content);
+  if (utf8 == (unsigned char *) NULL)
+    return((char *) NULL);
+  for (p=utf8; *p != '\0'; p++)
+    if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d))
+      break;
+  if (*p != '\0')
+    {
+      /*
+        String is binary, base64-encode it.
+      */
+      base64=Base64Encode(utf8,strlen((char *) utf8),&length);
+      utf8=(unsigned char *) RelinquishMagickMemory(utf8);
+      if (base64 == (char *) NULL)
+        return((char *) NULL);
+      canonical_content=AcquireString("<base64>");
+      (void) ConcatenateString(&canonical_content,base64);
+      base64=DestroyString(base64);
+      (void) ConcatenateString(&canonical_content,"</base64>");
+      return(canonical_content);
+    }
+  /*
+    Substitute predefined entities.
+  */
+  i=0;
+  canonical_content=AcquireString((char *) NULL);
+  extent=MaxTextExtent;
+  for (p=utf8; *p != '\0'; p++)
+  {
+    if ((i+MaxTextExtent) > (ssize_t) extent)
+      {
+        extent+=MaxTextExtent;
+        canonical_content=(char *) ResizeQuantumMemory(canonical_content,extent,
+          sizeof(*canonical_content));
+        if (canonical_content == (char *) NULL)
+          return(canonical_content);
+      }
+    switch (*p)
+    {
+      case '&':
+      {
+        i+=FormatLocaleString(canonical_content+i,extent,"&amp;");
+        break;
+      }
+      case '<':
+      {
+        i+=FormatLocaleString(canonical_content+i,extent,"&lt;");
+        break;
+      }
+      case '>':
+      {
+        i+=FormatLocaleString(canonical_content+i,extent,"&gt;");
+        break;
+      }
+      case '"':
+      {
+        i+=FormatLocaleString(canonical_content+i,extent,"&quot;");
+        break;
+      }
+      case '\n':
+      {
+        if (pedantic == MagickFalse)
+          {
+            canonical_content[i++]=(char) (*p);
+            break;
+          }
+        i+=FormatLocaleString(canonical_content+i,extent,"&#xA;");
+        break;
+      }
+      case '\t':
+      {
+        if (pedantic == MagickFalse)
+          {
+            canonical_content[i++]=(char) (*p);
+            break;
+          }
+        i+=FormatLocaleString(canonical_content+i,extent,"&#x9;");
+        break;
+      }
+      case '\r':
+      {
+        i+=FormatLocaleString(canonical_content+i,extent,"&#xD;");
+        break;
+      }
+      default:
+      {
+        canonical_content[i++]=(char) (*p);
+        break;
+      }
+    }
+  }
+  canonical_content[i]='\0';
+  utf8=(unsigned char *) RelinquishMagickMemory(utf8);
+  return(canonical_content);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y X M L T r e e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyXMLTree() destroys the xml-tree.
+%
+%  The format of the DestroyXMLTree method is:
+%
+%      XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+
+static char **DestroyXMLTreeAttributes(char **attributes)
+{
+  register ssize_t
+    i;
+
+  /*
+    Destroy a tag attribute list.
+  */
+  if ((attributes == (char **) NULL) || (attributes == sentinel))
+    return((char **) NULL);
+  for (i=0; attributes[i] != (char *) NULL; i+=2)
+  {
+    /*
+      Destroy attribute tag and value.
+    */
+    if (attributes[i] != (char *) NULL)
+      attributes[i]=DestroyString(attributes[i]);
+    if (attributes[i+1] != (char *) NULL)
+      attributes[i+1]=DestroyString(attributes[i+1]);
+  }
+  attributes=(char **) RelinquishMagickMemory(attributes);
+  return((char **) NULL);
+}
+
+MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
+{
+  char
+    **attributes;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  XMLTreeRoot
+    *root;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (xml_info->child != (XMLTreeInfo *) NULL)
+    xml_info->child=DestroyXMLTree(xml_info->child);
+  if (xml_info->ordered != (XMLTreeInfo *) NULL)
+    xml_info->ordered=DestroyXMLTree(xml_info->ordered);
+  if (xml_info->parent == (XMLTreeInfo *) NULL)
+    {
+      /*
+        Free root tag allocations.
+      */
+      root=(XMLTreeRoot *) xml_info;
+      for (i=NumberPredefinedEntities; root->entities[i]; i+=2)
+        root->entities[i+1]=DestroyString(root->entities[i+1]);
+      root->entities=(char **) RelinquishMagickMemory(root->entities);
+      for (i=0; root->attributes[i] != (char **) NULL; i++)
+      {
+        attributes=root->attributes[i];
+        if (attributes[0] != (char *) NULL)
+          attributes[0]=DestroyString(attributes[0]);
+        for (j=1; attributes[j] != (char *) NULL; j+=3)
+        {
+          if (attributes[j] != (char *) NULL)
+            attributes[j]=DestroyString(attributes[j]);
+          if (attributes[j+1] != (char *) NULL)
+            attributes[j+1]=DestroyString(attributes[j+1]);
+          if (attributes[j+2] != (char *) NULL)
+            attributes[j+2]=DestroyString(attributes[j+2]);
+        }
+        attributes=(char **) RelinquishMagickMemory(attributes);
+      }
+      if (root->attributes[0] != (char **) NULL)
+        root->attributes=(char ***) RelinquishMagickMemory(root->attributes);
+      if (root->processing_instructions[0] != (char **) NULL)
+        {
+          for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
+          {
+            for (j=0; root->processing_instructions[i][j] != (char *) NULL; j++)
+              root->processing_instructions[i][j]=DestroyString(
+                root->processing_instructions[i][j]);
+            root->processing_instructions[i][j+1]=DestroyString(
+              root->processing_instructions[i][j+1]);
+            root->processing_instructions[i]=(char **) RelinquishMagickMemory(
+              root->processing_instructions[i]);
+          }
+          root->processing_instructions=(char ***) RelinquishMagickMemory(
+            root->processing_instructions);
+        }
+    }
+  xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes);
+  xml_info->content=DestroyString(xml_info->content);
+  xml_info->tag=DestroyString(xml_info->tag);
+  xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info);
+  return((XMLTreeInfo *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t N e x t X M L T r e e T a g                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetNextXMLTreeTag() returns the next tag or NULL if not found.
+%
+%  The format of the GetNextXMLTreeTag method is:
+%
+%      XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
+{
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(xml_info->next);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e A t t r i b u t e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeAttribute() returns the value of the attribute tag with the
+%  specified tag if found, otherwise NULL.
+%
+%  The format of the GetXMLTreeAttribute method is:
+%
+%      const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o tag: the attribute tag.
+%
+*/
+MagickExport const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,
+  const char *tag)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  XMLTreeRoot
+    *root;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (xml_info->attributes == (char **) NULL)
+    return((const char *) NULL);
+  i=0;
+  while ((xml_info->attributes[i] != (char *) NULL) &&
+         (strcmp(xml_info->attributes[i],tag) != 0))
+    i+=2;
+  if (xml_info->attributes[i] != (char *) NULL)
+    return(xml_info->attributes[i+1]);
+  root=(XMLTreeRoot*) xml_info;
+  while (root->root.parent != (XMLTreeInfo *) NULL)
+    root=(XMLTreeRoot *) root->root.parent;
+  i=0;
+  while ((root->attributes[i] != (char **) NULL) &&
+         (strcmp(root->attributes[i][0],xml_info->tag) != 0))
+    i++;
+  if (root->attributes[i] == (char **) NULL)
+    return((const char *) NULL);
+  j=1;
+  while ((root->attributes[i][j] != (char *) NULL) &&
+         (strcmp(root->attributes[i][j],tag) != 0))
+    j+=3;
+  if (root->attributes[i][j] == (char *) NULL)
+    return((const char *) NULL);
+  return(root->attributes[i][j+1]);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e A t t r i b u t e s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeAttributes() injects all attributes associated with the current
+%  tag in the specified splay-tree.
+%
+%  The format of the GetXMLTreeAttributes method is:
+%
+%      MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
+%        SplayTreeInfo *attributes)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o attributes: the attribute splay-tree.
+%
+*/
+MagickExport MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
+  SplayTreeInfo *attributes)
+{
+  register ssize_t
+    i;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((const XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(attributes != (SplayTreeInfo *) NULL);
+  if (xml_info->attributes == (char **) NULL)
+    return(MagickTrue);
+  i=0;
+  while (xml_info->attributes[i] != (char *) NULL)
+  {
+     (void) AddValueToSplayTree(attributes,
+       ConstantString(xml_info->attributes[i]),
+       ConstantString(xml_info->attributes[i+1]));
+    i+=2;
+  }
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e C h i l d                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeChild() returns the first child tag with the specified tag if
+%  found, otherwise NULL.
+%
+%  The format of the GetXMLTreeChild method is:
+%
+%      XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
+{
+  XMLTreeInfo
+    *child;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  child=xml_info->child;
+  if (tag != (const char *) NULL)
+    while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0))
+      child=child->sibling;
+  return(child);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e C o n t e n t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeContent() returns any content associated with specified
+%  xml-tree node.
+%
+%  The format of the GetXMLTreeContent method is:
+%
+%      const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
+{
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(xml_info->content);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e O r d e r e d                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL.
+%
+%  The format of the GetXMLTreeOrdered method is:
+%
+%      XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
+{
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(xml_info->ordered);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e P a t h                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreePath() traverses the XML-tree as defined by the specified path
+%  and returns the node if found, otherwise NULL.
+%
+%  The format of the GetXMLTreePath method is:
+%
+%      XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o path: the path (e.g. property/elapsed-time).
+%
+*/
+MagickExport XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
+{
+  char
+    **components,
+    subnode[MaxTextExtent],
+    tag[MaxTextExtent];
+
+  register ssize_t
+    i;
+
+  size_t
+    number_components;
+
+  ssize_t
+    j;
+
+  XMLTreeInfo
+    *node;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  node=xml_info;
+  components=GetPathComponents(path,&number_components);
+  if (components == (char **) NULL)
+    return((XMLTreeInfo *) NULL);
+  for (i=0; i < (ssize_t) number_components; i++)
+  {
+    GetPathComponent(components[i],SubimagePath,subnode);
+    GetPathComponent(components[i],CanonicalPath,tag);
+    node=GetXMLTreeChild(node,tag);
+    if (node == (XMLTreeInfo *) NULL)
+      break;
+    for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--)
+    {
+      node=GetXMLTreeOrdered(node);
+      if (node == (XMLTreeInfo *) NULL)
+        break;
+    }
+    if (node == (XMLTreeInfo *) NULL)
+      break;
+    components[i]=DestroyString(components[i]);
+  }
+  for ( ; i < (ssize_t) number_components; i++)
+    components[i]=DestroyString(components[i]);
+  components=(char **) RelinquishMagickMemory(components);
+  return(node);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e P r o c e s s i n g I n s t r u c t i o n s           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeProcessingInstructions() returns a null terminated array of
+%  processing instructions for the given target.
+%
+%  The format of the GetXMLTreeProcessingInstructions method is:
+%
+%      const char **GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info,
+%        const char *target)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport const char **GetXMLTreeProcessingInstructions(
+  XMLTreeInfo *xml_info,const char *target)
+{
+  register ssize_t
+    i;
+
+  XMLTreeRoot
+    *root;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  root=(XMLTreeRoot *) xml_info;
+  while (root->root.parent != (XMLTreeInfo *) NULL)
+    root=(XMLTreeRoot *) root->root.parent;
+  i=0;
+  while ((root->processing_instructions[i] != (char **) NULL) &&
+         (strcmp(root->processing_instructions[i][0],target) != 0))
+    i++;
+  if (root->processing_instructions[i] == (char **) NULL)
+    return((const char **) sentinel);
+  return((const char **) (root->processing_instructions[i]+1));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e S i b l i n g                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeSibling() returns the node sibling if found, otherwise NULL.
+%
+%  The format of the GetXMLTreeSibling method is:
+%
+%      XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
+{
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(xml_info->sibling);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   G e t X M L T r e e T a g                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  GetXMLTreeTag() returns the tag associated with specified xml-tree node.
+%
+%  The format of the GetXMLTreeTag method is:
+%
+%      const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
+{
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  return(xml_info->tag);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n s e r t I n t o T a g X M L T r e e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of
+%  the parent tag's character content.  This method returns the child tag.
+%
+%  The format of the InsertTagIntoXMLTree method is:
+%
+%      XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
+%        XMLTreeInfo *child,const size_t offset)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o child: the child tag.
+%
+%    o offset: the tag offset.
+%
+*/
+MagickExport XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
+  XMLTreeInfo *child,const size_t offset)
+{
+  XMLTreeInfo
+    *head,
+    *node,
+    *previous;
+
+  child->ordered=(XMLTreeInfo *) NULL;
+  child->sibling=(XMLTreeInfo *) NULL;
+  child->next=(XMLTreeInfo *) NULL;
+  child->offset=offset;
+  child->parent=xml_info;
+  if (xml_info->child == (XMLTreeInfo *) NULL)
+    {
+      xml_info->child=child;
+      return(child);
+    }
+  head=xml_info->child;
+  if (head->offset > offset)
+    {
+      child->ordered=head;
+      xml_info->child=child;
+    }
+  else
+    {
+      node=head;
+      while ((node->ordered != (XMLTreeInfo *) NULL) &&
+             (node->ordered->offset <= offset))
+        node=node->ordered;
+      child->ordered=node->ordered;
+      node->ordered=child;
+    }
+  previous=(XMLTreeInfo *) NULL;
+  node=head;
+  while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0))
+  {
+    previous=node;
+    node=node->sibling;
+  }
+  if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
+    {
+      while ((node->next != (XMLTreeInfo *) NULL) &&
+             (node->next->offset <= offset))
+        node=node->next;
+      child->next=node->next;
+      node->next=child;
+    }
+  else
+    {
+      if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL))
+        previous->sibling=node->sibling;
+      child->next=node;
+      previous=(XMLTreeInfo *) NULL;
+      node=head;
+      while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
+      {
+        previous=node;
+        node=node->sibling;
+      }
+      child->sibling=node;
+      if (previous != (XMLTreeInfo *) NULL)
+        previous->sibling=child;
+    }
+  return(child);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w X M L T r e e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified
+%  XML string.
+%
+%  The format of the NewXMLTree method is:
+%
+%      XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o xml:  The XML string.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static char *ConvertUTF16ToUTF8(const char *content,size_t *length)
+{
+  char
+    *utf8;
+
+  int
+    bits,
+    byte,
+    c,
+    encoding;
+
+  register ssize_t
+    i;
+
+  size_t
+    extent;
+
+  ssize_t
+    j;
+
+  utf8=(char *) AcquireQuantumMemory(*length,sizeof(*utf8));
+  if (utf8 == (char *) NULL)
+    return((char *) NULL);
+  encoding=(*content == '\xFE') ? 1 : (*content == '\xFF') ? 0 : -1;
+  if (encoding == -1)
+    {
+      /*
+        Already UTF-8.
+      */
+      (void) CopyMagickMemory(utf8,content,*length*sizeof(*utf8));
+      return(utf8);
+    }
+  j=0;
+  extent=(*length);
+  for (i=2; i < (ssize_t) (*length-1); i+=2)
+  {
+    c=(encoding != 0) ? ((content[i] & 0xff) << 8) | (content[i+1] & 0xff) :
+      ((content[i+1] & 0xff) << 8) | (content[i] & 0xff);
+    if ((c >= 0xd800) && (c <= 0xdfff) && ((i+=2) < (ssize_t) (*length-1)))
+      {
+        byte=(encoding != 0) ? ((content[i] & 0xff) << 8) |
+          (content[i+1] & 0xff) : ((content[i+1] & 0xff) << 8) |
+          (content[i] & 0xff);
+        c=(((c & 0x3ff) << 10) | (byte & 0x3ff))+0x10000;
+      }
+    if ((size_t) (j+MaxTextExtent) > extent)
+      {
+        extent=(size_t) j+MaxTextExtent;
+        utf8=(char *) ResizeQuantumMemory(utf8,extent,sizeof(*utf8));
+        if (utf8 == (char *) NULL)
+          return(utf8);
+      }
+    if (c < 0x80)
+      {
+        utf8[j]=c;
+        j++;
+        continue;
+      }
+    /*
+      Multi-byte UTF-8 sequence.
+    */
+    byte=c;
+    for (bits=0; byte != 0; byte/=2)
+      bits++;
+    bits=(bits-2)/5;
+    utf8[j++]=(0xFF << (7-bits)) | (c >> (6*bits));
+    while (bits != 0)
+    {
+      bits--;
+      utf8[j]=0x80 | ((c >> (6*bits)) & 0x3f);
+      j++;
+    }
+  }
+  *length=(size_t) j;
+  return((char *) ResizeQuantumMemory(utf8,*length,sizeof(*utf8)));
+}
+
+static char *ParseEntities(char *xml,char **entities,int state)
+{
+  char
+    *entity;
+
+  int
+    byte,
+    c;
+
+  register char
+    *p,
+    *q;
+
+  register ssize_t
+    i;
+
+  size_t
+    extent,
+    length;
+
+  ssize_t
+    offset;
+
+  /*
+    Normalize line endings.
+  */
+  p=xml;
+  q=xml;
+  for ( ; *xml != '\0'; xml++)
+    while (*xml == '\r')
+    {
+      *(xml++)='\n';
+      if (*xml == '\n')
+        (void) CopyMagickMemory(xml,xml+1,strlen(xml));
+    }
+  for (xml=p; ; )
+  {
+    while ((*xml != '\0') && (*xml != '&') && ((*xml != '%') ||
+           (state != '%')) && (isspace((int) ((unsigned char) *xml) == 0)))
+      xml++;
+    if (*xml == '\0')
+      break;
+    /*
+      States include:
+        '&' for general entity decoding
+        '%' for parameter entity decoding
+        'c' for CDATA sections
+        ' ' for attributes normalization
+        '*' for non-CDATA attributes normalization
+    */
+    if ((state != 'c') && (strncmp(xml,"&#",2) == 0))
+      {
+        /*
+          Character reference.
+        */
+        if (xml[2] != 'x')
+          c=strtol(xml+2,&entity,10);  /* base 10 */
+        else
+          c=strtol(xml+3,&entity,16);  /* base 16 */
+        if ((c == 0) || (*entity != ';'))
+          {
+            /*
+              Not a character reference.
+            */
+            xml++;
+            continue;
+          }
+        if (c < 0x80)
+          *(xml++)=c;
+        else
+          {
+            /*
+              Multi-byte UTF-8 sequence.
+            */
+            byte=c;
+            for (i=0; byte != 0; byte/=2)
+              i++;
+            i=(i-2)/5;
+            *xml=(char) ((0xFF << (7-i)) | (c >> (6*i)));
+            xml++;
+            while (i != 0)
+            {
+              i--;
+              *xml=(char) (0x80 | ((c >> (6*i)) & 0x3F));
+              xml++;
+            }
+          }
+        (void) CopyMagickMemory(xml,strchr(xml,';')+1,strlen(strchr(xml,';')));
+      }
+    else
+      if (((*xml == '&') && ((state == '&') || (state == ' ') ||
+          (state == '*'))) || ((state == '%') && (*xml == '%')))
+        {
+          /*
+            Find entity in the list.
+          */
+          i=0;
+          while ((entities[i] != (char *) NULL) &&
+                 (strncmp(xml+1,entities[i],strlen(entities[i])) != 0))
+            i+=2;
+          if (entities[i++] == (char *) NULL)
+            xml++;
+          else
+            {
+              /*
+                Found a match.
+              */
+              length=strlen(entities[i]);
+              entity=strchr(xml,';');
+              if ((length-1L) >= (size_t) (entity-xml))
+                {
+                  offset=(ssize_t) (xml-p);
+                  extent=(size_t) (offset+length+strlen(entity));
+                  if (p != q)
+                    p=(char *) ResizeQuantumMemory(p,extent,sizeof(*p));
+                  else
+                    {
+                      char
+                        *xml;
+
+                      xml=(char *) AcquireQuantumMemory(extent,sizeof(*xml));
+                      if (xml != (char *) NULL)
+                        {
+                          (void) CopyMagickString(xml,p,extent*sizeof(*xml));
+                          p=xml;
+                        }
+                    }
+                  if (p == (char *) NULL)
+                    ThrowFatalException(ResourceLimitFatalError,
+                      "MemoryAllocationFailed");
+                  xml=p+offset;
+                  entity=strchr(xml,';');
+                }
+              (void) CopyMagickMemory(xml+length,entity+1,strlen(entity));
+              (void) strncpy(xml,entities[i],length);
+            }
+        }
+      else
+        if (((state == ' ') || (state == '*')) &&
+            (isspace((int) ((unsigned char) *xml) != 0)))
+          *(xml++)=' ';
+        else
+          xml++;
+  }
+  if (state == '*')
+    {
+      /*
+        Normalize spaces for non-CDATA attributes.
+      */
+      for (xml=p; *xml != '\0'; xml++)
+      {
+        i=(ssize_t) strspn(xml," ");
+        if (i != 0)
+          (void) CopyMagickMemory(xml,xml+i,strlen(xml+i)+1);
+        while ((*xml != '\0') && (*xml != ' '))
+          xml++;
+      }
+      xml--;
+      if ((xml >= p) && (*xml == ' '))
+        *xml='\0';
+    }
+  return(p == q ? ConstantString(p) : p);
+}
+
+static void ParseCharacterContent(XMLTreeRoot *root,char *xml,
+  const size_t length,const char state)
+{
+  XMLTreeInfo
+    *xml_info;
+
+  xml_info=root->node;
+  if ((xml_info == (XMLTreeInfo *) NULL) || (xml_info->tag == (char *) NULL) ||
+      (length == 0))
+    return;
+  xml[length]='\0';
+  xml=ParseEntities(xml,root->entities,state);
+  if (*xml_info->content != '\0')
+    {
+      (void) ConcatenateString(&xml_info->content,xml);
+      xml=DestroyString(xml);
+    }
+  else
+    {
+      if (xml_info->content != (char *) NULL)
+        xml_info->content=DestroyString(xml_info->content);
+      xml_info->content=xml;
+    }
+}
+
+static XMLTreeInfo *ParseCloseTag(XMLTreeRoot *root,char *tag,
+  char *magick_unused(xml),ExceptionInfo *exception)
+{
+  if ((root->node == (XMLTreeInfo *) NULL) ||
+      (root->node->tag == (char *) NULL) || (strcmp(tag,root->node->tag) != 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "ParseError","unexpected closing tag </%s>",tag);
+      return(&root->root);
+    }
+  root->node=root->node->parent;
+  return((XMLTreeInfo *) NULL);
+}
+
+static MagickBooleanType ValidateEntities(char *tag,char *xml,char **entities)
+{
+  register ssize_t
+    i;
+
+  /*
+    Check for circular entity references.
+  */
+  for ( ; ; xml++)
+  {
+    while ((*xml != '\0') && (*xml != '&'))
+      xml++;
+    if (*xml == '\0')
+      return(MagickTrue);
+    if (strncmp(xml+1,tag,strlen(tag)) == 0)
+      return(MagickFalse);
+    i=0;
+    while ((entities[i] != (char *) NULL) &&
+           (strncmp(entities[i],xml+1,strlen(entities[i]) == 0)))
+      i+=2;
+    if ((entities[i] != (char *) NULL) &&
+        (ValidateEntities(tag,entities[i+1],entities) == 0))
+      return(MagickFalse);
+  }
+  return(MagickTrue);
+}
+
+static void ParseProcessingInstructions(XMLTreeRoot *root,char *xml,
+  size_t length)
+{
+  char
+    *target;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  target=xml;
+  xml[length]='\0';
+  xml+=strcspn(xml,XMLWhitespace);
+  if (*xml != '\0')
+    {
+      *xml='\0';
+      xml+=strspn(xml+1,XMLWhitespace)+1;
+    }
+  if (strcmp(target,"xml") == 0)
+    {
+      xml=strstr(xml,"standalone");
+      if ((xml != (char *) NULL) &&
+          (strncmp(xml+strspn(xml+10,XMLWhitespace "='\"")+10,"yes",3) == 0))
+        root->standalone=MagickTrue;
+      return;
+    }
+  if (root->processing_instructions[0] == (char **) NULL)
+    {
+      root->processing_instructions=(char ***) AcquireMagickMemory(sizeof(
+        *root->processing_instructions));
+      if (root->processing_instructions ==(char ***) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+      *root->processing_instructions=(char **) NULL;
+    }
+  i=0;
+  while ((root->processing_instructions[i] != (char **) NULL) &&
+         (strcmp(target,root->processing_instructions[i][0]) != 0))
+    i++;
+  if (root->processing_instructions[i] == (char **) NULL)
+    {
+      root->processing_instructions=(char ***) ResizeQuantumMemory(
+        root->processing_instructions,(size_t) (i+2),
+        sizeof(*root->processing_instructions));
+      if (root->processing_instructions == (char ***) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+      root->processing_instructions[i]=(char **) AcquireQuantumMemory(3,
+        sizeof(**root->processing_instructions));
+      if (root->processing_instructions[i] == (char **) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+      root->processing_instructions[i+1]=(char **) NULL;
+      root->processing_instructions[i][0]=ConstantString(target);
+      root->processing_instructions[i][1]=(char *)
+        root->processing_instructions[i+1];
+      root->processing_instructions[i+1]=(char **) NULL;
+      root->processing_instructions[i][2]=ConstantString("");
+    }
+  j=1;
+  while (root->processing_instructions[i][j] != (char *) NULL)
+    j++;
+  root->processing_instructions[i]=(char **) ResizeQuantumMemory(
+    root->processing_instructions[i],(size_t) (j+3),
+    sizeof(**root->processing_instructions));
+  if (root->processing_instructions[i] == (char **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  root->processing_instructions[i][j+2]=(char *) ResizeQuantumMemory(
+    root->processing_instructions[i][j+1],(size_t) (j+1),
+    sizeof(**root->processing_instructions));
+  if (root->processing_instructions[i][j+2] == (char *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) CopyMagickString(root->processing_instructions[i][j+2]+j-1,
+    root->root.tag != (char *) NULL ? ">" : "<",2);
+  root->processing_instructions[i][j]=ConstantString(xml);
+  root->processing_instructions[i][j+1]=(char *) NULL;
+}
+
+static MagickBooleanType ParseInternalDoctype(XMLTreeRoot *root,char *xml,
+  size_t length,ExceptionInfo *exception)
+{
+  char
+    *c,
+    **entities,
+    *n,
+    **predefined_entitites,
+    q,
+    *t,
+    *v;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  n=(char *) NULL;
+  predefined_entitites=(char **) AcquireMagickMemory(sizeof(sentinel));
+  if (predefined_entitites == (char **) NULL)
+    ThrowFatalException(ResourceLimitError,"MemoryAllocationFailed");
+  (void) CopyMagickMemory(predefined_entitites,sentinel,sizeof(sentinel));
+  for (xml[length]='\0'; xml != (char *) NULL; )
+  {
+    while ((*xml != '\0') && (*xml != '<') && (*xml != '%'))
+      xml++;
+    if (*xml == '\0')
+      break;
+    if (strncmp(xml,"<!ENTITY",8) == 0)
+      {
+        /*
+          Parse entity definitions.
+        */
+        xml+=strspn(xml+8,XMLWhitespace)+8;
+        c=xml;
+        n=xml+strspn(xml,XMLWhitespace "%");
+        xml=n+strcspn(n,XMLWhitespace);
+        *xml=';';
+        v=xml+strspn(xml+1,XMLWhitespace)+1;
+        q=(*v);
+        v++;
+        if ((q != '"') && (q != '\''))
+          {
+            /*
+              Skip externals.
+            */
+            xml=strchr(xml,'>');
+            continue;
+          }
+        entities=(*c == '%') ? predefined_entitites : root->entities;
+        for (i=0; entities[i] != (char *) NULL; i++) ;
+        entities=(char **) ResizeQuantumMemory(entities,(size_t) (i+3),
+          sizeof(*entities));
+        if (entities == (char **) NULL)
+          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+        if (*c == '%')
+          predefined_entitites=entities;
+        else
+          root->entities=entities;
+        xml++;
+        *xml='\0';
+        xml=strchr(v,q);
+        if (xml != (char *) NULL)
+          {
+            *xml='\0';
+            xml++;
+          }
+        entities[i+1]=ParseEntities(v,predefined_entitites,'%');
+        entities[i+2]=(char *) NULL;
+        if (ValidateEntities(n,entities[i+1],entities) != MagickFalse)
+          entities[i]=n;
+        else
+          {
+            if (entities[i+1] != v)
+              entities[i+1]=DestroyString(entities[i+1]);
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              OptionWarning,"ParseError","circular entity declaration &%s",n);
+            predefined_entitites=(char **) RelinquishMagickMemory(
+              predefined_entitites);
+            return(MagickFalse);
+          }
+        }
+      else
+       if (strncmp(xml,"<!ATTLIST",9) == 0)
+         {
+            /*
+              Parse default attributes.
+            */
+            t=xml+strspn(xml+9,XMLWhitespace)+9;
+            if (*t == '\0')
+              {
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  OptionWarning,"ParseError","unclosed <!ATTLIST");
+                predefined_entitites=(char **) RelinquishMagickMemory(
+                  predefined_entitites);
+                return(MagickFalse);
+              }
+            xml=t+strcspn(t,XMLWhitespace ">");
+            if (*xml == '>')
+              continue;
+            *xml='\0';
+            i=0;
+            while ((root->attributes[i] != (char **) NULL) &&
+                   (strcmp(n,root->attributes[i][0]) != 0))
+              i++;
+            while ((*(n=xml+strspn(xml+1,XMLWhitespace)+1) != '\0') &&
+                   (*n != '>'))
+            {
+              xml=n+strcspn(n,XMLWhitespace);
+              if (*xml != '\0')
+                *xml='\0';
+              else
+                {
+                  (void) ThrowMagickException(exception,GetMagickModule(),
+                    OptionWarning,"ParseError","malformed <!ATTLIST");
+                  predefined_entitites=(char **) RelinquishMagickMemory(
+                    predefined_entitites);
+                  return(MagickFalse);
+                }
+              xml+=strspn(xml+1,XMLWhitespace)+1;
+              c=(char *) (strncmp(xml,"CDATA",5) != 0 ? "*" : " ");
+              if (strncmp(xml,"NOTATION",8) == 0)
+                xml+=strspn(xml+8,XMLWhitespace)+8;
+              xml=(*xml == '(') ? strchr(xml,')') : xml+
+                strcspn(xml,XMLWhitespace);
+              if (xml == (char *) NULL)
+                {
+                  (void) ThrowMagickException(exception,GetMagickModule(),
+                    OptionWarning,"ParseError","malformed <!ATTLIST");
+                  predefined_entitites=(char **) RelinquishMagickMemory(
+                    predefined_entitites);
+                  return(MagickFalse);
+                }
+              xml+=strspn(xml,XMLWhitespace ")");
+              if (strncmp(xml,"#FIXED",6) == 0)
+                xml+=strspn(xml+6,XMLWhitespace)+6;
+              if (*xml == '#')
+                {
+                  xml+=strcspn(xml,XMLWhitespace ">")-1;
+                  if (*c == ' ')
+                    continue;
+                  v=(char *) NULL;
+                }
+              else
+                if (((*xml == '"') || (*xml == '\''))  &&
+                    ((xml=strchr(v=xml+1,*xml)) != (char *) NULL))
+                  *xml='\0';
+                else
+                  {
+                    (void) ThrowMagickException(exception,GetMagickModule(),
+                      OptionWarning,"ParseError","malformed <!ATTLIST");
+                    predefined_entitites=(char **) RelinquishMagickMemory(
+                      predefined_entitites);
+                    return(MagickFalse);
+                  }
+              if (root->attributes[i] == (char **) NULL)
+                {
+                  /*
+                    New attribute tag.
+                  */
+                  if (i == 0)
+                    root->attributes=(char ***) AcquireQuantumMemory(2,
+                      sizeof(*root->attributes));
+                  else
+                    root->attributes=(char ***) ResizeQuantumMemory(
+                      root->attributes,(size_t) (i+2),
+                      sizeof(*root->attributes));
+                  if (root->attributes == (char ***) NULL)
+                    ThrowFatalException(ResourceLimitFatalError,
+                      "MemoryAllocationFailed");
+                  root->attributes[i]=(char **) AcquireQuantumMemory(2,
+                    sizeof(*root->attributes));
+                  if (root->attributes[i] == (char **) NULL)
+                    ThrowFatalException(ResourceLimitFatalError,
+                      "MemoryAllocationFailed");
+                  root->attributes[i][0]=ConstantString(t);
+                  root->attributes[i][1]=(char *) NULL;
+                  root->attributes[i+1]=(char **) NULL;
+                }
+              for (j=1; root->attributes[i][j] != (char *) NULL; j+=3) ;
+              root->attributes[i]=(char **) ResizeQuantumMemory(
+                root->attributes[i],(size_t) (j+4),sizeof(*root->attributes));
+              if (root->attributes[i] == (char **) NULL)
+                ThrowFatalException(ResourceLimitFatalError,
+                  "MemoryAllocationFailed");
+              root->attributes[i][j+3]=(char *) NULL;
+              root->attributes[i][j+2]=ConstantString(c);
+              root->attributes[i][j+1]=(char *) NULL;
+              if (v != (char *) NULL)
+                root->attributes[i][j+1]=ParseEntities(v,root->entities,*c);
+              root->attributes[i][j]=ConstantString(n);
+            }
+        }
+      else
+        if (strncmp(xml, "<!--", 4) == 0)
+          xml=strstr(xml+4,"-->");
+        else
+          if (strncmp(xml,"<?", 2) == 0)
+            {
+              c=xml+2;
+              xml=strstr(c,"?>");
+              if (xml != (char *) NULL)
+                {
+                  ParseProcessingInstructions(root,c,(size_t) (xml-c));
+                  xml++;
+                }
+            }
+           else
+             if (*xml == '<')
+               xml=strchr(xml,'>');
+             else
+               if ((*(xml++) == '%') && (root->standalone == MagickFalse))
+                 break;
+    }
+  predefined_entitites=(char **) RelinquishMagickMemory(predefined_entitites);
+  return(MagickTrue);
+}
+
+static void ParseOpenTag(XMLTreeRoot *root,char *tag,char **attributes)
+{
+  XMLTreeInfo
+    *xml_info;
+
+  xml_info=root->node;
+  if (xml_info->tag == (char *) NULL)
+    xml_info->tag=ConstantString(tag);
+  else
+    xml_info=AddChildToXMLTree(xml_info,tag,strlen(xml_info->content));
+  xml_info->attributes=attributes;
+  root->node=xml_info;
+}
+
+MagickExport XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
+{
+  char
+    **attribute,
+    **attributes,
+    *tag,
+    *utf8;
+
+  int
+    c,
+    terminal;
+
+  MagickBooleanType
+    status;
+
+  register char
+    *p;
+
+  register ssize_t
+    i;
+
+  size_t
+    length;
+
+  ssize_t
+    j,
+    l;
+
+  XMLTreeRoot
+    *root;
+
+  /*
+    Convert xml-string to UTF8.
+  */
+  if ((xml == (const char *) NULL) || (strlen(xml) == 0))
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "ParseError","root tag missing");
+      return((XMLTreeInfo *) NULL);
+    }
+  root=(XMLTreeRoot *) NewXMLTreeTag((char *) NULL);
+  length=strlen(xml);
+  utf8=ConvertUTF16ToUTF8(xml,&length);
+  if (utf8 == (char *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "ParseError","UTF16 to UTF8 failed");
+      return((XMLTreeInfo *) NULL);
+    }
+  terminal=utf8[length-1];
+  utf8[length-1]='\0';
+  p=utf8;
+  while ((*p != '\0') && (*p != '<'))
+    p++;
+  if (*p == '\0')
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "ParseError","root tag missing");
+      utf8=DestroyString(utf8);
+      return((XMLTreeInfo *) NULL);
+    }
+  attribute=(char **) NULL;
+  for (p++; ; p++)
+  {
+    attributes=(char **) sentinel;
+    tag=p;
+    if ((isalpha((int) ((unsigned char) *p)) !=0) || (*p == '_') ||
+        (*p == ':') || (((int) *p) < '\0'))
+      {
+        /*
+          Tag.
+        */
+        if (root->node == (XMLTreeInfo *) NULL)
+          {
+            (void) ThrowMagickException(exception,GetMagickModule(),
+              OptionWarning,"ParseError","root tag missing");
+            utf8=DestroyString(utf8);
+            return(&root->root);
+          }
+        p+=strcspn(p,XMLWhitespace "/>");
+        while (isspace((int) ((unsigned char) *p)) != 0)
+          *p++='\0';
+        if ((*p != '\0') && (*p != '/') && (*p != '>'))
+          {
+            /*
+              Find tag in default attributes list.
+            */
+            i=0;
+            while ((root->attributes[i] != (char **) NULL) &&
+                   (strcmp(root->attributes[i][0],tag) != 0))
+              i++;
+            attribute=root->attributes[i];
+          }
+        for (l=0; (*p != '\0') && (*p != '/') && (*p != '>'); l+=2)
+        {
+          /*
+            Attribute.
+          */
+          if (l == 0)
+            attributes=(char **) AcquireQuantumMemory(4,sizeof(*attributes));
+          else
+            attributes=(char **) ResizeQuantumMemory(attributes,(size_t) (l+4),
+              sizeof(*attributes));
+          if (attributes == (char **) NULL)
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                ResourceLimitError,"MemoryAllocationFailed","`%s'","");
+              utf8=DestroyString(utf8);
+              return(&root->root);
+            }
+          attributes[l+2]=(char *) NULL;
+          attributes[l+1]=(char *) NULL;
+          attributes[l]=p;
+          p+=strcspn(p,XMLWhitespace "=/>");
+          if ((*p != '=') && (isspace((int) ((unsigned char) *p)) == 0))
+            attributes[l]=ConstantString("");
+          else
+            {
+              *p++='\0';
+              p+=strspn(p,XMLWhitespace "=");
+              c=(*p);
+              if ((c == '"') || (c == '\''))
+                {
+                  /*
+                    Attributes value.
+                  */
+                  p++;
+                  attributes[l+1]=p;
+                  while ((*p != '\0') && (*p != c))
+                    p++;
+                  if (*p != '\0')
+                    *p++='\0';
+                  else
+                    {
+                      attributes[l]=ConstantString("");
+                      attributes[l+1]=ConstantString("");
+                      (void) DestroyXMLTreeAttributes(attributes);
+                      (void) ThrowMagickException(exception,GetMagickModule(),
+                        OptionWarning,"ParseError","missing %c",c);
+                      utf8=DestroyString(utf8);
+                      return(&root->root);
+                    }
+                  j=1;
+                  while ((attribute != (char **) NULL) &&
+                         (attribute[j] != (char *) NULL) &&
+                         (strcmp(attribute[j],attributes[l]) != 0))
+                    j+=3;
+                  attributes[l+1]=ParseEntities(attributes[l+1],root->entities,
+                    (attribute != (char **) NULL) && (attribute[j] !=
+                    (char *) NULL) ? *attribute[j+2] : ' ');
+                }
+              attributes[l]=ConstantString(attributes[l]);
+            }
+          while (isspace((int) ((unsigned char) *p)) != 0)
+            p++;
+        }
+        if (*p == '/')
+          {
+            /*
+              Self closing tag.
+            */
+            *p++='\0';
+            if (((*p != '\0') && (*p != '>')) ||
+                ((*p == '\0') && (terminal != '>')))
+              {
+                if (l != 0)
+                  (void) DestroyXMLTreeAttributes(attributes);
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  OptionWarning,"ParseError","missing >");
+                utf8=DestroyString(utf8);
+                return(&root->root);
+              }
+            ParseOpenTag(root,tag,attributes);
+            (void) ParseCloseTag(root,tag,p,exception);
+          }
+        else
+          {
+            c=(*p);
+            if ((*p == '>') || ((*p == '\0') && (terminal == '>')))
+              {
+                *p='\0';
+                ParseOpenTag(root,tag,attributes);
+                *p=c;
+              }
+            else
+              {
+                if (l != 0)
+                  (void) DestroyXMLTreeAttributes(attributes);
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  OptionWarning,"ParseError","missing >");
+                utf8=DestroyString(utf8);
+                return(&root->root);
+              }
+          }
+      }
+    else
+      if (*p == '/')
+        {
+          /*
+            Close tag.
+          */
+          tag=p+1;
+          p+=strcspn(tag,XMLWhitespace ">")+1;
+          c=(*p);
+          if ((c == '\0') && (terminal != '>'))
+            {
+              (void) ThrowMagickException(exception,GetMagickModule(),
+                OptionWarning,"ParseError","missing >");
+              utf8=DestroyString(utf8);
+              return(&root->root);
+            }
+          *p='\0';
+          if (ParseCloseTag(root,tag,p,exception) != (XMLTreeInfo *) NULL)
+            {
+              utf8=DestroyString(utf8);
+              return(&root->root);
+            }
+          *p=c;
+          if (isspace((int) ((unsigned char) *p)) != 0)
+            p+=strspn(p,XMLWhitespace);
+        }
+      else
+        if (strncmp(p,"!--",3) == 0)
+          {
+            /*
+              Comment.
+            */
+            p=strstr(p+3,"--");
+            if ((p == (char *) NULL) || ((*(p+=2) != '>') && (*p != '\0')) ||
+                ((*p == '\0') && (terminal != '>')))
+              {
+                (void) ThrowMagickException(exception,GetMagickModule(),
+                  OptionWarning,"ParseError","unclosed <!--");
+                utf8=DestroyString(utf8);
+                return(&root->root);
+              }
+          }
+        else
+          if (strncmp(p,"![CDATA[",8) == 0)
+            {
+              /*
+                Cdata.
+              */
+              p=strstr(p,"]]>");
+              if (p != (char *) NULL)
+                {
+                  p+=2;
+                  ParseCharacterContent(root,tag+8,(size_t) (p-tag-10),'c');
+                }
+              else
+                {
+                  (void) ThrowMagickException(exception,GetMagickModule(),
+                    OptionWarning,"ParseError","unclosed <![CDATA[");
+                  utf8=DestroyString(utf8);
+                  return(&root->root);
+                }
+            }
+          else
+            if (strncmp(p,"!DOCTYPE",8) == 0)
+              {
+                /*
+                  DTD.
+                */
+                for (l=0; (*p != '\0') && (((l == 0) && (*p != '>')) ||
+                     ((l != 0) && ((*p != ']') ||
+                     (*(p+strspn(p+1,XMLWhitespace)+1) != '>'))));
+                  l=(ssize_t) ((*p == '[') ? 1 : l))
+                p+=strcspn(p+1,"[]>")+1;
+                if ((*p == '\0') && (terminal != '>'))
+                  {
+                    (void) ThrowMagickException(exception,GetMagickModule(),
+                      OptionWarning,"ParseError","unclosed <!DOCTYPE");
+                    utf8=DestroyString(utf8);
+                    return(&root->root);
+                  }
+                if (l != 0)
+                  tag=strchr(tag,'[')+1;
+                if (l != 0)
+                  {
+                    status=ParseInternalDoctype(root,tag,(size_t) (p-tag),
+                      exception);
+                    if (status == MagickFalse)
+                      {
+                        utf8=DestroyString(utf8);
+                        return(&root->root);
+                      }
+                    p++;
+                  }
+              }
+            else
+              if (*p == '?')
+                {
+                  /*
+                    Processing instructions.
+                  */
+                  do
+                  {
+                    p=strchr(p,'?');
+                    if (p == (char *) NULL)
+                      break;
+                    p++;
+                  } while ((*p != '\0') && (*p != '>'));
+                  if ((p == (char *) NULL) || ((*p == '\0') &&
+                      (terminal != '>')))
+                    {
+                      (void) ThrowMagickException(exception,GetMagickModule(),
+                        OptionWarning,"ParseError","unclosed <?");
+                      utf8=DestroyString(utf8);
+                      return(&root->root);
+                    }
+                  ParseProcessingInstructions(root,tag+1,(size_t) (p-tag-2));
+                }
+              else
+                {
+                  (void) ThrowMagickException(exception,GetMagickModule(),
+                    OptionWarning,"ParseError","unexpected <");
+                  utf8=DestroyString(utf8);
+                  return(&root->root);
+                }
+     if ((p == (char *) NULL) || (*p == '\0'))
+       break;
+     *p++='\0';
+     tag=p;
+     if ((*p != '\0') && (*p != '<'))
+       {
+        /*
+          Tag character content.
+        */
+        while ((*p != '\0') && (*p != '<'))
+          p++;
+        if (*p == '\0')
+          break;
+        ParseCharacterContent(root,tag,(size_t) (p-tag),'&');
+      }
+    else
+      if (*p == '\0')
+        break;
+  }
+  utf8=DestroyString(utf8);
+  if (root->node == (XMLTreeInfo *) NULL)
+    return(&root->root);
+  if (root->node->tag == (char *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+        "ParseError","root tag missing");
+      return(&root->root);
+    }
+  (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
+    "ParseError","unclosed tag: `%s'",root->node->tag);
+  return(&root->root);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   N e w X M L T r e e T a g                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  NewXMLTreeTag() returns a new empty xml structure for the xml-tree tag.
+%
+%  The format of the NewXMLTreeTag method is:
+%
+%      XMLTreeInfo *NewXMLTreeTag(const char *tag)
+%
+%  A description of each parameter follows:
+%
+%    o tag: the tag.
+%
+*/
+MagickExport XMLTreeInfo *NewXMLTreeTag(const char *tag)
+{
+  static const char
+    *predefined_entities[NumberPredefinedEntities+1] =
+    {
+      "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
+      "apos;", "&#39;", "amp;", "&#38;", (char *) NULL
+    };
+
+  XMLTreeRoot
+    *root;
+
+  root=(XMLTreeRoot *) AcquireMagickMemory(sizeof(*root));
+  if (root == (XMLTreeRoot *) NULL)
+    return((XMLTreeInfo *) NULL);
+  (void) ResetMagickMemory(root,0,sizeof(*root));
+  root->root.tag=(char *) NULL;
+  if (tag != (char *) NULL)
+    root->root.tag=ConstantString(tag);
+  root->node=(&root->root);
+  root->root.content=ConstantString("");
+  root->entities=(char **) AcquireMagickMemory(sizeof(predefined_entities));
+  if (root->entities == (char **) NULL)
+    return((XMLTreeInfo *) NULL);
+  (void) CopyMagickMemory(root->entities,predefined_entities,
+    sizeof(predefined_entities));
+  root->root.attributes=sentinel;
+  root->attributes=(char ***) root->root.attributes;
+  root->processing_instructions=(char ***) root->root.attributes;
+  root->debug=IsEventLogging();
+  root->signature=MagickSignature;
+  return(&root->root);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   P r u n e T a g F r o m X M L T r e e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  PruneTagFromXMLTree() prunes a tag from the xml-tree along with all its
+%  subtags.
+%
+%  The format of the PruneTagFromXMLTree method is:
+%
+%      XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+MagickExport XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
+{
+  XMLTreeInfo
+    *node;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (xml_info->next != (XMLTreeInfo *) NULL)
+    xml_info->next->sibling=xml_info->sibling;
+  if (xml_info->parent != (XMLTreeInfo *) NULL)
+    {
+      node=xml_info->parent->child;
+      if (node == xml_info)
+        xml_info->parent->child=xml_info->ordered;
+      else
+        {
+          while (node->ordered != xml_info)
+            node=node->ordered;
+          node->ordered=node->ordered->ordered;
+          node=xml_info->parent->child;
+          if (strcmp(node->tag,xml_info->tag) != 0)
+            {
+              while (strcmp(node->sibling->tag,xml_info->tag) != 0)
+                node=node->sibling;
+              if (node->sibling != xml_info)
+                node=node->sibling;
+              else
+                node->sibling=(xml_info->next != (XMLTreeInfo *) NULL) ?
+                  xml_info->next : node->sibling->sibling;
+            }
+          while ((node->next != (XMLTreeInfo *) NULL) &&
+                 (node->next != xml_info))
+            node=node->next;
+          if (node->next != (XMLTreeInfo *) NULL)
+            node->next=node->next->next;
+        }
+    }
+  xml_info->ordered=(XMLTreeInfo *) NULL;
+  xml_info->sibling=(XMLTreeInfo *) NULL;
+  xml_info->next=(XMLTreeInfo *) NULL;
+  return(xml_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t X M L T r e e A t t r i b u t e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetXMLTreeAttribute() sets the tag attributes or adds a new attribute if not
+%  found.  A value of NULL removes the specified attribute.
+%
+%  The format of the SetXMLTreeAttribute method is:
+%
+%      XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag,
+%        const char *value)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o tag:  The attribute tag.
+%
+%    o value:  The attribute value.
+%
+*/
+MagickExport XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,
+  const char *tag,const char *value)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  i=0;
+  while ((xml_info->attributes[i] != (char *) NULL) &&
+         (strcmp(xml_info->attributes[i],tag) != 0))
+    i+=2;
+  if (xml_info->attributes[i] == (char *) NULL)
+    {
+      /*
+        Add new attribute tag.
+      */
+      if (value == (const char *) NULL)
+        return(xml_info);
+      if (xml_info->attributes != sentinel)
+        xml_info->attributes=(char **) ResizeQuantumMemory(
+          xml_info->attributes,(size_t) (i+4),sizeof(*xml_info->attributes));
+      else
+        {
+          xml_info->attributes=(char **) AcquireQuantumMemory(4,
+            sizeof(*xml_info->attributes));
+          if (xml_info->attributes != (char **) NULL)
+            xml_info->attributes[1]=ConstantString("");
+        }
+      if (xml_info->attributes == (char **) NULL)
+        ThrowFatalException(ResourceLimitFatalError,
+          "UnableToAcquireString");
+      xml_info->attributes[i]=ConstantString(tag);
+      xml_info->attributes[i+2]=(char *) NULL;
+      (void) strlen(xml_info->attributes[i+1]);
+    }
+  /*
+    Add new value to an existing attribute.
+  */
+  for (j=i; xml_info->attributes[j] != (char *) NULL; j+=2) ;
+  if (xml_info->attributes[i+1] != (char *) NULL)
+    xml_info->attributes[i+1]=DestroyString(xml_info->attributes[i+1]);
+  if (value != (const char *) NULL)
+    {
+      xml_info->attributes[i+1]=ConstantString(value);
+      return(xml_info);
+    }
+  if (xml_info->attributes[i] != (char *) NULL)
+    xml_info->attributes[i]=DestroyString(xml_info->attributes[i]);
+  (void) CopyMagickMemory(xml_info->attributes+i,xml_info->attributes+i+2,
+    (size_t) (j-i)*sizeof(*xml_info->attributes));
+  j-=2;
+  xml_info->attributes=(char **) ResizeQuantumMemory(xml_info->attributes,
+    (size_t) (j+2),sizeof(*xml_info->attributes));
+  if (xml_info->attributes == (char **) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
+  (void) CopyMagickMemory(xml_info->attributes[j+1]+(i/2),
+    xml_info->attributes[j+1]+(i/2)+1,(size_t) ((j/2)-(i/2))*
+    sizeof(*xml_info->attributes));
+  return(xml_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S e t X M L T r e e C o n t e n t                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetXMLTreeContent() sets the character content for the given tag and
+%  returns the tag.
+%
+%  The format of the SetXMLTreeContent method is:
+%
+%      XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
+%        const char *content)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+%    o content:  The content.
+%
+*/
+MagickExport XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
+  const char *content)
+{
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (xml_info->content != (char *) NULL)
+    xml_info->content=DestroyString(xml_info->content);
+  xml_info->content=(char *) ConstantString(content);
+  return(xml_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M L T r e e I n f o T o X M L                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMLTreeInfoToXML() converts an xml-tree to an XML string.
+%
+%  The format of the XMLTreeInfoToXML method is:
+%
+%      char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
+%
+%  A description of each parameter follows:
+%
+%    o xml_info: the xml info.
+%
+*/
+
+static char *EncodePredefinedEntities(const char *source,ssize_t offset,
+  char **destination,size_t *length,size_t *extent,MagickBooleanType pedantic)
+{
+  char
+    *canonical_content;
+
+  if (offset < 0)
+    canonical_content=CanonicalXMLContent(source,pedantic);
+  else
+    {
+      char
+        *content;
+
+      content=AcquireString(source);
+      content[offset]='\0';
+      canonical_content=CanonicalXMLContent(content,pedantic);
+      content=DestroyString(content);
+    }
+  if (canonical_content == (char *) NULL)
+    return(*destination);
+  if ((*length+strlen(canonical_content)+MaxTextExtent) > *extent)
+    {
+      *extent=(*length)+strlen(canonical_content)+MaxTextExtent;
+      *destination=(char *) ResizeQuantumMemory(*destination,*extent,
+        sizeof(**destination));
+      if (*destination == (char *) NULL)
+        return(*destination);
+    }
+  *length+=FormatLocaleString(*destination+(*length),*extent,"%s",
+    canonical_content);
+  canonical_content=DestroyString(canonical_content);
+  return(*destination);
+}
+
+static char *XMLTreeTagToXML(XMLTreeInfo *xml_info,char **source,size_t *length,
+  size_t *extent,size_t start,char ***attributes)
+{
+  char
+    *content;
+
+  const char
+    *attribute;
+
+  register ssize_t
+    i;
+
+  size_t
+    offset;
+
+  ssize_t
+    j;
+
+  content=(char *) "";
+  if (xml_info->parent != (XMLTreeInfo *) NULL)
+    content=xml_info->parent->content;
+  offset=0;
+  *source=EncodePredefinedEntities(content+start,(ssize_t) (xml_info->offset-
+    start),source,length,extent,MagickFalse);
+  if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent)
+    {
+      *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent;
+      *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(*source));
+      if (*source == (char *) NULL)
+        return(*source);
+    }
+  *length+=FormatLocaleString(*source+(*length),*extent,"<%s",xml_info->tag);
+  for (i=0; xml_info->attributes[i]; i+=2)
+  {
+    attribute=GetXMLTreeAttribute(xml_info,xml_info->attributes[i]);
+    if (attribute != xml_info->attributes[i+1])
+      continue;
+    if ((*length+strlen(xml_info->attributes[i])+MaxTextExtent) > *extent)
+      {
+        *extent=(*length)+strlen(xml_info->attributes[i])+MaxTextExtent;
+        *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
+        if (*source == (char *) NULL)
+          return((char *) NULL);
+      }
+    *length+=FormatLocaleString(*source+(*length),*extent," %s=\"",
+      xml_info->attributes[i]);
+    (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length,
+      extent,MagickTrue);
+    *length+=FormatLocaleString(*source+(*length),*extent,"\"");
+  }
+  i=0;
+  while ((attributes[i] != (char **) NULL) &&
+         (strcmp(attributes[i][0],xml_info->tag) != 0))
+    i++;
+  j=1;
+  while ((attributes[i] != (char **) NULL) &&
+         (attributes[i][j] != (char *) NULL))
+  {
+    if ((attributes[i][j+1] == (char *) NULL) ||
+        (GetXMLTreeAttribute(xml_info,attributes[i][j]) != attributes[i][j+1]))
+      {
+        j+=3;
+        continue;
+      }
+    if ((*length+strlen(attributes[i][j])+MaxTextExtent) > *extent)
+      {
+        *extent=(*length)+strlen(attributes[i][j])+MaxTextExtent;
+        *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
+        if (*source == (char *) NULL)
+          return((char *) NULL);
+      }
+    *length+=FormatLocaleString(*source+(*length),*extent," %s=\"",
+      attributes[i][j]);
+    (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,extent,
+      MagickTrue);
+    *length+=FormatLocaleString(*source+(*length),*extent,"\"");
+    j+=3;
+  }
+  *length+=FormatLocaleString(*source+(*length),*extent,*xml_info->content ?
+    ">" : "/>");
+  if (xml_info->child != (XMLTreeInfo *) NULL)
+    *source=XMLTreeTagToXML(xml_info->child,source,length,extent,0,attributes);
+  else
+    *source=EncodePredefinedEntities(xml_info->content,-1,source,length,extent,
+      MagickFalse);
+  if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent)
+    {
+      *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent;
+      *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
+      if (*source == (char *) NULL)
+        return((char *) NULL);
+    }
+  if (*xml_info->content != '\0')
+    *length+=FormatLocaleString(*source+(*length),*extent,"</%s>",
+      xml_info->tag);
+  while ((content[offset] != '\0') && (offset < xml_info->offset))
+    offset++;
+  if (xml_info->ordered != (XMLTreeInfo *) NULL)
+    content=XMLTreeTagToXML(xml_info->ordered,source,length,extent,offset,
+      attributes);
+  else
+    content=EncodePredefinedEntities(content+offset,-1,source,length,extent,
+      MagickFalse);
+  return(content);
+}
+
+MagickExport char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
+{
+  char
+    *xml;
+
+  register char
+    *p,
+    *q;
+
+  register ssize_t
+    i;
+
+  size_t
+    extent,
+    length;
+
+  ssize_t
+    j,
+    k;
+
+  XMLTreeInfo
+    *ordered,
+    *parent;
+
+  XMLTreeRoot
+    *root;
+
+  assert(xml_info != (XMLTreeInfo *) NULL);
+  assert((xml_info->signature == MagickSignature) ||
+         (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  if (xml_info->tag == (char *) NULL)
+    return((char *) NULL);
+  xml=AcquireString((char *) NULL);
+  length=0;
+  extent=MaxTextExtent;
+  root=(XMLTreeRoot *) xml_info;
+  while (root->root.parent != (XMLTreeInfo *) NULL)
+    root=(XMLTreeRoot *) root->root.parent;
+  parent=(XMLTreeInfo *) NULL;
+  if (xml_info != (XMLTreeInfo *) NULL)
+    parent=xml_info->parent;
+  if (parent == (XMLTreeInfo *) NULL)
+    for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
+    {
+      /*
+        Pre-root processing instructions.
+      */
+      for (k=2; root->processing_instructions[i][k-1]; k++) ;
+      p=root->processing_instructions[i][1];
+      for (j=1; p != (char *) NULL; j++)
+      {
+        if (root->processing_instructions[i][k][j-1] == '>')
+          {
+            p=root->processing_instructions[i][j];
+            continue;
+          }
+        q=root->processing_instructions[i][0];
+        if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent)
+          {
+            extent=length+strlen(p)+strlen(q)+MaxTextExtent;
+            xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml));
+            if (xml == (char *) NULL)
+              return(xml);
+          }
+        length+=FormatLocaleString(xml+length,extent,"<?%s%s%s?>\n",q,
+          *p != '\0' ? " " : "",p);
+        p=root->processing_instructions[i][j];
+      }
+    }
+  ordered=(XMLTreeInfo *) NULL;
+  if (xml_info != (XMLTreeInfo *) NULL)
+    ordered=xml_info->ordered;
+  xml_info->parent=(XMLTreeInfo *) NULL;
+  xml_info->ordered=(XMLTreeInfo *) NULL;
+  xml=XMLTreeTagToXML(xml_info,&xml,&length,&extent,0,root->attributes);
+  xml_info->parent=parent;
+  xml_info->ordered=ordered;
+  if (parent == (XMLTreeInfo *) NULL)
+    for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
+    {
+      /*
+        Post-root processing instructions.
+      */
+      for (k=2; root->processing_instructions[i][k-1]; k++) ;
+      p=root->processing_instructions[i][1];
+      for (j=1; p != (char *) NULL; j++)
+      {
+        if (root->processing_instructions[i][k][j-1] == '<')
+          {
+            p=root->processing_instructions[i][j];
+            continue;
+          }
+        q=root->processing_instructions[i][0];
+        if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent)
+          {
+            extent=length+strlen(p)+strlen(q)+MaxTextExtent;
+            xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml));
+            if (xml == (char *) NULL)
+              return(xml);
+          }
+        length+=FormatLocaleString(xml+length,extent,"\n<?%s%s%s?>",q,
+          *p != '\0' ? " " : "",p);
+        p=root->processing_instructions[i][j];
+      }
+    }
+  return((char *) ResizeQuantumMemory(xml,length+1,sizeof(*xml)));
+}
diff --git a/MagickCore/xml-tree.h b/MagickCore/xml-tree.h
new file mode 100644
index 0000000..64a4053
--- /dev/null
+++ b/MagickCore/xml-tree.h
@@ -0,0 +1,65 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+
+    http://www.imagemagick.org/MagicksToolkit/script/license.php
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  Magick's toolkit xml-tree methods.
+*/
+#ifndef _MAGICKCORE_XML_TREE_H
+#define _MAGICKCORE_XML_TREE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <MagickCore/exception.h>
+#include <MagickCore/splay-tree.h>
+
+typedef struct _XMLTreeInfo
+  XMLTreeInfo;
+
+extern MagickExport char
+  *CanonicalXMLContent(const char *,const MagickBooleanType),
+  *XMLTreeInfoToXML(XMLTreeInfo *);
+
+extern MagickExport const char
+  *GetXMLTreeAttribute(XMLTreeInfo *,const char *),
+  *GetXMLTreeContent(XMLTreeInfo *),
+  **GetXMLTreeProcessingInstructions(XMLTreeInfo *,const char *),
+  *GetXMLTreeTag(XMLTreeInfo *);
+
+extern MagickExport MagickBooleanType
+  GetXMLTreeAttributes(const XMLTreeInfo *,SplayTreeInfo *);
+
+extern MagickExport XMLTreeInfo
+  *AddChildToXMLTree(XMLTreeInfo *,const char *,const size_t),
+  *AddPathToXMLTree(XMLTreeInfo *,const char *,const size_t),
+  *DestroyXMLTree(XMLTreeInfo *),
+  *GetNextXMLTreeTag(XMLTreeInfo *),
+  *GetXMLTreeChild(XMLTreeInfo *,const char *),
+  *GetXMLTreeOrdered(XMLTreeInfo *),
+  *GetXMLTreePath(XMLTreeInfo *,const char *),
+  *GetXMLTreeSibling(XMLTreeInfo *),
+  *InsertTagIntoXMLTree(XMLTreeInfo *,XMLTreeInfo *,const size_t),
+  *NewXMLTree(const char *,ExceptionInfo *),
+  *NewXMLTreeTag(const char *),
+  *ParseTagFromXMLTree(XMLTreeInfo *),
+  *PruneTagFromXMLTree(XMLTreeInfo *),
+  *SetXMLTreeAttribute(XMLTreeInfo *,const char *,const char *),
+  *SetXMLTreeContent(XMLTreeInfo *,const char *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/xwdfile.h_vms b/MagickCore/xwdfile.h_vms
new file mode 100644
index 0000000..6f52d7f
--- /dev/null
+++ b/MagickCore/xwdfile.h_vms
@@ -0,0 +1,109 @@
+/* $XConsortium: XWDFile.h,v 1.17 94/04/17 20:10:49 dpw Exp $ */
+/*
+
+Copyright (c) 1985, 1986  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+/*
+ * XWDFile.h	MIT Project Athena, X Window system window raster
+ *		image dumper, dump file format header file.
+ *
+ *  Author:	Tony Della Fera, DEC
+ *		27-Jun-85
+ * 
+ * Modifier:    William F. Wyatt, SAO
+ *              18-Nov-86  - version 6 for saving/restoring color maps
+ */
+
+#include <X11/Xmd.h>
+
+#define XWD_FILE_VERSION 7
+#define sz_XWDheader 100
+#define sz_XWDColor 12
+
+typedef CARD32 xwdval;		/* for old broken programs */
+
+/* Values in the file are most significant byte first. */
+
+typedef struct _xwd_file_header {
+	/* header_size = SIZEOF(XWDheader) + length of null-terminated
+	 * window name. */
+	CARD32 header_size B32;		
+
+	CARD32 file_version B32;	/* = XWD_FILE_VERSION above */
+	CARD32 pixmap_format B32;	/* ZPixmap or XYPixmap */
+	CARD32 pixmap_depth B32;	/* Pixmap depth */
+	CARD32 pixmap_width B32;	/* Pixmap width */
+	CARD32 pixmap_height B32;	/* Pixmap height */
+	CARD32 xoffset B32;		/* Bitmap x offset, normally 0 */
+	CARD32 byte_order B32;		/* of image data: MSBFirst, LSBFirst */
+
+	/* bitmap_unit applies to bitmaps (depth 1 format XY) only.
+	 * It is the number of bits that each scanline is padded to. */
+	CARD32 bitmap_unit B32;		
+
+	CARD32 bitmap_bit_order B32;	/* bitmaps only: MSBFirst, LSBFirst */
+
+	/* bitmap_pad applies to pixmaps (non-bitmaps) only.
+	 * It is the number of bits that each scanline is padded to. */
+	CARD32 bitmap_pad B32;		
+
+	CARD32 bits_per_pixel B32;	/* Bits per pixel */
+
+	/* bytes_per_line is pixmap_width padded to bitmap_unit (bitmaps)
+	 * or bitmap_pad (pixmaps).  It is the delta (in bytes) to get
+	 * to the same x position on an adjacent row. */
+	CARD32 bytes_per_line B32;
+	CARD32 visual_class B32;	/* Class of colormap */
+	CARD32 red_mask B32;		/* Z red mask */
+	CARD32 green_mask B32;		/* Z green mask */
+	CARD32 blue_mask B32;		/* Z blue mask */
+	CARD32 bits_per_rgb B32;	/* Log2 of distinct color values */
+	CARD32 colormap_entries B32;	/* Number of entries in colormap; not used? */
+	CARD32 ncolors B32;		/* Number of XWDColor structures */
+	CARD32 window_width B32;	/* Window width */
+	CARD32 window_height B32;	/* Window height */
+	CARD32 window_x B32;		/* Window upper left X coordinate */
+	CARD32 window_y B32;		/* Window upper left Y coordinate */
+	CARD32 window_bdrwidth B32;	/* Window border width */
+} XWDFileHeader;
+
+/* Null-terminated window name follows the above structure. */
+
+/* Next comes XWDColor structures, at offset XWDFileHeader.header_size in
+ * the file.  XWDFileHeader.ncolors tells how many XWDColor structures
+ * there are.
+ */
+
+typedef struct {
+        CARD32	pixel B32;
+        CARD16	red B16;
+	CARD16	green B16;
+	CARD16	blue B16;
+        CARD8	flags;
+        CARD8	pad;
+} XWDColor;
+
+/* Last comes the image data in the format described by XWDFileHeader. */
diff --git a/MagickCore/xwindow-private.h b/MagickCore/xwindow-private.h
new file mode 100644
index 0000000..b56a32e
--- /dev/null
+++ b/MagickCore/xwindow-private.h
@@ -0,0 +1,604 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore X11 window methods.
+*/
+#ifndef _MAGICKCORE_XWINDOW_PRIVATE_H
+#define _MAGICKCORE_XWINDOW_PRIVATE_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if defined(MAGICKCORE_X11_DELEGATE)
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include "MagickCore/exception.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/quantize.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+# define klass  c_class
+#else
+# define klass  class
+#endif
+
+/*
+  Invoke pre-X11R6 ICCCM routines if XlibSpecificationRelease is not 6.
+*/
+#if XlibSpecificationRelease < 6
+#if !defined(PRE_R6_ICCCM)
+#define PRE_R6_ICCCM
+#endif
+#endif
+/*
+  Invoke pre-X11R5 ICCCM routines if XlibSpecificationRelease is not defined.
+*/
+#if !defined(XlibSpecificationRelease)
+#define PRE_R5_ICCCM
+#endif
+/*
+  Invoke pre-X11R4 ICCCM routines if PWinGravity is not defined.
+*/
+#if !defined(PWinGravity)
+#define PRE_R4_ICCCM
+#endif
+
+#define MaxIconSize  96
+#define MaxNumberPens  11
+#define MaxNumberFonts  11
+#define MaxXWindows  12
+#undef index
+
+#define ThrowXWindowException(severity,tag,context) \
+{ \
+  ExceptionInfo \
+    exception; \
+ \
+  GetExceptionInfo(&exception); \
+  (void) ThrowMagickException(&exception,GetMagickModule(),severity, \
+    tag == (const char *) NULL ? "unknown" : tag,"`%s': %s",context, \
+    strerror(errno)); \
+  CatchException(&exception); \
+  (void) DestroyExceptionInfo(&exception); \
+}
+#define ThrowXWindowFatalException(severity,tag,context) \
+{ \
+   ThrowXWindowException(severity,tag,context); \
+  _exit(1); \
+}
+
+typedef enum
+{
+  ForegroundStencil,
+  BackgroundStencil,
+  OpaqueStencil,
+  TransparentStencil
+} AnnotationStencil;
+
+typedef enum
+{
+  UndefinedElement,
+  PointElement,
+  LineElement,
+  RectangleElement,
+  FillRectangleElement,
+  CircleElement,
+  FillCircleElement,
+  EllipseElement,
+  FillEllipseElement,
+  PolygonElement,
+  FillPolygonElement,
+  ColorElement,
+  MatteElement,
+  TextElement,
+  ImageElement
+} ElementType;
+
+typedef enum
+{
+  UndefinedColormap,
+  PrivateColormap,
+  SharedColormap
+} XColormapType;
+
+typedef struct _XDrawInfo
+{
+  int
+    x,
+    y;
+
+  unsigned int
+    width,
+    height;
+
+  double
+    degrees;
+
+  AnnotationStencil
+    stencil;
+
+  ElementType
+    element;
+
+  Pixmap
+    stipple;
+
+  unsigned int
+    line_width;
+
+  XSegment
+    line_info;
+
+  unsigned int
+    number_coordinates;
+
+  RectangleInfo
+    rectangle_info;
+
+  XPoint
+    *coordinate_info;
+
+  char
+    geometry[MaxTextExtent];
+} XDrawInfo;
+
+typedef enum
+{
+  DefaultState = 0x0000,
+  EscapeState = 0x0001,
+  ExitState = 0x0002,
+  FormerImageState = 0x0004,
+  ModifierState = 0x0008,
+  MontageImageState = 0x0010,
+  NextImageState = 0x0020,
+  RetainColorsState = 0x0040,
+  SuspendTime = 50,
+  UpdateConfigurationState = 0x0080,
+  UpdateRegionState = 0x0100
+} XState;
+
+typedef struct _XAnnotateInfo
+{
+  int
+    x,
+    y;
+
+  unsigned int
+    width,
+    height;
+
+  double
+    degrees;
+
+  XFontStruct
+    *font_info;
+
+  char
+    *text;
+
+  AnnotationStencil
+    stencil;
+
+  char
+    geometry[MaxTextExtent];
+
+  struct _XAnnotateInfo
+    *next,
+    *previous;
+} XAnnotateInfo;
+
+typedef struct _XPixelInfo
+{
+  ssize_t
+    colors;
+
+  unsigned long
+    *pixels;
+
+  XColor
+    foreground_color,
+    background_color,
+    border_color,
+    matte_color,
+    highlight_color,
+    shadow_color,
+    depth_color,
+    trough_color,
+    box_color,
+    pen_color,
+    pen_colors[MaxNumberPens];
+
+  GC
+    annotate_context,
+    highlight_context,
+    widget_context;
+
+  unsigned short
+    box_index,
+    pen_index;
+} XPixelInfo;
+
+typedef struct _XResourceInfo
+{
+  XrmDatabase
+    resource_database;
+
+  ImageInfo
+    *image_info;
+
+  QuantizeInfo
+    *quantize_info;
+
+  size_t
+    colors;
+
+  MagickBooleanType
+    close_server,
+    backdrop;
+
+  char
+    *background_color,
+    *border_color;
+
+  char
+    *client_name;
+
+  XColormapType
+    colormap;
+
+  unsigned int
+    border_width;
+
+  size_t
+    delay;
+
+  MagickBooleanType
+    color_recovery,
+    confirm_exit,
+    confirm_edit;
+
+  char
+    *display_gamma;
+
+  char
+    *font,
+    *font_name[MaxNumberFonts],
+    *foreground_color;
+
+  MagickBooleanType
+    display_warnings,
+    gamma_correct;
+
+  char
+    *icon_geometry;
+
+  MagickBooleanType
+    iconic,
+    immutable;
+
+  char
+    *image_geometry;
+
+  char
+    *map_type,
+    *matte_color,
+    *name;
+
+  unsigned int
+    magnify,
+    pause;
+
+  char
+    *pen_colors[MaxNumberPens];
+
+  char
+    *text_font,
+    *title;
+
+  int
+    quantum;
+
+  unsigned int
+    update;
+
+  MagickBooleanType
+    use_pixmap,
+    use_shared_memory;
+
+  size_t
+    undo_cache;
+
+  char
+    *visual_type,
+    *window_group,
+    *window_id,
+    *write_filename;
+
+  Image
+    *copy_image;
+
+  int
+    gravity;
+
+  char
+    home_directory[MaxTextExtent];
+} XResourceInfo;
+
+typedef struct _XWindowInfo
+{
+  Window
+    id;
+
+  Window
+    root;
+
+  Visual
+    *visual;
+
+  unsigned int
+    storage_class,
+    depth;
+
+  XVisualInfo
+    *visual_info;
+
+  XStandardColormap
+    *map_info;
+
+  XPixelInfo
+    *pixel_info;
+
+  XFontStruct
+    *font_info;
+
+  GC
+    annotate_context,
+    highlight_context,
+    widget_context;
+
+  Cursor
+    cursor,
+    busy_cursor;
+
+  char
+    *name,
+    *geometry,
+    *icon_name,
+    *icon_geometry,
+    *crop_geometry;
+
+  size_t
+    data,
+    flags;
+
+  int
+    x,
+    y;
+
+  unsigned int
+    width,
+    height,
+    min_width,
+    min_height,
+    width_inc,
+    height_inc,
+    border_width;
+
+  MagickBooleanType
+    use_pixmap,
+    immutable,
+    shape,
+    shared_memory;
+
+  int
+    screen;
+
+  XImage
+    *ximage,
+    *matte_image;
+
+  Pixmap
+    highlight_stipple,
+    shadow_stipple,
+    pixmap,
+    *pixmaps,
+    matte_pixmap,
+    *matte_pixmaps;
+
+  XSetWindowAttributes
+    attributes;
+
+  XWindowChanges
+    window_changes;
+
+  void
+    *segment_info;
+
+  long
+    mask;
+
+  MagickBooleanType
+    orphan,
+    mapped,
+    stasis;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    destroy;
+} XWindowInfo;
+
+typedef struct _XWindows
+{
+  Display
+    *display;
+
+  XStandardColormap
+    *map_info,
+    *icon_map;
+
+  XVisualInfo
+    *visual_info,
+    *icon_visual;
+
+  XPixelInfo
+    *pixel_info,
+    *icon_pixel;
+
+  XFontStruct
+    *font_info;
+
+  XResourceInfo
+    *icon_resources;
+
+  XClassHint
+    *class_hints;
+
+  XWMHints
+    *manager_hints;
+
+  XWindowInfo
+    context,
+    group_leader,
+    backdrop,
+    icon,
+    image,
+    info,
+    magnify,
+    pan,
+    command,
+    widget,
+    popup;
+
+  Atom
+    wm_protocols,
+    wm_delete_window,
+    wm_take_focus,
+    im_protocols,
+    im_remote_command,
+    im_update_widget,
+    im_update_colormap,
+    im_former_image,
+    im_retain_colors,
+    im_next_image,
+    im_exit,
+    dnd_protocols;
+} XWindows;
+
+extern MagickExport char
+  *XGetResourceClass(XrmDatabase,const char *,const char *,char *),
+  *XGetResourceInstance(XrmDatabase,const char *,const char *,const char *),
+  *XGetScreenDensity(Display *);
+
+extern MagickExport Cursor
+  XMakeCursor(Display *,Window,Colormap,char *,char *);
+
+extern MagickExport int
+  XCheckDefineCursor(Display *,Window,Cursor),
+  XError(Display *,XErrorEvent *);
+
+extern MagickExport MagickBooleanType
+  XAnnotateImage(Display *,const XPixelInfo *,XAnnotateInfo *,Image *),
+  XComponentGenesis(void),
+  XDrawImage(Display *,const XPixelInfo *,XDrawInfo *,Image *),
+  XGetWindowColor(Display *,XWindows *,char *),
+  XMagickProgressMonitor(const char *,const MagickOffsetType,
+    const MagickSizeType,void *),
+  XMakeImage(Display *,const XResourceInfo *,XWindowInfo *,Image *,unsigned int,
+    unsigned int),
+  XQueryColorDatabase(const char *,XColor *),
+  XRemoteCommand(Display *,const char *,const char *);
+
+extern MagickExport void
+  DestroyXResources(void),
+  XBestIconSize(Display *,XWindowInfo *,Image *),
+  XBestPixel(Display *,const Colormap,XColor *,unsigned int,XColor *),
+  XCheckRefreshWindows(Display *,XWindows *),
+  XClientMessage(Display *,const Window,const Atom,const Atom,const Time),
+  XComponentTerminus(void),
+  XConfigureImageColormap(Display *,XResourceInfo *,XWindows *,Image *),
+  XConstrainWindowPosition(Display *,XWindowInfo *),
+  XDelay(Display *,const size_t),
+  XDisplayImageInfo(Display *,const XResourceInfo *,XWindows *,Image *,Image *),
+  XDestroyResourceInfo(XResourceInfo *),
+  XDestroyWindowColors(Display *,Window),
+  XFreeResources(Display *,XVisualInfo *,XStandardColormap *,XPixelInfo *,
+    XFontStruct *,XResourceInfo *,XWindowInfo *),
+  XFreeStandardColormap(Display *,const XVisualInfo *,XStandardColormap *,
+    XPixelInfo *),
+  XHighlightEllipse(Display *,Window,GC,const RectangleInfo *),
+  XHighlightLine(Display *,Window,GC,const XSegment *),
+  XHighlightRectangle(Display *,Window,GC,const RectangleInfo *),
+  XGetAnnotateInfo(XAnnotateInfo *),
+  XGetPixelInfo(Display *,const XVisualInfo *,const XStandardColormap *,
+    const XResourceInfo *,Image *,XPixelInfo *),
+  XGetMapInfo(const XVisualInfo *,const Colormap,XStandardColormap *),
+  XGetResourceInfo(const ImageInfo *,XrmDatabase,const char *,XResourceInfo *),
+  XGetWindowInfo(Display *,XVisualInfo *,XStandardColormap *,XPixelInfo *,
+    XFontStruct *,XResourceInfo *,XWindowInfo *),
+  XMakeMagnifyImage(Display *,XWindows *),
+  XMakeStandardColormap(Display *,XVisualInfo *,XResourceInfo *,Image *,
+    XStandardColormap *,XPixelInfo *),
+  XMakeWindow(Display *,Window,char **,int,XClassHint *,XWMHints *,
+    XWindowInfo *),
+  XQueryPosition(Display *,const Window,int *,int *),
+  XRefreshWindow(Display *,const XWindowInfo *,const XEvent *),
+  XRetainWindowColors(Display *,const Window),
+  XSetCursorState(Display *,XWindows *,const MagickStatusType),
+  XUserPreferences(XResourceInfo *),
+  XWarning(const ExceptionType,const char *,const char *);
+
+extern MagickExport Window
+  XWindowByID(Display *,const Window,const size_t),
+  XWindowByName(Display *,const Window,const char *),
+  XWindowByProperty(Display *,const Window,const Atom);
+
+extern MagickExport XFontStruct
+  *XBestFont(Display *,const XResourceInfo *,const MagickBooleanType);
+
+extern MagickExport XrmDatabase
+  XGetResourceDatabase(Display *,const char *);
+
+extern MagickExport XVisualInfo
+  *XBestVisualInfo(Display *,XStandardColormap *,XResourceInfo *);
+
+extern MagickExport XWindows
+  *XInitializeWindows(Display *,XResourceInfo *),
+  *XSetWindows(XWindows *);
+
+static inline MagickRealType XPixelIntensity(const XColor *pixel)
+{
+  MagickRealType
+    intensity;
+
+  intensity=0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue;
+  return(intensity);
+}
+
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif
diff --git a/MagickCore/xwindow.c b/MagickCore/xwindow.c
new file mode 100644
index 0000000..6fe293c
--- /dev/null
+++ b/MagickCore/xwindow.c
@@ -0,0 +1,9768 @@
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%              X   X  W   W  IIIII  N   N  DDDD    OOO   W   W                %
+%               X X   W   W    I    NN  N  D   D  O   O  W   W                %
+%                X    W   W    I    N N N  D   D  O   O  W   W                %
+%               X X   W W W    I    N  NN  D   D  O   O  W W W                %
+%              X   X   W W   IIIII  N   N  DDDD    OOO    W W                 %
+%                                                                             %
+%                                                                             %
+%                       MagickCore X11 Utility Methods                        %
+%                                                                             %
+%                               Software Design                               %
+%                                 John Cristy                                 %
+%                                  July 1992                                  %
+%                                                                             %
+%                                                                             %
+%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  dedicated to making software imaging solutions freely available.           %
+%                                                                             %
+%  You may not use this file except in compliance with the License.  You may  %
+%  obtain a copy of the License at                                            %
+%                                                                             %
+%    http://www.imagemagick.org/script/license.php                            %
+%                                                                             %
+%  Unless required by applicable law or agreed to in writing, software        %
+%  distributed under the License is distributed on an "AS IS" BASIS,          %
+%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
+%  See the License for the specific language governing permissions and        %
+%  limitations under the License.                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%
+*/
+
+/*
+  Include declarations.
+*/
+#include "MagickCore/studio.h"
+#include "MagickCore/animate.h"
+#include "MagickCore/artifact.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/client.h"
+#include "MagickCore/color.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/composite.h"
+#include "MagickCore/display.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/geometry.h"
+#include "MagickCore/identify.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/locale_.h"
+#include "MagickCore/log.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/option.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/PreRvIcccm.h"
+#include "MagickCore/quantize.h"
+#include "MagickCore/quantum.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/resource_.h"
+#include "MagickCore/resize.h"
+#include "MagickCore/shear.h"
+#include "MagickCore/statistic.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
+#include "MagickCore/transform.h"
+#include "MagickCore/utility.h"
+#include "MagickCore/widget.h"
+#include "MagickCore/xwindow.h"
+#include "MagickCore/xwindow-private.h"
+#include "MagickCore/version.h"
+#if defined(__BEOS__)
+#include <OS.h>
+#endif
+#if defined(MAGICKCORE_X11_DELEGATE)
+#include <X11/Xproto.h>
+#include <X11/Xlocale.h>
+#if defined(MAGICK_HAVE_POLL)
+# include <sys/poll.h>
+#endif
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+#if defined(MAGICKCORE_HAVE_MACHINE_PARAM_H)
+# include <machine/param.h>
+#endif
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#endif
+#if defined(MAGICKCORE_HAVE_SHAPE)
+#include <X11/extensions/shape.h>
+#endif
+
+/*
+  X defines.
+*/
+#define XBlueGamma(color) ClampToQuantum(blue_gamma == 1.0 ? (double) \
+  (color) : ((pow(((double) QuantumScale*(color)),1.0/(double) blue_gamma)* \
+  QuantumRange)))
+#define XGammaPacket(map,color)  (size_t) (map->base_pixel+ \
+  ((ScaleQuantumToShort(XRedGamma((color)->red))*map->red_max/65535L)* \
+    map->red_mult)+ \
+  ((ScaleQuantumToShort(XGreenGamma((color)->green))*map->green_max/65535L)* \
+    map->green_mult)+ \
+  ((ScaleQuantumToShort(XBlueGamma((color)->blue))*map->blue_max/65535L)* \
+    map->blue_mult))
+#define XGammaPixel(image,map,color)  (size_t) (map->base_pixel+ \
+  ((ScaleQuantumToShort(XRedGamma(GetPixelRed(image,color)))*map->red_max/65535L)* \
+    map->red_mult)+ \
+  ((ScaleQuantumToShort(XGreenGamma(GetPixelGreen(image,color)))*map->green_max/65535L)* \
+    map->green_mult)+ \
+  ((ScaleQuantumToShort(XBlueGamma(GetPixelBlue(image,color)))*map->blue_max/65535L)* \
+    map->blue_mult))
+#define XGreenGamma(color) ClampToQuantum(green_gamma == 1.0 ? (double) \
+  (color) : ((pow(((double) QuantumScale*(color)),1.0/(double) green_gamma)* \
+  QuantumRange)))
+#define XRedGamma(color) ClampToQuantum(red_gamma == 1.0 ? (double) \
+  (color) : ((pow(((double) QuantumScale*(color)),1.0/(double) red_gamma)* \
+  QuantumRange)))
+#define XStandardPixel(map,color)  (size_t) (map->base_pixel+ \
+  (((color)->red*map->red_max/65535L)*map->red_mult)+ \
+  (((color)->green*map->green_max/65535L)*map->green_mult)+ \
+  (((color)->blue*map->blue_max/65535L)*map->blue_mult))
+
+#define AccentuateModulate  ScaleCharToQuantum(80)
+#define HighlightModulate  ScaleCharToQuantum(125)
+#define ShadowModulate  ScaleCharToQuantum(135)
+#define DepthModulate  ScaleCharToQuantum(185)
+#define TroughModulate  ScaleCharToQuantum(110)
+
+#define XLIB_ILLEGAL_ACCESS  1
+#undef ForgetGravity
+#undef NorthWestGravity
+#undef NorthGravity
+#undef NorthEastGravity
+#undef WestGravity
+#undef CenterGravity
+#undef EastGravity
+#undef SouthWestGravity
+#undef SouthGravity
+#undef SouthEastGravity
+#undef StaticGravity
+
+#undef index
+#if defined(hpux9)
+#define XFD_SET  int
+#else
+#define XFD_SET  fd_set
+#endif
+
+/*
+  Enumeration declarations.
+*/
+typedef enum
+{
+#undef DoRed
+  DoRed = 0x0001,
+#undef DoGreen
+  DoGreen = 0x0002,
+#undef DoBlue
+  DoBlue = 0x0004,
+  DoMatte = 0x0008
+} XColorFlags;
+
+/*
+  Typedef declarations.
+*/
+typedef struct _DiversityPacket
+{
+  Quantum
+    red,
+    green,
+    blue;
+
+  unsigned short
+    index;
+
+  size_t
+    count;
+} DiversityPacket;
+
+/*
+  Constant declaractions.
+*/
+static MagickBooleanType
+  xerror_alert = MagickFalse;
+
+/*
+  Method prototypes.
+*/
+static const char
+  *XVisualClassName(const int);
+
+static MagickRealType
+  blue_gamma = 1.0,
+  green_gamma = 1.0,
+  red_gamma = 1.0;
+
+static MagickBooleanType
+  XMakePixmap(Display *,const XResourceInfo *,XWindowInfo *);
+
+static void
+  XMakeImageLSBFirst(const XResourceInfo *,const XWindowInfo *,Image *,
+    XImage *,XImage *),
+  XMakeImageMSBFirst(const XResourceInfo *,const XWindowInfo *,Image *,
+    XImage *,XImage *);
+
+static Window
+  XSelectWindow(Display *,RectangleInfo *);
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   D e s t r o y X R e s o u r c e s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  DestroyXResources() destroys any X resources.
+%
+%  The format of the DestroyXResources method is:
+%
+%      void DestroyXResources()
+%
+%  A description of each parameter follows:
+%
+*/
+MagickExport void DestroyXResources(void)
+{
+  register int
+    i;
+
+  unsigned int
+    number_windows;
+
+  XWindowInfo
+    *magick_windows[MaxXWindows];
+
+  XWindows
+    *windows;
+
+  DestroyXWidget();
+  windows=XSetWindows((XWindows *) ~0);
+  if ((windows == (XWindows *) NULL) || (windows->display == (Display *) NULL))
+    return;
+  number_windows=0;
+  magick_windows[number_windows++]=(&windows->context);
+  magick_windows[number_windows++]=(&windows->group_leader);
+  magick_windows[number_windows++]=(&windows->backdrop);
+  magick_windows[number_windows++]=(&windows->icon);
+  magick_windows[number_windows++]=(&windows->image);
+  magick_windows[number_windows++]=(&windows->info);
+  magick_windows[number_windows++]=(&windows->magnify);
+  magick_windows[number_windows++]=(&windows->pan);
+  magick_windows[number_windows++]=(&windows->command);
+  magick_windows[number_windows++]=(&windows->widget);
+  magick_windows[number_windows++]=(&windows->popup);
+  magick_windows[number_windows++]=(&windows->context);
+  for (i=0; i < (int) number_windows; i++)
+  {
+    if (magick_windows[i]->mapped != MagickFalse)
+      {
+        (void) XWithdrawWindow(windows->display,magick_windows[i]->id,
+          magick_windows[i]->screen);
+        magick_windows[i]->mapped=MagickFalse;
+      }
+    if (magick_windows[i]->name != (char *) NULL)
+      magick_windows[i]->name=(char *)
+        RelinquishMagickMemory(magick_windows[i]->name);
+    if (magick_windows[i]->icon_name != (char *) NULL)
+      magick_windows[i]->icon_name=(char *)
+        RelinquishMagickMemory(magick_windows[i]->icon_name);
+    if (magick_windows[i]->cursor != (Cursor) NULL)
+      {
+        (void) XFreeCursor(windows->display,magick_windows[i]->cursor);
+        magick_windows[i]->cursor=(Cursor) NULL;
+      }
+    if (magick_windows[i]->busy_cursor != (Cursor) NULL)
+      {
+        (void) XFreeCursor(windows->display,magick_windows[i]->busy_cursor);
+        magick_windows[i]->busy_cursor=(Cursor) NULL;
+      }
+    if (magick_windows[i]->highlight_stipple != (Pixmap) NULL)
+      {
+        (void) XFreePixmap(windows->display,
+          magick_windows[i]->highlight_stipple);
+        magick_windows[i]->highlight_stipple=(Pixmap) NULL;
+      }
+    if (magick_windows[i]->shadow_stipple != (Pixmap) NULL)
+      {
+        (void) XFreePixmap(windows->display,magick_windows[i]->shadow_stipple);
+        magick_windows[i]->shadow_stipple=(Pixmap) NULL;
+      }
+    if (magick_windows[i]->ximage != (XImage *) NULL)
+      {
+        XDestroyImage(magick_windows[i]->ximage);
+        magick_windows[i]->ximage=(XImage *) NULL;
+      }
+    if (magick_windows[i]->pixmap != (Pixmap) NULL)
+      {
+        (void) XFreePixmap(windows->display,magick_windows[i]->pixmap);
+        magick_windows[i]->pixmap=(Pixmap) NULL;
+      }
+    if (magick_windows[i]->id != (Window) NULL)
+      {
+        (void) XDestroyWindow(windows->display,magick_windows[i]->id);
+        magick_windows[i]->id=(Window) NULL;
+      }
+    if (magick_windows[i]->destroy != MagickFalse)
+      {
+        if (magick_windows[i]->image != (Image *) NULL)
+          {
+            magick_windows[i]->image=DestroyImage(magick_windows[i]->image);
+            magick_windows[i]->image=NewImageList();
+          }
+        if (magick_windows[i]->matte_pixmap != (Pixmap) NULL)
+          {
+            (void) XFreePixmap(windows->display,
+              magick_windows[i]->matte_pixmap);
+            magick_windows[i]->matte_pixmap=(Pixmap) NULL;
+          }
+      }
+    if (magick_windows[i]->segment_info != (void *) NULL)
+      {
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+        XShmSegmentInfo
+          *segment_info;
+
+        segment_info=(XShmSegmentInfo *) magick_windows[i]->segment_info;
+        if (segment_info != (XShmSegmentInfo *) NULL)
+          if (segment_info[0].shmid >= 0)
+            {
+              if (segment_info[0].shmaddr != NULL)
+                (void) shmdt(segment_info[0].shmaddr);
+              (void) shmctl(segment_info[0].shmid,IPC_RMID,0);
+              segment_info[0].shmaddr=NULL;
+              segment_info[0].shmid=(-1);
+            }
+#endif
+        magick_windows[i]->segment_info=(void *)
+          RelinquishMagickMemory(magick_windows[i]->segment_info);
+      }
+  }
+  windows->icon_resources=(XResourceInfo *)
+    RelinquishMagickMemory(windows->icon_resources);
+  if (windows->icon_pixel != (XPixelInfo *) NULL)
+    {
+      if (windows->icon_pixel->pixels != (unsigned long *) NULL)
+        windows->icon_pixel->pixels=(unsigned long *)
+          RelinquishMagickMemory(windows->icon_pixel->pixels);
+      if (windows->icon_pixel->annotate_context != (GC) NULL)
+        XFreeGC(windows->display,windows->icon_pixel->annotate_context);
+      windows->icon_pixel=(XPixelInfo *)
+        RelinquishMagickMemory(windows->icon_pixel);
+    }
+  if (windows->pixel_info != (XPixelInfo *) NULL)
+    {
+      if (windows->pixel_info->pixels != (unsigned long *) NULL)
+        windows->pixel_info->pixels=(unsigned long *)
+          RelinquishMagickMemory(windows->pixel_info->pixels);
+      if (windows->pixel_info->annotate_context != (GC) NULL)
+        XFreeGC(windows->display,windows->pixel_info->annotate_context);
+      if (windows->pixel_info->widget_context != (GC) NULL)
+        XFreeGC(windows->display,windows->pixel_info->widget_context);
+      if (windows->pixel_info->highlight_context != (GC) NULL)
+        XFreeGC(windows->display,windows->pixel_info->highlight_context);
+      windows->pixel_info=(XPixelInfo *)
+        RelinquishMagickMemory(windows->pixel_info);
+    }
+  if (windows->font_info != (XFontStruct *) NULL)
+    {
+      XFreeFont(windows->display,windows->font_info);
+      windows->font_info=(XFontStruct *) NULL;
+    }
+  if (windows->class_hints != (XClassHint *) NULL)
+    {
+      if (windows->class_hints->res_name != (char *) NULL)
+        XFree(windows->class_hints->res_name);
+      if (windows->class_hints->res_class != (char *) NULL)
+        XFree(windows->class_hints->res_class);
+      XFree(windows->class_hints);
+      windows->class_hints=(XClassHint *) NULL;
+    }
+  if (windows->manager_hints != (XWMHints *) NULL)
+    {
+      XFree(windows->manager_hints);
+      windows->manager_hints=(XWMHints *) NULL;
+    }
+  if (windows->map_info != (XStandardColormap *) NULL)
+    {
+      XFree(windows->map_info);
+      windows->map_info=(XStandardColormap *) NULL;
+    }
+  if (windows->icon_map != (XStandardColormap *) NULL)
+    {
+      XFree(windows->icon_map);
+      windows->icon_map=(XStandardColormap *) NULL;
+    }
+  if (windows->visual_info != (XVisualInfo *) NULL)
+    {
+      XFree(windows->visual_info);
+      windows->visual_info=(XVisualInfo *) NULL;
+    }
+  if (windows->icon_visual != (XVisualInfo *) NULL)
+    {
+      XFree(windows->icon_visual);
+      windows->icon_visual=(XVisualInfo *) NULL;
+    }
+  (void) XSetWindows((XWindows *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X A n n o t a t e I m a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XAnnotateImage() annotates the image with text.
+%
+%  The format of the XAnnotateImage method is:
+%
+%      MagickBooleanType XAnnotateImage(Display *display,
+%        const XPixelInfo *pixel,XAnnotateInfo *annotate_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+%    o annotate_info: Specifies a pointer to a XAnnotateInfo structure.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType XAnnotateImage(Display *display,
+  const XPixelInfo *pixel,XAnnotateInfo *annotate_info,Image *image)
+{
+  CacheView
+    *annotate_view;
+
+  GC
+    annotate_context;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *annotate_image;
+
+  int
+    x,
+    y;
+
+  MagickBooleanType
+    matte;
+
+  Pixmap
+    annotate_pixmap;
+
+  unsigned int
+    depth,
+    height,
+    width;
+
+  Window
+    root_window;
+
+  XGCValues
+    context_values;
+
+  XImage
+    *annotate_ximage;
+
+  /*
+    Initialize annotated image.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(pixel != (XPixelInfo *) NULL);
+  assert(annotate_info != (XAnnotateInfo *) NULL);
+  assert(image != (Image *) NULL);
+  /*
+    Initialize annotated pixmap.
+  */
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  depth=(unsigned int) XDefaultDepth(display,XDefaultScreen(display));
+  annotate_pixmap=XCreatePixmap(display,root_window,annotate_info->width,
+    annotate_info->height,depth);
+  if (annotate_pixmap == (Pixmap) NULL)
+    return(MagickFalse);
+  /*
+    Initialize graphics info.
+  */
+  context_values.background=0;
+  context_values.foreground=(size_t) (~0);
+  context_values.font=annotate_info->font_info->fid;
+  annotate_context=XCreateGC(display,root_window,(unsigned long)
+    (GCBackground | GCFont | GCForeground),&context_values);
+  if (annotate_context == (GC) NULL)
+    return(MagickFalse);
+  /*
+    Draw text to pixmap.
+  */
+  (void) XDrawImageString(display,annotate_pixmap,annotate_context,0,
+    (int) annotate_info->font_info->ascent,annotate_info->text,
+    (int) strlen(annotate_info->text));
+  (void) XFreeGC(display,annotate_context);
+  /*
+    Initialize annotated X image.
+  */
+  annotate_ximage=XGetImage(display,annotate_pixmap,0,0,annotate_info->width,
+    annotate_info->height,AllPlanes,ZPixmap);
+  if (annotate_ximage == (XImage *) NULL)
+    return(MagickFalse);
+  (void) XFreePixmap(display,annotate_pixmap);
+  /*
+    Initialize annotated image.
+  */
+  annotate_image=AcquireImage((ImageInfo *) NULL);
+  if (annotate_image == (Image *) NULL)
+    return(MagickFalse);
+  annotate_image->columns=annotate_info->width;
+  annotate_image->rows=annotate_info->height;
+  /*
+    Transfer annotated X image to image.
+  */
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  (void) XParseGeometry(annotate_info->geometry,&x,&y,&width,&height);
+  (void) GetOneVirtualPixel(image,(ssize_t) x,(ssize_t) y,
+    &annotate_image->background_color,&image->exception);
+  if (annotate_info->stencil == ForegroundStencil)
+    annotate_image->matte=MagickTrue;
+  exception=(&image->exception);
+  annotate_view=AcquireCacheView(annotate_image);
+  for (y=0; y < (int) annotate_image->rows; y++)
+  {
+    register int
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=GetCacheViewAuthenticPixels(annotate_view,0,(ssize_t) y,
+      annotate_image->columns,1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (int) annotate_image->columns; x++)
+    {
+      SetPixelAlpha(annotate_image,OpaqueAlpha,q);
+      if (XGetPixel(annotate_ximage,x,y) == 0)
+        {
+          /*
+            Set this pixel to the background color.
+          */
+          SetPixelRed(annotate_image,ScaleShortToQuantum(
+            pixel->box_color.red),q);
+          SetPixelGreen(annotate_image,ScaleShortToQuantum(
+            pixel->box_color.green),q);
+          SetPixelBlue(annotate_image,ScaleShortToQuantum(
+            pixel->box_color.blue),q);
+          if ((annotate_info->stencil == ForegroundStencil) ||
+              (annotate_info->stencil == OpaqueStencil))
+            SetPixelAlpha(annotate_image,TransparentAlpha,q);
+        }
+      else
+        {
+          /*
+            Set this pixel to the pen color.
+          */
+          SetPixelRed(annotate_image,ScaleShortToQuantum(
+            pixel->pen_color.red),q);
+          SetPixelGreen(annotate_image,ScaleShortToQuantum(
+            pixel->pen_color.green),q);
+          SetPixelBlue(annotate_image,ScaleShortToQuantum(
+            pixel->pen_color.blue),q);
+          if (annotate_info->stencil == BackgroundStencil)
+            SetPixelAlpha(annotate_image,TransparentAlpha,q);
+        }
+      q+=GetPixelChannels(annotate_image);
+    }
+    if (SyncCacheViewAuthenticPixels(annotate_view,exception) == MagickFalse)
+      break;
+  }
+  annotate_view=DestroyCacheView(annotate_view);
+  XDestroyImage(annotate_ximage);
+  /*
+    Determine annotate geometry.
+  */
+  (void) XParseGeometry(annotate_info->geometry,&x,&y,&width,&height);
+  if ((width != (unsigned int) annotate_image->columns) ||
+      (height != (unsigned int) annotate_image->rows))
+    {
+      char
+        image_geometry[MaxTextExtent];
+
+      /*
+        Scale image.
+      */
+      (void) FormatLocaleString(image_geometry,MaxTextExtent,"%ux%u",
+        width,height);
+      (void) TransformImage(&annotate_image,(char *) NULL,image_geometry);
+    }
+  if (annotate_info->degrees != 0.0)
+    {
+      Image
+        *rotate_image;
+
+      int
+        rotations;
+
+      MagickRealType
+        normalized_degrees;
+
+      /*
+        Rotate image.
+      */
+      rotate_image=
+        RotateImage(annotate_image,annotate_info->degrees,&image->exception);
+      if (rotate_image == (Image *) NULL)
+        return(MagickFalse);
+      annotate_image=DestroyImage(annotate_image);
+      annotate_image=rotate_image;
+      /*
+        Annotation is relative to the degree of rotation.
+      */
+      normalized_degrees=annotate_info->degrees;
+      while (normalized_degrees < -45.0)
+        normalized_degrees+=360.0;
+      for (rotations=0; normalized_degrees > 45.0; rotations++)
+        normalized_degrees-=90.0;
+      switch (rotations % 4)
+      {
+        default:
+        case 0:
+          break;
+        case 1:
+        {
+          /*
+            Rotate 90 degrees.
+          */
+          x-=(int) annotate_image->columns/2;
+          y+=(int) annotate_image->columns/2;
+          break;
+        }
+        case 2:
+        {
+          /*
+            Rotate 180 degrees.
+          */
+          x=x-(int) annotate_image->columns;
+          break;
+        }
+        case 3:
+        {
+          /*
+            Rotate 270 degrees.
+          */
+          x=x-(int) annotate_image->columns/2;
+          y=y-(int) (annotate_image->rows-(annotate_image->columns/2));
+          break;
+        }
+      }
+    }
+  /*
+    Composite text onto the image.
+  */
+  (void) XParseGeometry(annotate_info->geometry,&x,&y,&width,&height);
+  matte=image->matte;
+  (void) CompositeImage(image,annotate_image->matte != MagickFalse ?
+    OverCompositeOp : CopyCompositeOp,annotate_image,(ssize_t) x,(ssize_t) y);
+  image->matte=matte;
+  annotate_image=DestroyImage(annotate_image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X B e s t F o n t                                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XBestFont() returns the "best" font.  "Best" is defined as a font specified
+%  in the X resource database or a font such that the text width displayed
+%  with the font does not exceed the specified maximum width.
+%
+%  The format of the XBestFont method is:
+%
+%      XFontStruct *XBestFont(Display *display,
+%        const XResourceInfo *resource_info,const MagickBooleanType text_font)
+%
+%  A description of each parameter follows:
+%
+%    o font: XBestFont returns a pointer to a XFontStruct structure.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o text_font:  True is font should be mono-spaced (typewriter style).
+%
+*/
+
+static char **FontToList(char *font)
+{
+  char
+    **fontlist;
+
+  register char
+    *p,
+    *q;
+
+  register int
+    i;
+
+  unsigned int
+    fonts;
+
+  if (font == (char *) NULL)
+    return((char **) NULL);
+  /*
+    Convert string to an ASCII list.
+  */
+  fonts=1U;
+  for (p=font; *p != '\0'; p++)
+    if ((*p == ':') || (*p == ';') || (*p == ','))
+      fonts++;
+  fontlist=(char **) AcquireQuantumMemory((size_t) fonts+1UL,sizeof(*fontlist));
+  if (fontlist == (char **) NULL)
+    {
+      ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
+        font);
+      return((char **) NULL);
+    }
+  p=font;
+  for (i=0; i < (int) fonts; i++)
+  {
+    for (q=p; *q != '\0'; q++)
+      if ((*q == ':') || (*q == ';') || (*q == ','))
+        break;
+    fontlist[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+1UL,
+      sizeof(*fontlist[i]));
+    if (fontlist[i] == (char *) NULL)
+      {
+        ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
+          font);
+        return((char **) NULL);
+      }
+    (void) CopyMagickString(fontlist[i],p,(size_t) (q-p+1));
+    p=q+1;
+  }
+  fontlist[i]=(char *) NULL;
+  return(fontlist);
+}
+
+MagickExport XFontStruct *XBestFont(Display *display,
+  const XResourceInfo *resource_info,const MagickBooleanType text_font)
+{
+  static const char
+    *Fonts[]=
+    {
+      "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1",
+      "-*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-1",
+      "-*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-15",
+      "-*-arial-medium-r-normal--12-*-*-*-*-*-iso8859-15",
+      "-*-helvetica-medium-r-normal--12-*-*-*-*-*-*-*",
+      "-*-arial-medium-r-normal--12-*-*-*-*-*-*-*",
+      "variable",
+      "fixed",
+      (char *) NULL
+    },
+    *TextFonts[]=
+    {
+      "-*-courier-medium-r-normal-*-12-*-*-*-*-*-iso8859-1",
+      "-*-courier-medium-r-normal-*-12-*-*-*-*-*-iso8859-15",
+      "-*-fixed-medium-r-normal-*-12-*-*-*-*-*-*-*",
+      "fixed",
+      (char *) NULL
+    };
+
+  char
+    *font_name;
+
+  register const char
+    **p;
+
+  XFontStruct
+    *font_info;
+
+  font_info=(XFontStruct *) NULL;
+  font_name=resource_info->font;
+  if (text_font != MagickFalse)
+    font_name=resource_info->text_font;
+  if ((font_name != (char *) NULL) && (*font_name != '\0'))
+    {
+      char
+        **fontlist;
+
+      register int
+        i;
+
+      /*
+        Load preferred font specified in the X resource database.
+      */
+      fontlist=FontToList(font_name);
+      if (fontlist != (char **) NULL)
+        {
+          for (i=0; fontlist[i] != (char *) NULL; i++)
+          {
+            if (font_info == (XFontStruct *) NULL)
+              font_info=XLoadQueryFont(display,fontlist[i]);
+            fontlist[i]=DestroyString(fontlist[i]);
+          }
+          fontlist=(char **) RelinquishMagickMemory(fontlist);
+        }
+      if (font_info == (XFontStruct *) NULL)
+        ThrowXWindowFatalException(XServerError,"UnableToLoadFont",font_name);
+    }
+  /*
+    Load fonts from list of fonts until one is found.
+  */
+  p=Fonts;
+  if (text_font != MagickFalse)
+    p=TextFonts;
+  if (XDisplayHeight(display,XDefaultScreen(display)) >= 748)
+    p++;
+  while (*p != (char *) NULL)
+  {
+    if (font_info != (XFontStruct *) NULL)
+      break;
+    font_info=XLoadQueryFont(display,(char *) *p);
+    p++;
+  }
+  return(font_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X B e s t I c o n S i z e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XBestIconSize() returns the "best" icon size.  "Best" is defined as an icon
+%  size that maintains the aspect ratio of the image.  If the window manager
+%  has preferred icon sizes, one of the preferred sizes is used.
+%
+%  The format of the XBestIconSize method is:
+%
+%      void XBestIconSize(Display *display,XWindowInfo *window,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o image: the image.
+%
+*/
+MagickExport void XBestIconSize(Display *display,XWindowInfo *window,
+  Image *image)
+{
+  int
+    i,
+    number_sizes;
+
+  MagickRealType
+    scale_factor;
+
+  unsigned int
+    height,
+    icon_height,
+    icon_width,
+    width;
+
+  Window
+    root_window;
+
+  XIconSize
+    *icon_size,
+    *size_list;
+
+  /*
+    Determine if the window manager has specified preferred icon sizes.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (XWindowInfo *) NULL);
+  assert(image != (Image *) NULL);
+  window->width=MaxIconSize;
+  window->height=MaxIconSize;
+  icon_size=(XIconSize *) NULL;
+  number_sizes=0;
+  root_window=XRootWindow(display,window->screen);
+  if (XGetIconSizes(display,root_window,&size_list,&number_sizes) != 0)
+    if ((number_sizes > 0) && (size_list != (XIconSize *) NULL))
+      icon_size=size_list;
+  if (icon_size == (XIconSize *) NULL)
+    {
+      /*
+        Window manager does not restrict icon size.
+      */
+      icon_size=XAllocIconSize();
+      if (icon_size == (XIconSize *) NULL)
+        {
+          ThrowXWindowFatalException(ResourceLimitError,
+            "MemoryAllocationFailed",image->filename);
+          return;
+        }
+      icon_size->min_width=1;
+      icon_size->max_width=MaxIconSize;
+      icon_size->min_height=1;
+      icon_size->max_height=MaxIconSize;
+      icon_size->width_inc=1;
+      icon_size->height_inc=1;
+    }
+  /*
+    Determine aspect ratio of image.
+  */
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  i=0;
+  if (window->crop_geometry)
+    (void) XParseGeometry(window->crop_geometry,&i,&i,&width,&height);
+  /*
+    Look for an icon size that maintains the aspect ratio of image.
+  */
+  scale_factor=(MagickRealType) icon_size->max_width/width;
+  if (scale_factor > ((MagickRealType) icon_size->max_height/height))
+    scale_factor=(MagickRealType) icon_size->max_height/height;
+  icon_width=(unsigned int) icon_size->min_width;
+  while ((int) icon_width < icon_size->max_width)
+  {
+    if (icon_width >= (unsigned int) (scale_factor*width+0.5))
+      break;
+    icon_width+=icon_size->width_inc;
+  }
+  icon_height=(unsigned int) icon_size->min_height;
+  while ((int) icon_height < icon_size->max_height)
+  {
+    if (icon_height >= (unsigned int) (scale_factor*height+0.5))
+      break;
+    icon_height+=icon_size->height_inc;
+  }
+  (void) XFree((void *) icon_size);
+  window->width=icon_width;
+  window->height=icon_height;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X B e s t P i x e l                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XBestPixel() returns a pixel from an array of pixels that is closest to the
+%  requested color.  If the color array is NULL, the colors are obtained from
+%  the X server.
+%
+%  The format of the XBestPixel method is:
+%
+%      void XBestPixel(Display *display,const Colormap colormap,XColor *colors,
+%        unsigned int number_colors,XColor *color)
+%
+%  A description of each parameter follows:
+%
+%    o pixel: XBestPixel returns the pixel value closest to the requested
+%      color.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o colormap: Specifies the ID of the X server colormap.
+%
+%    o colors: Specifies an array of XColor structures.
+%
+%    o number_colors: Specifies the number of XColor structures in the
+%      color definition array.
+%
+%    o color: Specifies the desired RGB value to find in the colors array.
+%
+*/
+MagickExport void XBestPixel(Display *display,const Colormap colormap,
+  XColor *colors,unsigned int number_colors,XColor *color)
+{
+  MagickBooleanType
+    query_server;
+
+  PixelInfo
+    pixel;
+
+  MagickRealType
+    min_distance;
+
+  register MagickRealType
+    distance;
+
+  register int
+    i,
+    j;
+
+  Status
+    status;
+
+  /*
+    Find closest representation for the requested RGB color.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(color != (XColor *) NULL);
+  status=XAllocColor(display,colormap,color);
+  if (status != False)
+    return;
+  query_server=colors == (XColor *) NULL ? MagickTrue : MagickFalse;
+  if (query_server != MagickFalse)
+    {
+      /*
+        Read X server colormap.
+      */
+      colors=(XColor *) AcquireQuantumMemory(number_colors,sizeof(*colors));
+      if (colors == (XColor *) NULL)
+        {
+          ThrowXWindowFatalException(ResourceLimitError,
+            "MemoryAllocationFailed","...");
+          return;
+        }
+      for (i=0; i < (int) number_colors; i++)
+        colors[i].pixel=(size_t) i;
+      if (number_colors > 256)
+        number_colors=256;
+      (void) XQueryColors(display,colormap,colors,(int) number_colors);
+    }
+  min_distance=3.0*((MagickRealType) QuantumRange+1.0)*((MagickRealType)
+    QuantumRange+1.0);
+  j=0;
+  for (i=0; i < (int) number_colors; i++)
+  {
+    pixel.red=colors[i].red-(MagickRealType) color->red;
+    distance=pixel.red*pixel.red;
+    if (distance > min_distance)
+      continue;
+    pixel.green=colors[i].green-(MagickRealType) color->green;
+    distance+=pixel.green*pixel.green;
+    if (distance > min_distance)
+      continue;
+    pixel.blue=colors[i].blue-(MagickRealType) color->blue;
+    distance+=pixel.blue*pixel.blue;
+    if (distance > min_distance)
+      continue;
+    min_distance=distance;
+    color->pixel=colors[i].pixel;
+    j=i;
+  }
+  (void) XAllocColor(display,colormap,&colors[j]);
+  if (query_server != MagickFalse)
+    colors=(XColor *) RelinquishMagickMemory(colors);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X B e s t V i s u a l I n f o                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XBestVisualInfo() returns visual information for a visual that is the "best"
+%  the server supports.  "Best" is defined as:
+%
+%    1. Restrict the visual list to those supported by the default screen.
+%
+%    2. If a visual type is specified, restrict the visual list to those of
+%       that type.
+%
+%    3. If a map type is specified, choose the visual that matches the id
+%       specified by the Standard Colormap.
+%
+%    4  From the list of visuals, choose one that can display the most
+%       simultaneous colors.  If more than one visual can display the same
+%       number of simultaneous colors, one is chosen based on a rank.
+%
+%  The format of the XBestVisualInfo method is:
+%
+%      XVisualInfo *XBestVisualInfo(Display *display,
+%        XStandardColormap *map_info,XResourceInfo *resource_info)
+%
+%  A description of each parameter follows:
+%
+%    o visual_info: XBestVisualInfo returns a pointer to a X11 XVisualInfo
+%      structure.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o map_info: If map_type is specified, this structure is initialized
+%      with info from the Standard Colormap.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+*/
+
+static inline int MagickMax(const int x,const int y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline size_t MagickMin(const unsigned int x,
+  const unsigned int y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickExport XVisualInfo *XBestVisualInfo(Display *display,
+  XStandardColormap *map_info,XResourceInfo *resource_info)
+{
+#define MaxStandardColormaps  7
+#define XVisualColormapSize(visual_info) MagickMin((unsigned int) (\
+  (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor) ? \
+   visual_info->red_mask | visual_info->green_mask | visual_info->blue_mask : \
+   (unsigned int) visual_info->colormap_size),1U << visual_info->depth)
+
+  char
+    *map_type,
+    *visual_type;
+
+  int
+    visual_mask;
+
+  register int
+    i;
+
+  size_t
+    one;
+
+  static int
+    number_visuals;
+
+  static XVisualInfo
+    visual_template;
+
+  XVisualInfo
+    *visual_info,
+    *visual_list;
+
+  /*
+    Restrict visual search by screen number.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(map_info != (XStandardColormap *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  map_type=resource_info->map_type;
+  visual_type=resource_info->visual_type;
+  visual_mask=VisualScreenMask;
+  visual_template.screen=XDefaultScreen(display);
+  visual_template.depth=XDefaultDepth(display,XDefaultScreen(display));
+  one=1;
+  if ((resource_info->immutable != MagickFalse) && (resource_info->colors != 0))
+    if (resource_info->colors <= (one << (size_t) visual_template.depth))
+      visual_mask|=VisualDepthMask;
+  if (visual_type != (char *) NULL)
+    {
+      /*
+        Restrict visual search by class or visual id.
+      */
+      if (LocaleCompare("staticgray",visual_type) == 0)
+        {
+          visual_mask|=VisualClassMask;
+          visual_template.klass=StaticGray;
+        }
+      else
+        if (LocaleCompare("grayscale",visual_type) == 0)
+          {
+            visual_mask|=VisualClassMask;
+            visual_template.klass=GrayScale;
+          }
+        else
+          if (LocaleCompare("staticcolor",visual_type) == 0)
+            {
+              visual_mask|=VisualClassMask;
+              visual_template.klass=StaticColor;
+            }
+          else
+            if (LocaleCompare("pseudocolor",visual_type) == 0)
+              {
+                visual_mask|=VisualClassMask;
+                visual_template.klass=PseudoColor;
+              }
+            else
+              if (LocaleCompare("truecolor",visual_type) == 0)
+                {
+                  visual_mask|=VisualClassMask;
+                  visual_template.klass=TrueColor;
+                }
+              else
+                if (LocaleCompare("directcolor",visual_type) == 0)
+                  {
+                    visual_mask|=VisualClassMask;
+                    visual_template.klass=DirectColor;
+                  }
+                else
+                  if (LocaleCompare("default",visual_type) == 0)
+                    {
+                      visual_mask|=VisualIDMask;
+                      visual_template.visualid=XVisualIDFromVisual(
+                        XDefaultVisual(display,XDefaultScreen(display)));
+                    }
+                  else
+                    if (isdigit((int) ((unsigned char) *visual_type)) != 0)
+                      {
+                        visual_mask|=VisualIDMask;
+                        visual_template.visualid=
+                          strtol(visual_type,(char **) NULL,0);
+                      }
+                    else
+                      ThrowXWindowFatalException(XServerError,
+                        "UnrecognizedVisualSpecifier",visual_type);
+    }
+  /*
+    Get all visuals that meet our criteria so far.
+  */
+  number_visuals=0;
+  visual_list=XGetVisualInfo(display,visual_mask,&visual_template,
+    &number_visuals);
+  visual_mask=VisualScreenMask | VisualIDMask;
+  if ((number_visuals == 0) || (visual_list == (XVisualInfo *) NULL))
+    {
+      /*
+        Failed to get visual;  try using the default visual.
+      */
+      ThrowXWindowFatalException(XServerWarning,"UnableToGetVisual",
+        visual_type);
+      visual_template.visualid=XVisualIDFromVisual(XDefaultVisual(display,
+        XDefaultScreen(display)));
+      visual_list=XGetVisualInfo(display,visual_mask,&visual_template,
+        &number_visuals);
+      if ((number_visuals == 0) || (visual_list == (XVisualInfo *) NULL))
+        return((XVisualInfo *) NULL);
+      ThrowXWindowFatalException(XServerWarning,"UsingDefaultVisual",
+        XVisualClassName(visual_list->klass));
+    }
+  resource_info->color_recovery=MagickFalse;
+  if ((map_info != (XStandardColormap *) NULL) && (map_type != (char *) NULL))
+    {
+      Atom
+        map_property;
+
+      char
+        map_name[MaxTextExtent];
+
+      int
+        j,
+        number_maps;
+
+      Status
+        status;
+
+      Window
+        root_window;
+
+      XStandardColormap
+        *map_list;
+
+      /*
+        Choose a visual associated with a standard colormap.
+      */
+      root_window=XRootWindow(display,XDefaultScreen(display));
+      status=False;
+      if (LocaleCompare(map_type,"list") != 0)
+        {
+          /*
+            User specified Standard Colormap.
+          */
+          (void) FormatLocaleString((char *) map_name,MaxTextExtent,
+            "RGB_%s_MAP",map_type);
+          LocaleUpper(map_name);
+          map_property=XInternAtom(display,(char *) map_name,MagickTrue);
+          if (map_property != (Atom) NULL)
+            status=XGetRGBColormaps(display,root_window,&map_list,&number_maps,
+              map_property);
+        }
+      else
+        {
+          static const char
+            *colormap[MaxStandardColormaps]=
+            {
+              "_HP_RGB_SMOOTH_MAP_LIST",
+              "RGB_BEST_MAP",
+              "RGB_DEFAULT_MAP",
+              "RGB_GRAY_MAP",
+              "RGB_RED_MAP",
+              "RGB_GREEN_MAP",
+              "RGB_BLUE_MAP",
+            };
+
+          /*
+            Choose a standard colormap from a list.
+          */
+          for (i=0; i < MaxStandardColormaps; i++)
+          {
+            map_property=XInternAtom(display,(char *) colormap[i],MagickTrue);
+            if (map_property == (Atom) NULL)
+              continue;
+            status=XGetRGBColormaps(display,root_window,&map_list,&number_maps,
+              map_property);
+            if (status != False)
+              break;
+          }
+          resource_info->color_recovery=i == 0 ? MagickTrue : MagickFalse;
+        }
+      if (status == False)
+        {
+          ThrowXWindowFatalException(XServerError,"UnableToGetStandardColormap",
+            map_type);
+          return((XVisualInfo *) NULL);
+        }
+      /*
+        Search all Standard Colormaps and visuals for ids that match.
+      */
+      *map_info=map_list[0];
+#if !defined(PRE_R4_ICCCM)
+      visual_template.visualid=XVisualIDFromVisual(visual_list[0].visual);
+      for (i=0; i < number_maps; i++)
+        for (j=0; j < number_visuals; j++)
+          if (map_list[i].visualid ==
+              XVisualIDFromVisual(visual_list[j].visual))
+            {
+              *map_info=map_list[i];
+              visual_template.visualid=XVisualIDFromVisual(
+                visual_list[j].visual);
+              break;
+            }
+      if (map_info->visualid != visual_template.visualid)
+        {
+          ThrowXWindowFatalException(XServerError,
+            "UnableToMatchVisualToStandardColormap",map_type);
+          return((XVisualInfo *) NULL);
+        }
+#endif
+      if (map_info->colormap == (Colormap) NULL)
+        {
+          ThrowXWindowFatalException(XServerError,
+            "StandardColormapIsNotInitialized",map_type);
+          return((XVisualInfo *) NULL);
+        }
+      (void) XFree((void *) map_list);
+    }
+  else
+    {
+      static const unsigned int
+        rank[]=
+          {
+            StaticGray,
+            GrayScale,
+            StaticColor,
+            DirectColor,
+            TrueColor,
+            PseudoColor
+          };
+
+      XVisualInfo
+        *p;
+
+      /*
+        Pick one visual that displays the most simultaneous colors.
+      */
+      visual_info=visual_list;
+      p=visual_list;
+      for (i=1; i < number_visuals; i++)
+      {
+        p++;
+        if (XVisualColormapSize(p) > XVisualColormapSize(visual_info))
+          visual_info=p;
+        else
+          if (XVisualColormapSize(p) == XVisualColormapSize(visual_info))
+            if (rank[p->klass] > rank[visual_info->klass])
+              visual_info=p;
+      }
+      visual_template.visualid=XVisualIDFromVisual(visual_info->visual);
+    }
+  (void) XFree((void *) visual_list);
+  /*
+    Retrieve only one visual by its screen & id number.
+  */
+  visual_info=XGetVisualInfo(display,visual_mask,&visual_template,
+    &number_visuals);
+  if ((number_visuals == 0) || (visual_info == (XVisualInfo *) NULL))
+    return((XVisualInfo *) NULL);
+  return(visual_info);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C h e c k D e f i n e C u r s o r                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XCheckDefineCursor() prevents cursor changes on the root window.
+%
+%  The format of the XXCheckDefineCursor method is:
+%
+%      XCheckDefineCursor(display,window,cursor)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: the window.
+%
+%    o cursor: the cursor.
+%
+*/
+MagickExport int XCheckDefineCursor(Display *display,Window window,
+  Cursor cursor)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  if (window == XRootWindow(display,XDefaultScreen(display)))
+    return(0);
+  return(XDefineCursor(display,window,cursor));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C h e c k R e f r e s h W i n d o w s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XCheckRefreshWindows() checks the X server for exposure events for a
+%  particular window and updates the areassociated with the exposure event.
+%
+%  The format of the XCheckRefreshWindows method is:
+%
+%      void XCheckRefreshWindows(Display *display,XWindows *windows)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+*/
+MagickExport void XCheckRefreshWindows(Display *display,XWindows *windows)
+{
+  Window
+    id;
+
+  XEvent
+    event;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  XDelay(display,SuspendTime);
+  id=windows->command.id;
+  while (XCheckTypedWindowEvent(display,id,Expose,&event) != MagickFalse)
+    (void) XCommandWidget(display,windows,(char const **) NULL,&event);
+  id=windows->image.id;
+  while (XCheckTypedWindowEvent(display,id,Expose,&event) != MagickFalse)
+    XRefreshWindow(display,&windows->image,&event);
+  XDelay(display,SuspendTime << 1);
+  id=windows->command.id;
+  while (XCheckTypedWindowEvent(display,id,Expose,&event) != MagickFalse)
+    (void) XCommandWidget(display,windows,(char const **) NULL,&event);
+  id=windows->image.id;
+  while (XCheckTypedWindowEvent(display,id,Expose,&event) != MagickFalse)
+    XRefreshWindow(display,&windows->image,&event);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C l i e n t M e s s a g e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XClientMessage() sends a reason to a window with XSendEvent.  The reason is
+%  initialized with a particular protocol type and atom.
+%
+%  The format of the XClientMessage function is:
+%
+%      XClientMessage(display,window,protocol,reason,timestamp)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window structure.
+%
+%    o protocol: Specifies an atom value.
+%
+%    o reason: Specifies an atom value which is the reason to send.
+%
+%    o timestamp: Specifies a value of type Time.
+%
+*/
+MagickExport void XClientMessage(Display *display,const Window window,
+  const Atom protocol,const Atom reason,const Time timestamp)
+{
+  XClientMessageEvent
+    client_event;
+
+  assert(display != (Display *) NULL);
+  client_event.type=ClientMessage;
+  client_event.window=window;
+  client_event.message_type=protocol;
+  client_event.format=32;
+  client_event.data.l[0]=(long) reason;
+  client_event.data.l[1]=(long) timestamp;
+  (void) XSendEvent(display,window,MagickFalse,NoEventMask,(XEvent *) &client_event);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C l i e n t W i n d o w                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XClientWindow() finds a window, at or below the specified window, which has
+%  a WM_STATE property.  If such a window is found, it is returned, otherwise
+%  the argument window is returned.
+%
+%  The format of the XClientWindow function is:
+%
+%      client_window=XClientWindow(display,target_window)
+%
+%  A description of each parameter follows:
+%
+%    o client_window: XClientWindow returns a window, at or below the specified
+%      window, which has a WM_STATE property otherwise the argument
+%      target_window is returned.
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o target_window: Specifies the window to find a WM_STATE property.
+%
+*/
+static Window XClientWindow(Display *display,Window target_window)
+{
+  Atom
+    state,
+    type;
+
+  int
+    format;
+
+  Status
+    status;
+
+  unsigned char
+    *data;
+
+  unsigned long
+    after,
+    number_items;
+
+  Window
+    client_window;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  state=XInternAtom(display,"WM_STATE",MagickTrue);
+  if (state == (Atom) NULL)
+    return(target_window);
+  type=(Atom) NULL;
+  status=XGetWindowProperty(display,target_window,state,0L,0L,MagickFalse,
+    (Atom) AnyPropertyType,&type,&format,&number_items,&after,&data);
+  if ((status == Success) && (type != (Atom) NULL))
+    return(target_window);
+  client_window=XWindowByProperty(display,target_window,state);
+  if (client_window == (Window) NULL)
+    return(target_window);
+  return(client_window);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C o m p o n e n t T e r m i n u s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XComponentTerminus() destroys the module component.
+%
+%  The format of the XComponentTerminus method is:
+%
+%      XComponentTerminus(void)
+%
+*/
+MagickExport void XComponentTerminus(void)
+{
+  DestroyXResources();
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C o n f i g u r e I m a g e C o l o r m a p                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XConfigureImageColormap() creates a new X colormap.
+%
+%  The format of the XConfigureImageColormap method is:
+%
+%      void XConfigureImageColormap(Display *display,
+%        XResourceInfo *resource_info,XWindows *windows,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o image: the image.
+%
+*/
+MagickExport void XConfigureImageColormap(Display *display,
+  XResourceInfo *resource_info,XWindows *windows,Image *image)
+{
+  Colormap
+    colormap;
+
+  /*
+    Make standard colormap.
+  */
+  XSetCursorState(display,windows,MagickTrue);
+  XCheckRefreshWindows(display,windows);
+  XMakeStandardColormap(display,windows->visual_info,resource_info,image,
+    windows->map_info,windows->pixel_info);
+  colormap=windows->map_info->colormap;
+  (void) XSetWindowColormap(display,windows->image.id,colormap);
+  (void) XSetWindowColormap(display,windows->command.id,colormap);
+  (void) XSetWindowColormap(display,windows->widget.id,colormap);
+  if (windows->magnify.mapped != MagickFalse)
+    (void) XSetWindowColormap(display,windows->magnify.id,colormap);
+  if (windows->pan.mapped != MagickFalse)
+    (void) XSetWindowColormap(display,windows->pan.id,colormap);
+  XSetCursorState(display,windows,MagickFalse);
+  XClientMessage(display,windows->image.id,windows->im_protocols,
+    windows->im_update_colormap,CurrentTime);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X C o n s t r a i n W i n d o w P o s i t i o n                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XConstrainWindowPosition() assures a window is positioned within the X
+%  server boundaries.
+%
+%  The format of the XConstrainWindowPosition method is:
+%
+%      void XConstrainWindowPosition(Display *display,XWindowInfo *window_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o window_info: Specifies a pointer to a XWindowInfo structure.
+%
+*/
+MagickExport void XConstrainWindowPosition(Display *display,
+  XWindowInfo *window_info)
+{
+  int
+    limit;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window_info != (XWindowInfo *) NULL);
+  limit=XDisplayWidth(display,window_info->screen)-window_info->width;
+  if (window_info->x < 0)
+    window_info->x=0;
+  else
+    if (window_info->x > (int) limit)
+      window_info->x=(int) limit;
+  limit=XDisplayHeight(display,window_info->screen)-window_info->height;
+  if (window_info->y < 0)
+    window_info->y=0;
+  else
+    if (window_info->y > limit)
+      window_info->y=limit;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D e l a y                                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDelay() suspends program execution for the number of milliseconds
+%  specified.
+%
+%  The format of the Delay method is:
+%
+%      void XDelay(Display *display,const size_t milliseconds)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o milliseconds: Specifies the number of milliseconds to delay before
+%      returning.
+%
+*/
+MagickExport void XDelay(Display *display,const size_t milliseconds)
+{
+  assert(display != (Display *) NULL);
+  (void) XFlush(display);
+  MagickDelay(milliseconds);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D e s t r o y R e s o u r c e I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDestroyResourceInfo() frees memory associated with the XResourceInfo
+%  structure.
+%
+%  The format of the XDestroyResourceInfo method is:
+%
+%      void XDestroyResourceInfo(XResourceInfo *resource_info)
+%
+%  A description of each parameter follows:
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+*/
+MagickExport void XDestroyResourceInfo(XResourceInfo *resource_info)
+{
+  if (resource_info->image_geometry != (char *) NULL)
+    resource_info->image_geometry=(char *)
+      RelinquishMagickMemory(resource_info->image_geometry);
+  if (resource_info->quantize_info != (QuantizeInfo *) NULL)
+    resource_info->quantize_info=DestroyQuantizeInfo(
+      resource_info->quantize_info);
+  if (resource_info->client_name != (char *) NULL)
+    resource_info->client_name=(char *)
+      RelinquishMagickMemory(resource_info->client_name);
+  if (resource_info->name != (char *) NULL)
+    resource_info->name=DestroyString(resource_info->name);
+  (void) ResetMagickMemory(resource_info,0,sizeof(*resource_info));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D e s t r o y W i n d o w C o l o r s                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDestroyWindowColors() frees X11 color resources previously saved on a
+%  window by XRetainWindowColors or programs like xsetroot.
+%
+%  The format of the XDestroyWindowColors method is:
+%
+%      void XDestroyWindowColors(Display *display,Window window)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window structure.
+%
+*/
+MagickExport void XDestroyWindowColors(Display *display,Window window)
+{
+  Atom
+    property,
+    type;
+
+  int
+    format;
+
+  Status
+    status;
+
+  unsigned char
+    *data;
+
+  unsigned long
+    after,
+    length;
+
+  /*
+    If there are previous resources on the root window, destroy them.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  property=XInternAtom(display,"_XSETROOT_ID",MagickFalse);
+  if (property == (Atom) NULL)
+    {
+      ThrowXWindowFatalException(XServerError,"UnableToCreateProperty",
+        "_XSETROOT_ID");
+      return;
+    }
+  status=XGetWindowProperty(display,window,property,0L,1L,MagickTrue,
+    (Atom) AnyPropertyType,&type,&format,&length,&after,&data);
+  if (status != Success)
+    return;
+  if ((type == XA_PIXMAP) && (format == 32) && (length == 1) && (after == 0))
+    {
+      (void) XKillClient(display,(XID) (*((Pixmap *) data)));
+      (void) XDeleteProperty(display,window,property);
+    }
+  if (type != None)
+    (void) XFree((void *) data);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D i s p l a y I m a g e I n f o                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDisplayImageInfo() displays information about an X image.
+%
+%  The format of the XDisplayImageInfo method is:
+%
+%      void XDisplayImageInfo(Display *display,
+%        const XResourceInfo *resource_info,XWindows *windows,Image *undo_image,
+%        Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o undo_image: the undo image.
+%
+%    o image: the image.
+%
+*/
+MagickExport void XDisplayImageInfo(Display *display,
+  const XResourceInfo *resource_info,XWindows *windows,Image *undo_image,
+  Image *image)
+{
+  char
+    filename[MaxTextExtent],
+    *text,
+    **textlist;
+
+  FILE
+    *file;
+
+  int
+    unique_file;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_pixels;
+
+  ssize_t
+    bytes;
+
+  unsigned int
+    levels;
+
+  /*
+    Write info about the X server to a file.
+  */
+  assert(display != (Display *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(windows != (XWindows *) NULL);
+  assert(image != (Image *) NULL);
+  if (image->debug)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  file=(FILE *) NULL;
+  unique_file=AcquireUniqueFileResource(filename);
+  if (unique_file != -1)
+    file=fdopen(unique_file,"w");
+  if ((unique_file == -1) || (file == (FILE *) NULL))
+    {
+      XNoticeWidget(display,windows,"Unable to display image info",filename);
+      return;
+    }
+  if (resource_info->gamma_correct != MagickFalse)
+    if (resource_info->display_gamma != (char *) NULL)
+      (void) FormatLocaleFile(file,"Display\n  gamma: %s\n\n",
+        resource_info->display_gamma);
+  /*
+    Write info about the X image to a file.
+  */
+  (void) FormatLocaleFile(file,"X\n  visual: %s\n",
+    XVisualClassName((int) windows->image.storage_class));
+  (void) FormatLocaleFile(file,"  depth: %d\n",windows->image.ximage->depth);
+  if (windows->visual_info->colormap_size != 0)
+    (void) FormatLocaleFile(file,"  colormap size: %d\n",
+      windows->visual_info->colormap_size);
+  if (resource_info->colormap== SharedColormap)
+    (void) FormatLocaleFile(file,"  colormap type: Shared\n");
+  else
+    (void) FormatLocaleFile(file,"  colormap type: Private\n");
+  (void) FormatLocaleFile(file,"  geometry: %dx%d\n",
+    windows->image.ximage->width,windows->image.ximage->height);
+  if (windows->image.crop_geometry != (char *) NULL)
+    (void) FormatLocaleFile(file,"  crop geometry: %s\n",
+      windows->image.crop_geometry);
+  if (windows->image.pixmap == (Pixmap) NULL)
+    (void) FormatLocaleFile(file,"  type: X Image\n");
+  else
+    (void) FormatLocaleFile(file,"  type: Pixmap\n");
+  if (windows->image.shape != MagickFalse)
+    (void) FormatLocaleFile(file,"  non-rectangular shape: True\n");
+  else
+    (void) FormatLocaleFile(file,"  non-rectangular shape: False\n");
+  if (windows->image.shared_memory != MagickFalse)
+    (void) FormatLocaleFile(file,"  shared memory: True\n");
+  else
+    (void) FormatLocaleFile(file,"  shared memory: False\n");
+  (void) FormatLocaleFile(file,"\n");
+  if (resource_info->font != (char *) NULL)
+    (void) FormatLocaleFile(file,"Font: %s\n\n",resource_info->font);
+  if (resource_info->text_font != (char *) NULL)
+    (void) FormatLocaleFile(file,"Text font: %s\n\n",resource_info->text_font);
+  /*
+    Write info about the undo cache to a file.
+  */
+  bytes=0;
+  for (levels=0; undo_image != (Image *) NULL; levels++)
+  {
+    number_pixels=undo_image->list->columns*undo_image->list->rows;
+    bytes+=number_pixels*sizeof(PixelPacket);
+    undo_image=GetPreviousImageInList(undo_image);
+  }
+  (void) FormatLocaleFile(file,"Undo Edit Cache\n  levels: %u\n",levels);
+  (void) FormatLocaleFile(file,"  bytes: %.20gmb\n",(double)
+    ((bytes+(1 << 19)) >> 20));
+  (void) FormatLocaleFile(file,"  limit: %.20gmb\n\n",(double)
+    resource_info->undo_cache);
+  /*
+    Write info about the image to a file.
+  */
+  (void) IdentifyImage(image,file,MagickTrue);
+  (void) fclose(file);
+  text=FileToString(filename,~0,&image->exception);
+  (void) RelinquishUniqueFileResource(filename);
+  if (text == (char *) NULL)
+    {
+      XNoticeWidget(display,windows,"MemoryAllocationFailed",
+        "UnableToDisplayImageInfo");
+      return;
+    }
+  textlist=StringToList(text);
+  if (textlist != (char **) NULL)
+    {
+      char
+        title[MaxTextExtent];
+
+      /*
+        Display information about the image in the Text View widget.
+      */
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+      (void) FormatLocaleString(title,MaxTextExtent,"Image Info: %s",
+        image->filename);
+      XTextViewWidget(display,resource_info,windows,MagickTrue,title,
+        (char const **) textlist);
+      for (i=0; textlist[i] != (char *) NULL; i++)
+        textlist[i]=DestroyString(textlist[i]);
+      textlist=(char **) RelinquishMagickMemory(textlist);
+    }
+  text=DestroyString(text);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++     X D i t h e r I m a g e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDitherImage() dithers the reference image as required by the HP Color
+%  Recovery algorithm.  The color values are quantized to 3 bits of red and
+%  green, and 2 bits of blue (3/3/2) and can be used as indices into a 8-bit X
+%  standard colormap.
+%
+%  The format of the XDitherImage method is:
+%
+%      void XDitherImage(Image *image,XImage *ximage)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o ximage: Specifies a pointer to a XImage structure;  returned from
+%      XCreateImage.
+%
+*/
+static void XDitherImage(Image *image,XImage *ximage)
+{
+  static const short int
+    dither_red[2][16]=
+    {
+      {-16,  4, -1, 11,-14,  6, -3,  9,-15,  5, -2, 10,-13,  7, -4,  8},
+      { 15, -5,  0,-12, 13, -7,  2,-10, 14, -6,  1,-11, 12, -8,  3, -9}
+    },
+    dither_green[2][16]=
+    {
+      { 11,-15,  7, -3,  8,-14,  4, -2, 10,-16,  6, -4,  9,-13,  5, -1},
+      {-12, 14, -8,  2, -9, 13, -5,  1,-11, 15, -7,  3,-10, 12, -6,  0}
+    },
+    dither_blue[2][16]=
+    {
+      { -3,  9,-13,  7, -1, 11,-15,  5, -4,  8,-14,  6, -2, 10,-16,  4},
+      {  2,-10, 12, -8,  0,-12, 14, -6,  3, -9, 13, -7,  1,-11, 15, -5}
+    };
+
+  CacheView
+    *image_view;
+
+  int
+    value,
+    y;
+
+  PixelPacket
+    color;
+
+  register char
+    *q;
+
+  register const Quantum
+    *p;
+
+  register int
+    i,
+    j,
+    x;
+
+  unsigned int
+    scanline_pad;
+
+  register size_t
+    pixel;
+
+  unsigned char
+    *blue_map[2][16],
+    *green_map[2][16],
+    *red_map[2][16];
+
+  /*
+    Allocate and initialize dither maps.
+  */
+  for (i=0; i < 2; i++)
+    for (j=0; j < 16; j++)
+    {
+      red_map[i][j]=(unsigned char *) AcquireQuantumMemory(256UL,
+        sizeof(*red_map));
+      green_map[i][j]=(unsigned char *) AcquireQuantumMemory(256UL,
+        sizeof(*green_map));
+      blue_map[i][j]=(unsigned char *) AcquireQuantumMemory(256UL,
+        sizeof(*blue_map));
+      if ((red_map[i][j] == (unsigned char *) NULL) ||
+          (green_map[i][j] == (unsigned char *) NULL) ||
+          (blue_map[i][j] == (unsigned char *) NULL))
+        {
+          ThrowXWindowFatalException(ResourceLimitError,
+            "MemoryAllocationFailed",image->filename);
+          return;
+        }
+    }
+  /*
+    Initialize dither tables.
+  */
+  for (i=0; i < 2; i++)
+    for (j=0; j < 16; j++)
+      for (x=0; x < 256; x++)
+      {
+        value=x-16;
+        if (x < 48)
+          value=x/2+8;
+        value+=dither_red[i][j];
+        red_map[i][j][x]=(unsigned char)
+          ((value < 0) ? 0 : (value > 255) ? 255 : value);
+        value=x-16;
+        if (x < 48)
+          value=x/2+8;
+        value+=dither_green[i][j];
+        green_map[i][j][x]=(unsigned char)
+          ((value < 0) ? 0 : (value > 255) ? 255 : value);
+        value=x-32;
+        if (x < 112)
+          value=x/2+24;
+        value+=((size_t) dither_blue[i][j] << 1);
+        blue_map[i][j][x]=(unsigned char)
+          ((value < 0) ? 0 : (value > 255) ? 255 : value);
+      }
+  /*
+    Dither image.
+  */
+  scanline_pad=(unsigned int) (ximage->bytes_per_line-
+    ((size_t) (ximage->width*ximage->bits_per_pixel) >> 3));
+  i=0;
+  j=0;
+  q=ximage->data;
+  image_view=AcquireCacheView(image);
+  for (y=0; y < (int) image->rows; y++)
+  {
+    p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) y,image->columns,1,
+      &image->exception);
+    if (p == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (int) image->columns; x++)
+    {
+      color.red=ClampToQuantum((MagickRealType) (red_map[i][j][(int)
+        ScaleQuantumToChar(GetPixelRed(image,p))] << 8));
+      color.green=ClampToQuantum((MagickRealType) (green_map[i][j][(int)
+        ScaleQuantumToChar(GetPixelGreen(image,p))] << 8));
+      color.blue=ClampToQuantum((MagickRealType) (blue_map[i][j][(int)
+        ScaleQuantumToChar(GetPixelBlue(image,p))] << 8));
+      pixel=(size_t) (((size_t) color.red & 0xe0) |
+        (((size_t) color.green & 0xe0) >> 3) |
+        (((size_t) color.blue & 0xc0) >> 6));
+      *q++=(char) pixel;
+      p+=GetPixelChannels(image);
+      j++;
+      if (j == 16)
+        j=0;
+    }
+    q+=scanline_pad;
+    i++;
+    if (i == 2)
+      i=0;
+  }
+  image_view=DestroyCacheView(image_view);
+  /*
+    Free allocated memory.
+  */
+  for (i=0; i < 2; i++)
+    for (j=0; j < 16; j++)
+    {
+      green_map[i][j]=(unsigned char *) RelinquishMagickMemory(green_map[i][j]);
+      blue_map[i][j]=(unsigned char *) RelinquishMagickMemory(blue_map[i][j]);
+      red_map[i][j]=(unsigned char *) RelinquishMagickMemory(red_map[i][j]);
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X D r a w I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XDrawImage() draws a line on the image.
+%
+%  The format of the XDrawImage method is:
+%
+%    MagickBooleanType XDrawImage(display,pixel,draw_info,image)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+%    o draw_info: Specifies a pointer to a XDrawInfo structure.
+%
+%    o image: the image.
+%
+*/
+MagickExport MagickBooleanType XDrawImage(Display *display,
+  const XPixelInfo *pixel,XDrawInfo *draw_info,Image *image)
+{
+  CacheView
+    *draw_view;
+
+  ExceptionInfo
+    *exception;
+
+  GC
+    draw_context;
+
+  Image
+    *draw_image;
+
+  int
+    x,
+    y;
+
+  MagickBooleanType
+    matte;
+
+  Pixmap
+    draw_pixmap;
+
+  unsigned int
+    depth,
+    height,
+    width;
+
+  Window
+    root_window;
+
+  XGCValues
+    context_values;
+
+  XImage
+    *draw_ximage;
+
+  /*
+    Initialize drawd image.
+  */
+  assert(display != (Display *) NULL);
+  assert(pixel != (XPixelInfo *) NULL);
+  assert(draw_info != (XDrawInfo *) NULL);
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  /*
+    Initialize drawd pixmap.
+  */
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  depth=(unsigned int) XDefaultDepth(display,XDefaultScreen(display));
+  draw_pixmap=XCreatePixmap(display,root_window,draw_info->width,
+    draw_info->height,depth);
+  if (draw_pixmap == (Pixmap) NULL)
+    return(MagickFalse);
+  /*
+    Initialize graphics info.
+  */
+  context_values.background=(size_t) (~0);
+  context_values.foreground=0;
+  context_values.line_width=(int) draw_info->line_width;
+  draw_context=XCreateGC(display,root_window,(size_t)
+    (GCBackground | GCForeground | GCLineWidth),&context_values);
+  if (draw_context == (GC) NULL)
+    return(MagickFalse);
+  /*
+    Clear pixmap.
+  */
+  (void) XFillRectangle(display,draw_pixmap,draw_context,0,0,draw_info->width,
+    draw_info->height);
+  /*
+    Draw line to pixmap.
+  */
+  (void) XSetBackground(display,draw_context,0);
+  (void) XSetForeground(display,draw_context,(size_t) (~0));
+  if (draw_info->stipple !=  (Pixmap) NULL)
+    {
+      (void) XSetFillStyle(display,draw_context,FillOpaqueStippled);
+      (void) XSetStipple(display,draw_context,draw_info->stipple);
+    }
+  switch (draw_info->element)
+  {
+    case PointElement:
+    default:
+    {
+      (void) XDrawLines(display,draw_pixmap,draw_context,
+        draw_info->coordinate_info,(int) draw_info->number_coordinates,
+        CoordModeOrigin);
+      break;
+    }
+    case LineElement:
+    {
+      (void) XDrawLine(display,draw_pixmap,draw_context,draw_info->line_info.x1,
+        draw_info->line_info.y1,draw_info->line_info.x2,
+        draw_info->line_info.y2);
+      break;
+    }
+    case RectangleElement:
+    {
+      (void) XDrawRectangle(display,draw_pixmap,draw_context,
+        (int) draw_info->rectangle_info.x,(int) draw_info->rectangle_info.y,
+        (unsigned int) draw_info->rectangle_info.width,
+        (unsigned int) draw_info->rectangle_info.height);
+      break;
+    }
+    case FillRectangleElement:
+    {
+      (void) XFillRectangle(display,draw_pixmap,draw_context,
+        (int) draw_info->rectangle_info.x,(int) draw_info->rectangle_info.y,
+        (unsigned int) draw_info->rectangle_info.width,
+        (unsigned int) draw_info->rectangle_info.height);
+      break;
+    }
+    case CircleElement:
+    case EllipseElement:
+    {
+      (void) XDrawArc(display,draw_pixmap,draw_context,
+        (int) draw_info->rectangle_info.x,(int) draw_info->rectangle_info.y,
+        (unsigned int) draw_info->rectangle_info.width,
+        (unsigned int) draw_info->rectangle_info.height,0,360*64);
+      break;
+    }
+    case FillCircleElement:
+    case FillEllipseElement:
+    {
+      (void) XFillArc(display,draw_pixmap,draw_context,
+        (int) draw_info->rectangle_info.x,(int) draw_info->rectangle_info.y,
+        (unsigned int) draw_info->rectangle_info.width,
+        (unsigned int) draw_info->rectangle_info.height,0,360*64);
+      break;
+    }
+    case PolygonElement:
+    {
+      XPoint
+        *coordinate_info;
+
+      coordinate_info=draw_info->coordinate_info;
+      (void) XDrawLines(display,draw_pixmap,draw_context,coordinate_info,
+        (int) draw_info->number_coordinates,CoordModeOrigin);
+      (void) XDrawLine(display,draw_pixmap,draw_context,
+        coordinate_info[draw_info->number_coordinates-1].x,
+        coordinate_info[draw_info->number_coordinates-1].y,
+        coordinate_info[0].x,coordinate_info[0].y);
+      break;
+    }
+    case FillPolygonElement:
+    {
+      (void) XFillPolygon(display,draw_pixmap,draw_context,
+        draw_info->coordinate_info,(int) draw_info->number_coordinates,Complex,
+        CoordModeOrigin);
+      break;
+    }
+  }
+  (void) XFreeGC(display,draw_context);
+  /*
+    Initialize X image.
+  */
+  draw_ximage=XGetImage(display,draw_pixmap,0,0,draw_info->width,
+    draw_info->height,AllPlanes,ZPixmap);
+  if (draw_ximage == (XImage *) NULL)
+    return(MagickFalse);
+  (void) XFreePixmap(display,draw_pixmap);
+  /*
+    Initialize draw image.
+  */
+  draw_image=AcquireImage((ImageInfo *) NULL);
+  if (draw_image == (Image *) NULL)
+    return(MagickFalse);
+  draw_image->columns=draw_info->width;
+  draw_image->rows=draw_info->height;
+  /*
+    Transfer drawn X image to image.
+  */
+  width=(unsigned int) image->columns;
+  height=(unsigned int) image->rows;
+  x=0;
+  y=0;
+  (void) XParseGeometry(draw_info->geometry,&x,&y,&width,&height);
+  (void) GetOneVirtualPixel(image,(ssize_t) x,(ssize_t) y,
+    &draw_image->background_color,&image->exception);
+  if (SetImageStorageClass(draw_image,DirectClass) == MagickFalse)
+    return(MagickFalse);
+  draw_image->matte=MagickTrue;
+  exception=(&image->exception);
+  draw_view=AcquireCacheView(draw_image);
+  for (y=0; y < (int) draw_image->rows; y++)
+  {
+    register int
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=QueueCacheViewAuthenticPixels(draw_view,0,(ssize_t) y,draw_image->columns,
+      1,exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (int) draw_image->columns; x++)
+    {
+      if (XGetPixel(draw_ximage,x,y) == 0)
+        {
+          /*
+            Set this pixel to the background color.
+          */
+          SetPixelPacket(draw_image,&draw_image->background_color,q);
+          SetPixelAlpha(draw_image,(Quantum) (draw_info->stencil == 
+            OpaqueStencil ? TransparentAlpha : OpaqueAlpha),q);
+        }
+      else
+        {
+          /*
+            Set this pixel to the pen color.
+          */
+          SetPixelRed(draw_image,ScaleShortToQuantum(
+            pixel->pen_color.red),q);
+          SetPixelGreen(draw_image,ScaleShortToQuantum(
+            pixel->pen_color.green),q);
+          SetPixelBlue(draw_image,ScaleShortToQuantum(
+            pixel->pen_color.blue),q);
+          SetPixelAlpha(draw_image,(Quantum) (draw_info->stencil ==
+            OpaqueStencil ? OpaqueAlpha : TransparentAlpha),q);
+        }
+      q+=GetPixelChannels(draw_image);
+    }
+    if (SyncCacheViewAuthenticPixels(draw_view,exception) == MagickFalse)
+      break;
+  }
+  draw_view=DestroyCacheView(draw_view);
+  XDestroyImage(draw_ximage);
+  /*
+    Determine draw geometry.
+  */
+  (void) XParseGeometry(draw_info->geometry,&x,&y,&width,&height);
+  if ((width != (unsigned int) draw_image->columns) ||
+      (height != (unsigned int) draw_image->rows))
+    {
+      char
+        image_geometry[MaxTextExtent];
+
+      /*
+        Scale image.
+      */
+      (void) FormatLocaleString(image_geometry,MaxTextExtent,"%ux%u",
+        width,height);
+      (void) TransformImage(&draw_image,(char *) NULL,image_geometry);
+    }
+  if (draw_info->degrees != 0.0)
+    {
+      Image
+        *rotate_image;
+
+      int
+        rotations;
+
+      MagickRealType
+        normalized_degrees;
+
+      /*
+        Rotate image.
+      */
+      rotate_image=RotateImage(draw_image,draw_info->degrees,&image->exception);
+      if (rotate_image == (Image *) NULL)
+        return(MagickFalse);
+      draw_image=DestroyImage(draw_image);
+      draw_image=rotate_image;
+      /*
+        Annotation is relative to the degree of rotation.
+      */
+      normalized_degrees=draw_info->degrees;
+      while (normalized_degrees < -45.0)
+        normalized_degrees+=360.0;
+      for (rotations=0; normalized_degrees > 45.0; rotations++)
+        normalized_degrees-=90.0;
+      switch (rotations % 4)
+      {
+        default:
+        case 0:
+          break;
+        case 1:
+        {
+          /*
+            Rotate 90 degrees.
+          */
+          x=x-(int) draw_image->columns/2;
+          y=y+(int) draw_image->columns/2;
+          break;
+        }
+        case 2:
+        {
+          /*
+            Rotate 180 degrees.
+          */
+          x=x-(int) draw_image->columns;
+          break;
+        }
+        case 3:
+        {
+          /*
+            Rotate 270 degrees.
+          */
+          x=x-(int) draw_image->columns/2;
+          y=y-(int) (draw_image->rows-(draw_image->columns/2));
+          break;
+        }
+      }
+    }
+  /*
+    Composite text onto the image.
+  */
+  draw_view=AcquireCacheView(draw_image);
+  for (y=0; y < (int) draw_image->rows; y++)
+  {
+    register int
+      x;
+
+    register Quantum
+      *restrict q;
+
+    q=GetCacheViewAuthenticPixels(draw_view,0,(ssize_t) y,draw_image->columns,1,
+      exception);
+    if (q == (const Quantum *) NULL)
+      break;
+    for (x=0; x < (int) draw_image->columns; x++)
+    {
+      if (GetPixelAlpha(image,q) != TransparentAlpha)
+        SetPixelAlpha(draw_image,OpaqueAlpha,q);
+      q+=GetPixelChannels(draw_image);
+    }
+    if (SyncCacheViewAuthenticPixels(draw_view,exception) == MagickFalse)
+      break;
+  }
+  draw_view=DestroyCacheView(draw_view);
+  (void) XParseGeometry(draw_info->geometry,&x,&y,&width,&height);
+  if (draw_info->stencil == TransparentStencil)
+    (void) CompositeImage(image,CopyOpacityCompositeOp,draw_image,(ssize_t) x,
+      (ssize_t) y);
+  else
+    {
+      matte=image->matte;
+      (void) CompositeImage(image,OverCompositeOp,draw_image,(ssize_t) x,
+        (ssize_t) y);
+      image->matte=matte;
+    }
+  draw_image=DestroyImage(draw_image);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X E r r o r                                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XError() ignores BadWindow errors for XQueryTree and XGetWindowAttributes,
+%  and ignores BadDrawable errors for XGetGeometry, and ignores BadValue errors
+%  for XQueryColor.  It returns MagickFalse in those cases.  Otherwise it returns
+%  True.
+%
+%  The format of the XError function is:
+%
+%      XError(display,error)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o error: Specifies the error event.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+MagickExport int XError(Display *display,XErrorEvent *error)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(error != (XErrorEvent *) NULL);
+  xerror_alert=MagickTrue;
+  switch (error->request_code)
+  {
+    case X_GetGeometry:
+    {
+      if ((int) error->error_code == BadDrawable)
+        return(MagickFalse);
+      break;
+    }
+    case X_GetWindowAttributes:
+    case X_QueryTree:
+    {
+      if ((int) error->error_code == BadWindow)
+        return(MagickFalse);
+      break;
+    }
+    case X_QueryColors:
+    {
+      if ((int) error->error_code == BadValue)
+        return(MagickFalse);
+      break;
+    }
+  }
+  return(MagickTrue);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X F r e e R e s o u r c e s                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XFreeResources() frees X11 resources.
+%
+%  The format of the XFreeResources method is:
+%
+%      void XFreeResources(Display *display,XVisualInfo *visual_info,
+%        XStandardColormap *map_info,XPixelInfo *pixel,XFontStruct *font_info,
+%        XResourceInfo *resource_info,XWindowInfo *window_info)
+%        resource_info,window_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
+%      returned from XGetVisualInfo.
+%
+%    o map_info: If map_type is specified, this structure is initialized
+%      with info from the Standard Colormap.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+%    o font_info: Specifies a pointer to a XFontStruct structure.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+*/
+MagickExport void XFreeResources(Display *display,XVisualInfo *visual_info,
+  XStandardColormap *map_info,XPixelInfo *pixel,XFontStruct *font_info,
+  XResourceInfo *resource_info,XWindowInfo *window_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  if (window_info != (XWindowInfo *) NULL)
+    {
+      /*
+        Free X image.
+      */
+      if (window_info->ximage != (XImage *) NULL)
+        XDestroyImage(window_info->ximage);
+      if (window_info->id != (Window) NULL)
+        {
+          /*
+            Free destroy window and free cursors.
+          */
+          if (window_info->id != XRootWindow(display,visual_info->screen))
+            (void) XDestroyWindow(display,window_info->id);
+          if (window_info->annotate_context != (GC) NULL)
+            (void) XFreeGC(display,window_info->annotate_context);
+          if (window_info->highlight_context != (GC) NULL)
+            (void) XFreeGC(display,window_info->highlight_context);
+          if (window_info->widget_context != (GC) NULL)
+            (void) XFreeGC(display,window_info->widget_context);
+          if (window_info->cursor != (Cursor) NULL)
+            (void) XFreeCursor(display,window_info->cursor);
+          window_info->cursor=(Cursor) NULL;
+          if (window_info->busy_cursor != (Cursor) NULL)
+            (void) XFreeCursor(display,window_info->busy_cursor);
+          window_info->busy_cursor=(Cursor) NULL;
+        }
+    }
+  /*
+    Free font.
+  */
+  if (font_info != (XFontStruct *) NULL)
+    {
+      (void) XFreeFont(display,font_info);
+      font_info=(XFontStruct *) NULL;
+    }
+  if (map_info != (XStandardColormap *) NULL)
+    {
+      /*
+        Free X Standard Colormap.
+      */
+      if (resource_info->map_type == (char *) NULL)
+        (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
+      (void) XFree((void *) map_info);
+    }
+  /*
+    Free X visual info.
+  */
+  if (visual_info != (XVisualInfo *) NULL)
+    (void) XFree((void *) visual_info);
+  if (resource_info->close_server != MagickFalse)
+    (void) XCloseDisplay(display);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X F r e e S t a n d a r d C o l o r m a p                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XFreeStandardColormap() frees an X11 colormap.
+%
+%  The format of the XFreeStandardColormap method is:
+%
+%      void XFreeStandardColormap(Display *display,
+%        const XVisualInfo *visual_info,XStandardColormap *map_info,
+%        XPixelInfo *pixel)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
+%      returned from XGetVisualInfo.
+%
+%    o map_info: If map_type is specified, this structure is initialized
+%      with info from the Standard Colormap.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+*/
+MagickExport void XFreeStandardColormap(Display *display,
+  const XVisualInfo *visual_info,XStandardColormap *map_info,XPixelInfo *pixel)
+{
+  /*
+    Free colormap.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(visual_info != (XVisualInfo *) NULL);
+  assert(map_info != (XStandardColormap *) NULL);
+  (void) XFlush(display);
+  if (map_info->colormap != (Colormap) NULL)
+    {
+      if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
+        (void) XFreeColormap(display,map_info->colormap);
+      else
+        if (pixel != (XPixelInfo *) NULL)
+          if ((visual_info->klass != TrueColor) &&
+              (visual_info->klass != DirectColor))
+            (void) XFreeColors(display,map_info->colormap,pixel->pixels,
+              (int) pixel->colors,0);
+    }
+  map_info->colormap=(Colormap) NULL;
+  if (pixel != (XPixelInfo *) NULL)
+    {
+      if (pixel->pixels != (unsigned long *) NULL)
+        pixel->pixels=(unsigned long *) RelinquishMagickMemory(pixel->pixels);
+      pixel->pixels=(unsigned long *) NULL;
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t A n n o t a t e I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetAnnotateInfo() initializes the AnnotateInfo structure.
+%
+%  The format of the XGetAnnotateInfo method is:
+%
+%      void XGetAnnotateInfo(XAnnotateInfo *annotate_info)
+%
+%  A description of each parameter follows:
+%
+%    o annotate_info: Specifies a pointer to a XAnnotateInfo structure.
+%
+*/
+MagickExport void XGetAnnotateInfo(XAnnotateInfo *annotate_info)
+{
+  /*
+    Initialize annotate structure.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(annotate_info != (XAnnotateInfo *) NULL);
+  annotate_info->x=0;
+  annotate_info->y=0;
+  annotate_info->width=0;
+  annotate_info->height=0;
+  annotate_info->stencil=ForegroundStencil;
+  annotate_info->degrees=0.0;
+  annotate_info->font_info=(XFontStruct *) NULL;
+  annotate_info->text=(char *) NULL;
+  *annotate_info->geometry='\0';
+  annotate_info->previous=(XAnnotateInfo *) NULL;
+  annotate_info->next=(XAnnotateInfo *) NULL;
+  (void) XSupportsLocale();
+  (void) XSetLocaleModifiers("");
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t M a p I n f o                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetMapInfo() initializes the XStandardColormap structure.
+%
+%  The format of the XStandardColormap method is:
+%
+%      void XGetMapInfo(const XVisualInfo *visual_info,const Colormap colormap,
+%        XStandardColormap *map_info)
+%
+%  A description of each parameter follows:
+%
+%    o colormap: Specifies the ID of the X server colormap.
+%
+%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
+%      returned from XGetVisualInfo.
+%
+%    o map_info: Specifies a pointer to a X11 XStandardColormap structure.
+%
+*/
+MagickExport void XGetMapInfo(const XVisualInfo *visual_info,
+  const Colormap colormap,XStandardColormap *map_info)
+{
+  /*
+    Initialize map info.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(visual_info != (XVisualInfo *) NULL);
+  assert(map_info != (XStandardColormap *) NULL);
+  map_info->colormap=colormap;
+  map_info->red_max=visual_info->red_mask;
+  map_info->red_mult=(size_t) (map_info->red_max != 0 ? 1 : 0);
+  if (map_info->red_max != 0)
+    while ((map_info->red_max & 0x01) == 0)
+    {
+      map_info->red_max>>=1;
+      map_info->red_mult<<=1;
+    }
+  map_info->green_max=visual_info->green_mask;
+  map_info->green_mult=(size_t) (map_info->green_max != 0 ? 1 : 0);
+  if (map_info->green_max != 0)
+    while ((map_info->green_max & 0x01) == 0)
+    {
+      map_info->green_max>>=1;
+      map_info->green_mult<<=1;
+    }
+  map_info->blue_max=visual_info->blue_mask;
+  map_info->blue_mult=(size_t) (map_info->blue_max != 0 ? 1 : 0);
+  if (map_info->blue_max != 0)
+    while ((map_info->blue_max & 0x01) == 0)
+    {
+      map_info->blue_max>>=1;
+      map_info->blue_mult<<=1;
+    }
+  map_info->base_pixel=0;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t P i x e l I n f o                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetPixelInfo() initializes the PixelPacket structure.
+%
+%  The format of the XGetPixelInfo method is:
+%
+%      void XGetPixelInfo(Display *display,const XVisualInfo *visual_info,
+%        const XStandardColormap *map_info,const XResourceInfo *resource_info,
+%        Image *image,XPixelInfo *pixel)
+%        pixel)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
+%      returned from XGetVisualInfo.
+%
+%    o map_info: If map_type is specified, this structure is initialized
+%      with info from the Standard Colormap.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o image: the image.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+*/
+MagickExport void XGetPixelInfo(Display *display,
+  const XVisualInfo *visual_info,const XStandardColormap *map_info,
+  const XResourceInfo *resource_info,Image *image,XPixelInfo *pixel)
+{
+  static const char
+    *PenColors[MaxNumberPens]=
+    {
+      "#000000000000",  /* black */
+      "#00000000ffff",  /* blue */
+      "#0000ffffffff",  /* cyan */
+      "#0000ffff0000",  /* green */
+      "#bdbdbdbdbdbd",  /* gray */
+      "#ffff00000000",  /* red */
+      "#ffff0000ffff",  /* magenta */
+      "#ffffffff0000",  /* yellow */
+      "#ffffffffffff",  /* white */
+      "#bdbdbdbdbdbd",  /* gray */
+      "#bdbdbdbdbdbd"   /* gray */
+    };
+
+  Colormap
+    colormap;
+
+  register ssize_t
+    i;
+
+  Status
+    status;
+
+  unsigned int
+    packets;
+
+  /*
+    Initialize pixel info.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(visual_info != (XVisualInfo *) NULL);
+  assert(map_info != (XStandardColormap *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(pixel != (XPixelInfo *) NULL);
+  pixel->colors=0;
+  if (image != (Image *) NULL)
+    if (image->storage_class == PseudoClass)
+      pixel->colors=(ssize_t) image->colors;
+  packets=(unsigned int)
+    MagickMax((int) pixel->colors,visual_info->colormap_size)+MaxNumberPens;
+  if (pixel->pixels != (unsigned long *) NULL)
+    pixel->pixels=(unsigned long *) RelinquishMagickMemory(pixel->pixels);
+  pixel->pixels=(unsigned long *) AcquireQuantumMemory(packets,
+    sizeof(pixel->pixels));
+  if (pixel->pixels == (unsigned long *) NULL)
+    ThrowXWindowFatalException(ResourceLimitFatalError,"UnableToGetPixelInfo",
+      image->filename);
+  /*
+    Set foreground color.
+  */
+  colormap=map_info->colormap;
+  (void) XParseColor(display,colormap,(char *) ForegroundColor,
+    &pixel->foreground_color);
+  status=XParseColor(display,colormap,resource_info->foreground_color,
+    &pixel->foreground_color);
+  if (status == False)
+    ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",
+      resource_info->foreground_color);
+  pixel->foreground_color.pixel=
+    XStandardPixel(map_info,&pixel->foreground_color);
+  pixel->foreground_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set background color.
+  */
+  (void) XParseColor(display,colormap,"#d6d6d6d6d6d6",&pixel->background_color);
+  status=XParseColor(display,colormap,resource_info->background_color,
+    &pixel->background_color);
+  if (status == False)
+    ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",
+      resource_info->background_color);
+  pixel->background_color.pixel=
+    XStandardPixel(map_info,&pixel->background_color);
+  pixel->background_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set border color.
+  */
+  (void) XParseColor(display,colormap,(char *) BorderColor,
+    &pixel->border_color);
+  status=XParseColor(display,colormap,resource_info->border_color,
+    &pixel->border_color);
+  if (status == False)
+    ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",
+      resource_info->border_color);
+  pixel->border_color.pixel=XStandardPixel(map_info,&pixel->border_color);
+  pixel->border_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set matte color.
+  */
+  pixel->matte_color=pixel->background_color;
+  if (resource_info->matte_color != (char *) NULL)
+    {
+      /*
+        Matte color is specified as a X resource or command line argument.
+      */
+      status=XParseColor(display,colormap,resource_info->matte_color,
+        &pixel->matte_color);
+      if (status == False)
+        ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",
+          resource_info->matte_color);
+      pixel->matte_color.pixel=XStandardPixel(map_info,&pixel->matte_color);
+      pixel->matte_color.flags=(char) (DoRed | DoGreen | DoBlue);
+    }
+  /*
+    Set highlight color.
+  */
+  pixel->highlight_color.red=(unsigned short) ((
+    pixel->matte_color.red*ScaleQuantumToShort(HighlightModulate))/65535L+
+    (ScaleQuantumToShort((Quantum) (QuantumRange-HighlightModulate))));
+  pixel->highlight_color.green=(unsigned short) ((
+    pixel->matte_color.green*ScaleQuantumToShort(HighlightModulate))/65535L+
+    (ScaleQuantumToShort((Quantum) (QuantumRange-HighlightModulate))));
+  pixel->highlight_color.blue=(unsigned short) ((
+    pixel->matte_color.blue*ScaleQuantumToShort(HighlightModulate))/65535L+
+    (ScaleQuantumToShort((Quantum) (QuantumRange-HighlightModulate))));
+  pixel->highlight_color.pixel=
+    XStandardPixel(map_info,&pixel->highlight_color);
+  pixel->highlight_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set shadow color.
+  */
+  pixel->shadow_color.red=(unsigned short) (((MagickRealType)
+    pixel->matte_color.red*ScaleQuantumToShort(ShadowModulate))/65535L);
+  pixel->shadow_color.green=(unsigned short) (((MagickRealType)
+    pixel->matte_color.green*ScaleQuantumToShort(ShadowModulate))/65535L);
+  pixel->shadow_color.blue=(unsigned short) (((MagickRealType)
+    pixel->matte_color.blue*ScaleQuantumToShort(ShadowModulate))/65535L);
+  pixel->shadow_color.pixel=XStandardPixel(map_info,&pixel->shadow_color);
+  pixel->shadow_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set depth color.
+  */
+  pixel->depth_color.red=(unsigned short) (((MagickRealType)
+    pixel->matte_color.red*ScaleQuantumToShort(DepthModulate))/65535L);
+  pixel->depth_color.green=(unsigned short) (((MagickRealType)
+    pixel->matte_color.green*ScaleQuantumToShort(DepthModulate))/65535L);
+  pixel->depth_color.blue=(unsigned short) (((MagickRealType)
+    pixel->matte_color.blue*ScaleQuantumToShort(DepthModulate))/65535L);
+  pixel->depth_color.pixel=XStandardPixel(map_info,&pixel->depth_color);
+  pixel->depth_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set trough color.
+  */
+  pixel->trough_color.red=(unsigned short) (((MagickRealType)
+    pixel->matte_color.red*ScaleQuantumToShort(TroughModulate))/65535L);
+  pixel->trough_color.green=(unsigned short) (((MagickRealType)
+    pixel->matte_color.green*ScaleQuantumToShort(TroughModulate))/65535L);
+  pixel->trough_color.blue=(unsigned short) (((MagickRealType)
+    pixel->matte_color.blue*ScaleQuantumToShort(TroughModulate))/65535L);
+  pixel->trough_color.pixel=XStandardPixel(map_info,&pixel->trough_color);
+  pixel->trough_color.flags=(char) (DoRed | DoGreen | DoBlue);
+  /*
+    Set pen color.
+  */
+  for (i=0; i < MaxNumberPens; i++)
+  {
+    (void) XParseColor(display,colormap,(char *) PenColors[i],
+      &pixel->pen_colors[i]);
+    status=XParseColor(display,colormap,resource_info->pen_colors[i],
+      &pixel->pen_colors[i]);
+    if (status == False)
+      ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",
+        resource_info->pen_colors[i]);
+    pixel->pen_colors[i].pixel=XStandardPixel(map_info,&pixel->pen_colors[i]);
+    pixel->pen_colors[i].flags=(char) (DoRed | DoGreen | DoBlue);
+  }
+  pixel->box_color=pixel->background_color;
+  pixel->pen_color=pixel->foreground_color;
+  pixel->box_index=0;
+  pixel->pen_index=1;
+  if (image != (Image *) NULL)
+    {
+      if ((resource_info->gamma_correct != MagickFalse) &&
+          (image->gamma != 0.0))
+        {
+          GeometryInfo
+            geometry_info;
+
+          MagickStatusType
+            flags;
+
+          /*
+            Initialize map relative to display and image gamma.
+          */
+          flags=ParseGeometry(resource_info->display_gamma,&geometry_info);
+          red_gamma=geometry_info.rho;
+          green_gamma=geometry_info.sigma;
+          if ((flags & SigmaValue) == 0)
+            green_gamma=red_gamma;
+          blue_gamma=geometry_info.xi;
+          if ((flags & XiValue) == 0)
+            blue_gamma=red_gamma;
+          red_gamma*=image->gamma;
+          green_gamma*=image->gamma;
+          blue_gamma*=image->gamma;
+        }
+      if (image->storage_class == PseudoClass)
+        {
+          /*
+            Initialize pixel array for images of type PseudoClass.
+          */
+          for (i=0; i < (ssize_t) image->colors; i++)
+            pixel->pixels[i]=XGammaPacket(map_info,image->colormap+i);
+          for (i=0; i < MaxNumberPens; i++)
+            pixel->pixels[image->colors+i]=pixel->pen_colors[i].pixel;
+          pixel->colors+=MaxNumberPens;
+        }
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t R e s o u r c e C l a s s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetResourceClass() queries the X server for the specified resource name or
+%  class.  If the resource name or class is not defined in the database, the
+%  supplied default value is returned.
+%
+%  The format of the XGetResourceClass method is:
+%
+%      char *XGetResourceClass(XrmDatabase database,const char *client_name,
+%        const char *keyword,char *resource_default)
+%
+%  A description of each parameter follows:
+%
+%    o database: Specifies a resource database; returned from
+%      XrmGetStringDatabase.
+%
+%    o client_name:  Specifies the application name used to retrieve resource
+%      info from the X server database.
+%
+%    o keyword: Specifies the keyword of the value being retrieved.
+%
+%    o resource_default: Specifies the default value to return if the query
+%      fails to find the specified keyword/class.
+%
+*/
+MagickExport char *XGetResourceClass(XrmDatabase database,
+  const char *client_name,const char *keyword,char *resource_default)
+{
+  char
+    resource_class[MaxTextExtent],
+    resource_name[MaxTextExtent];
+
+  static char
+    *resource_type;
+
+  Status
+    status;
+
+  XrmValue
+    resource_value;
+
+  if (database == (XrmDatabase) NULL)
+    return(resource_default);
+  *resource_name='\0';
+  *resource_class='\0';
+  if (keyword != (char *) NULL)
+    {
+      int
+        c,
+        k;
+
+      /*
+        Initialize resource keyword and class.
+      */
+      (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.%s",
+        client_name,keyword);
+      c=(int) (*client_name);
+      if ((c >= XK_a) && (c <= XK_z))
+        c-=(XK_a-XK_A);
+      else
+        if ((c >= XK_agrave) && (c <= XK_odiaeresis))
+          c-=(XK_agrave-XK_Agrave);
+        else
+          if ((c >= XK_oslash) && (c <= XK_thorn))
+            c-=(XK_oslash-XK_Ooblique);
+      k=(int) (*keyword);
+      if ((k >= XK_a) && (k <= XK_z))
+        k-=(XK_a-XK_A);
+      else
+        if ((k >= XK_agrave) && (k <= XK_odiaeresis))
+          k-=(XK_agrave-XK_Agrave);
+        else
+          if ((k >= XK_oslash) && (k <= XK_thorn))
+            k-=(XK_oslash-XK_Ooblique);
+      (void) FormatLocaleString(resource_class,MaxTextExtent,"%c%s.%c%s",c,
+        client_name+1,k,keyword+1);
+    }
+  status=XrmGetResource(database,resource_name,resource_class,&resource_type,
+    &resource_value);
+  if (status == False)
+    return(resource_default);
+  return(resource_value.addr);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t R e s o u r c e D a t a b a s e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetResourceDatabase() creates a new resource database and initializes it.
+%
+%  The format of the XGetResourceDatabase method is:
+%
+%      XrmDatabase XGetResourceDatabase(Display *display,
+%        const char *client_name)
+%
+%  A description of each parameter follows:
+%
+%    o database: XGetResourceDatabase() returns the database after it is
+%      initialized.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o client_name:  Specifies the application name used to retrieve resource
+%      info from the X server database.
+%
+*/
+MagickExport XrmDatabase XGetResourceDatabase(Display *display,
+  const char *client_name)
+{
+  char
+    filename[MaxTextExtent];
+
+  int
+    c;
+
+  register const char
+    *p;
+
+  XrmDatabase
+    resource_database,
+    server_database;
+
+  if (display == (Display *) NULL)
+    return((XrmDatabase) NULL);
+  assert(client_name != (char *) NULL);
+  /*
+    Initialize resource database.
+  */
+  XrmInitialize();
+  (void) XGetDefault(display,(char *) client_name,"dummy");
+  resource_database=XrmGetDatabase(display);
+  /*
+    Combine application database.
+  */
+  if (client_name != (char *) NULL)
+    {
+      /*
+        Get basename of client.
+      */
+      p=client_name+(strlen(client_name)-1);
+      while ((p > client_name) && (*p != '/'))
+        p--;
+      if (*p == '/')
+        client_name=p+1;
+    }
+  c=(int) (*client_name);
+  if ((c >= XK_a) && (c <= XK_z))
+    c-=(XK_a-XK_A);
+  else
+    if ((c >= XK_agrave) && (c <= XK_odiaeresis))
+      c-=(XK_agrave-XK_Agrave);
+    else
+      if ((c >= XK_oslash) && (c <= XK_thorn))
+        c-=(XK_oslash-XK_Ooblique);
+#if defined(X11_APPLICATION_PATH)
+  (void) FormatLocaleString(filename,MaxTextExtent,"%s%c%s",
+    X11_APPLICATION_PATH,c,client_name+1);
+  (void) XrmCombineFileDatabase(filename,&resource_database,MagickFalse);
+#endif
+  if (XResourceManagerString(display) != (char *) NULL)
+    {
+      /*
+        Combine server database.
+      */
+      server_database=XrmGetStringDatabase(XResourceManagerString(display));
+      XrmCombineDatabase(server_database,&resource_database,MagickFalse);
+    }
+  /*
+    Merge user preferences database.
+  */
+#if defined(X11_PREFERENCES_PATH)
+  (void) FormatLocaleString(filename,MaxTextExtent,"%s%src",
+    X11_PREFERENCES_PATH,client_name);
+  ExpandFilename(filename);
+  (void) XrmCombineFileDatabase(filename,&resource_database,MagickFalse);
+#endif
+  return(resource_database);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t R e s o u r c e I n f o                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetResourceInfo(image_info,) initializes the ResourceInfo structure.
+%
+%  The format of the XGetResourceInfo method is:
+%
+%      void XGetResourceInfo(const ImageInfo *image_info,XrmDatabase database,
+%        const char *client_name,XResourceInfo *resource_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o database: Specifies a resource database; returned from
+%      XrmGetStringDatabase.
+%
+%    o client_name:  Specifies the application name used to retrieve
+%      resource info from the X server database.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+*/
+MagickExport void XGetResourceInfo(const ImageInfo *image_info,
+  XrmDatabase database,const char *client_name,XResourceInfo *resource_info)
+{
+  char
+    *directory,
+    *resource_value;
+
+  /*
+    Initialize resource info fields.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(resource_info != (XResourceInfo *) NULL);
+  (void) ResetMagickMemory(resource_info,0,sizeof(*resource_info));
+  resource_info->resource_database=database;
+  resource_info->image_info=(ImageInfo *) image_info;
+  (void) SetImageInfoProgressMonitor(resource_info->image_info,
+    XMagickProgressMonitor,(void *) NULL);
+  resource_info->quantize_info=CloneQuantizeInfo((QuantizeInfo *) NULL);
+  resource_info->close_server=MagickTrue;
+  resource_info->client_name=AcquireString(client_name);
+  resource_value=XGetResourceClass(database,client_name,"backdrop",
+    (char *) "False");
+  resource_info->backdrop=IsMagickTrue(resource_value);
+  resource_info->background_color=XGetResourceInstance(database,client_name,
+    "background",(char *) "#d6d6d6d6d6d6");
+  resource_info->border_color=XGetResourceInstance(database,client_name,
+    "borderColor",BorderColor);
+  resource_value=XGetResourceClass(database,client_name,"borderWidth",
+    (char *) "2");
+  resource_info->border_width=(unsigned int) StringToUnsignedLong(
+    resource_value);
+  resource_value=XGetResourceClass(database,client_name,"colormap",
+    (char *) "shared");
+  resource_info->colormap=UndefinedColormap;
+  if (LocaleCompare("private",resource_value) == 0)
+    resource_info->colormap=PrivateColormap;
+  if (LocaleCompare("shared",resource_value) == 0)
+    resource_info->colormap=SharedColormap;
+  if (resource_info->colormap == UndefinedColormap)
+    ThrowXWindowFatalException(OptionError,"UnrecognizedColormapType",
+      resource_value);
+  resource_value=XGetResourceClass(database,client_name,
+    "colorRecovery",(char *) "False");
+  resource_info->color_recovery=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"confirmExit",
+    (char *) "False");
+  resource_info->confirm_exit=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"confirmEdit",
+    (char *) "False");
+  resource_info->confirm_edit=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"delay",(char *) "1");
+  resource_info->delay=(unsigned int) StringToUnsignedLong(resource_value);
+  resource_info->display_gamma=XGetResourceClass(database,client_name,
+    "displayGamma",(char *) "2.2");
+  resource_value=XGetResourceClass(database,client_name,"displayWarnings",
+    (char *) "True");
+  resource_info->display_warnings=IsMagickTrue(resource_value);
+  resource_info->font=XGetResourceClass(database,client_name,"font",
+    (char *) NULL);
+  resource_info->font=XGetResourceClass(database,client_name,"fontList",
+    resource_info->font);
+  resource_info->font_name[0]=XGetResourceClass(database,client_name,"font1",
+    (char *) "fixed");
+  resource_info->font_name[1]=XGetResourceClass(database,client_name,"font2",
+    (char *) "variable");
+  resource_info->font_name[2]=XGetResourceClass(database,client_name,"font3",
+    (char *) "5x8");
+  resource_info->font_name[3]=XGetResourceClass(database,client_name,"font4",
+    (char *) "6x10");
+  resource_info->font_name[4]=XGetResourceClass(database,client_name,"font5",
+    (char *) "7x13bold");
+  resource_info->font_name[5]=XGetResourceClass(database,client_name,"font6",
+    (char *) "8x13bold");
+  resource_info->font_name[6]=XGetResourceClass(database,client_name,"font7",
+    (char *) "9x15bold");
+  resource_info->font_name[7]=XGetResourceClass(database,client_name,"font8",
+    (char *) "10x20");
+  resource_info->font_name[8]=XGetResourceClass(database,client_name,"font9",
+    (char *) "12x24");
+  resource_info->font_name[9]=XGetResourceClass(database,client_name,"font0",
+    (char *) "fixed");
+  resource_info->font_name[10]=XGetResourceClass(database,client_name,"font0",
+    (char *) "fixed");
+  resource_info->foreground_color=XGetResourceInstance(database,client_name,
+    "foreground",ForegroundColor);
+  resource_value=XGetResourceClass(database,client_name,"gammaCorrect",
+    (char *) "True");
+  resource_info->gamma_correct=IsMagickTrue(resource_value);
+  resource_info->image_geometry=ConstantString(XGetResourceClass(database,
+    client_name,"geometry",(char *) NULL));
+  resource_value=XGetResourceClass(database,client_name,"gravity",
+    (char *) "Center");
+  resource_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
+    MagickFalse,resource_value);
+  directory=getcwd(resource_info->home_directory,MaxTextExtent);
+  (void) directory;
+  resource_info->icon_geometry=XGetResourceClass(database,client_name,
+    "iconGeometry",(char *) NULL);
+  resource_value=XGetResourceClass(database,client_name,"iconic",
+    (char *) "False");
+  resource_info->iconic=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"immutable",
+    LocaleCompare(client_name,"PerlMagick") == 0 ? (char *) "True" :
+    (char *) "False");
+  resource_info->immutable=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"magnify",
+    (char *) "3");
+  resource_info->magnify=(unsigned int) StringToUnsignedLong(resource_value);
+  resource_info->map_type=XGetResourceClass(database,client_name,"map",
+    (char *) NULL);
+  resource_info->matte_color=XGetResourceInstance(database,client_name,
+    "mattecolor",(char *) NULL);
+  resource_info->name=ConstantString(XGetResourceClass(database,client_name,
+    "name",(char *) NULL));
+  resource_info->pen_colors[0]=XGetResourceClass(database,client_name,"pen1",
+    (char *) "black");
+  resource_info->pen_colors[1]=XGetResourceClass(database,client_name,"pen2",
+    (char *) "blue");
+  resource_info->pen_colors[2]=XGetResourceClass(database,client_name,"pen3",
+    (char *) "cyan");
+  resource_info->pen_colors[3]=XGetResourceClass(database,client_name,"pen4",
+    (char *) "green");
+  resource_info->pen_colors[4]=XGetResourceClass(database,client_name,"pen5",
+    (char *) "gray");
+  resource_info->pen_colors[5]=XGetResourceClass(database,client_name,"pen6",
+    (char *) "red");
+  resource_info->pen_colors[6]=XGetResourceClass(database,client_name,"pen7",
+    (char *) "magenta");
+  resource_info->pen_colors[7]=XGetResourceClass(database,client_name,"pen8",
+    (char *) "yellow");
+  resource_info->pen_colors[8]=XGetResourceClass(database,client_name,"pen9",
+    (char *) "white");
+  resource_info->pen_colors[9]=XGetResourceClass(database,client_name,"pen0",
+    (char *) "gray");
+  resource_info->pen_colors[10]=XGetResourceClass(database,client_name,"pen0",
+    (char *) "gray");
+  resource_value=XGetResourceClass(database,client_name,"pause",(char *) "0");
+  resource_info->pause=(unsigned int) StringToUnsignedLong(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"quantum",(char *) "1");
+  resource_info->quantum=StringToLong(resource_value);
+  resource_info->text_font=XGetResourceClass(database,client_name,(char *)
+    "font",(char *) "fixed");
+  resource_info->text_font=XGetResourceClass(database,client_name,
+    "textFontList",resource_info->text_font);
+  resource_info->title=XGetResourceClass(database,client_name,"title",
+    (char *) NULL);
+  resource_value=XGetResourceClass(database,client_name,"undoCache",
+    (char *) "16");
+  resource_info->undo_cache=(unsigned int) StringToUnsignedLong(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"update",
+    (char *) "False");
+  resource_info->update=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"usePixmap",
+    (char *) "True");
+  resource_info->use_pixmap=IsMagickTrue(resource_value);
+  resource_value=XGetResourceClass(database,client_name,"sharedMemory",
+    (char *) "True");
+  resource_info->use_shared_memory=IsMagickTrue(resource_value);
+  resource_info->visual_type=XGetResourceClass(database,client_name,"visual",
+    (char *) NULL);
+  resource_info->window_group=XGetResourceClass(database,client_name,
+    "windowGroup",(char *) NULL);
+  resource_info->window_id=XGetResourceClass(database,client_name,"window",
+    (char *) NULL);
+  resource_info->write_filename=XGetResourceClass(database,client_name,
+    "writeFilename",(char *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t R e s o u r c e I n s t a n c e                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetResourceInstance() queries the X server for the specified resource name.
+%  If the resource name is not defined in the database, the supplied default
+%  value is returned.
+%
+%  The format of the XGetResourceInstance method is:
+%
+%      char *XGetResourceInstance(XrmDatabase database,const char *client_name,
+%        const char *keyword,const char *resource_default)
+%
+%  A description of each parameter follows:
+%
+%    o database: Specifies a resource database; returned from
+%      XrmGetStringDatabase.
+%
+%    o client_name:  Specifies the application name used to retrieve
+%      resource info from the X server database.
+%
+%    o keyword: Specifies the keyword of the value being retrieved.
+%
+%    o resource_default: Specifies the default value to return if the query
+%      fails to find the specified keyword/class.
+%
+*/
+MagickExport char *XGetResourceInstance(XrmDatabase database,
+  const char *client_name,const char *keyword,const char *resource_default)
+{
+  char
+    *resource_type,
+    resource_name[MaxTextExtent];
+
+  Status
+    status;
+
+  XrmValue
+    resource_value;
+
+  if (database == (XrmDatabase) NULL)
+    return((char *) resource_default);
+  *resource_name='\0';
+  if (keyword != (char *) NULL)
+    (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.%s",client_name,
+      keyword);
+  status=XrmGetResource(database,resource_name,"ImageMagick",&resource_type,
+    &resource_value);
+  if (status == False)
+    return((char *) resource_default);
+  return(resource_value.addr);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t S c r e e n D e n s i t y                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetScreenDensity() returns the density of the X server screen in
+%  dots-per-inch.
+%
+%  The format of the XGetScreenDensity method is:
+%
+%      char *XGetScreenDensity(Display *display)
+%
+%  A description of each parameter follows:
+%
+%    o density: XGetScreenDensity() returns the density of the X screen in
+%      dots-per-inch.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+*/
+MagickExport char *XGetScreenDensity(Display *display)
+{
+  char
+    density[MaxTextExtent];
+
+  double
+    x_density,
+    y_density;
+
+  /*
+    Set density as determined by screen size.
+  */
+  x_density=((((double) DisplayWidth(display,XDefaultScreen(display)))*25.4)/
+    ((double) DisplayWidthMM(display,XDefaultScreen(display))));
+  y_density=((((double) DisplayHeight(display,XDefaultScreen(display)))*25.4)/
+    ((double) DisplayHeightMM(display,XDefaultScreen(display))));
+  (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",x_density,
+    y_density);
+  return(GetPageGeometry(density));
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X G e t S u b w i n d o w                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetSubwindow() returns the subwindow of a window chosen the user with the
+%  pointer and a button press.
+%
+%  The format of the XGetSubwindow method is:
+%
+%      Window XGetSubwindow(Display *display,Window window,int x,int y)
+%
+%  A description of each parameter follows:
+%
+%    o subwindow: XGetSubwindow() returns NULL if no subwindow is found
+%      otherwise the subwindow is returned.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window.
+%
+%    o x: the x coordinate of the pointer relative to the origin of the
+%      window.
+%
+%    o y: the y coordinate of the pointer relative to the origin of the
+%      window.
+%
+*/
+static Window XGetSubwindow(Display *display,Window window,int x,int y)
+{
+  int
+    x_offset,
+    y_offset;
+
+  Status
+    status;
+
+  Window
+    source_window,
+    target_window;
+
+  assert(display != (Display *) NULL);
+  source_window=XRootWindow(display,XDefaultScreen(display));
+  if (window == (Window) NULL)
+    return(source_window);
+  target_window=window;
+  for ( ; ; )
+  {
+    status=XTranslateCoordinates(display,source_window,window,x,y,
+      &x_offset,&y_offset,&target_window);
+    if (status != True)
+      break;
+    if (target_window == (Window) NULL)
+      break;
+    source_window=window;
+    window=target_window;
+    x=x_offset;
+    y=y_offset;
+  }
+  if (target_window == (Window) NULL)
+    target_window=window;
+  return(target_window);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t W i n d o w C o l o r                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetWindowColor() returns the color of a pixel interactively chosen from the
+%  X server.
+%
+%  The format of the XGetWindowColor method is:
+%
+%      MagickBooleanType XGetWindowColor(Display *display,XWindows *windows,
+%        char *name)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o name: the name of the color if found in the X Color Database is
+%      returned in this character string.
+%
+*/
+MagickExport MagickBooleanType XGetWindowColor(Display *display,
+  XWindows *windows,char *name)
+{
+  int
+    x,
+    y;
+
+  PixelPacket
+    pixel;
+
+  RectangleInfo
+    crop_info;
+
+  Status
+    status;
+
+  Window
+    child,
+    client_window,
+    root_window,
+    target_window;
+
+  XColor
+    color;
+
+  XImage
+    *ximage;
+
+  XWindowAttributes
+    window_attributes;
+
+  /*
+    Choose a pixel from the X server.
+  */
+  assert(display != (Display *) NULL);
+  assert(name != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
+  *name='\0';
+  target_window=XSelectWindow(display,&crop_info);
+  if (target_window == (Window) NULL)
+    return(MagickFalse);
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  client_window=target_window;
+  if (target_window != root_window)
+    {
+      unsigned int
+        d;
+
+      /*
+        Get client window.
+      */
+      status=XGetGeometry(display,target_window,&root_window,&x,&x,&d,&d,&d,&d);
+      if (status != False)
+        {
+          client_window=XClientWindow(display,target_window);
+          target_window=client_window;
+        }
+    }
+  /*
+    Verify window is viewable.
+  */
+  status=XGetWindowAttributes(display,target_window,&window_attributes);
+  if ((status == False) || (window_attributes.map_state != IsViewable))
+    return(MagickFalse);
+  /*
+    Get window X image.
+  */
+  (void) XTranslateCoordinates(display,root_window,target_window,
+    (int) crop_info.x,(int) crop_info.y,&x,&y,&child);
+  ximage=XGetImage(display,target_window,x,y,1,1,AllPlanes,ZPixmap);
+  if (ximage == (XImage *) NULL)
+    return(MagickFalse);
+  color.pixel=XGetPixel(ximage,0,0);
+  XDestroyImage(ximage);
+  /*
+    Match color against the color database.
+  */
+  (void) XQueryColor(display,window_attributes.colormap,&color);
+  pixel.red=ScaleShortToQuantum(color.red);
+  pixel.green=ScaleShortToQuantum(color.green);
+  pixel.blue=ScaleShortToQuantum(color.blue);
+  pixel.alpha=OpaqueAlpha;
+  (void) QueryColorname(windows->image.image,&pixel,X11Compliance,name,
+    &windows->image.image->exception);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X G e t W i n d o w I m a g e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetWindowImage() reads an image from the target X window and returns it.
+%  XGetWindowImage() optionally descends the window hierarchy and overlays the
+%  target image with each child image in an optimized fashion.  Any child
+%  window that have the same visual, colormap, and are contained by its parent
+%  are exempted.
+%
+%  The format of the XGetWindowImage method is:
+%
+%      Image *XGetWindowImage(Display *display,const Window window,
+%        const unsigned int borders,const unsigned int level)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies the window to obtain the image from.
+%
+%    o borders: Specifies whether borders pixels are to be saved with
+%      the image.
+%
+%    o level: Specifies an unsigned integer representing the level of
+%      decent in the window hierarchy.  This value must be zero or one on
+%      the initial call to XGetWindowImage.  A value of zero returns after
+%      one call.  A value of one causes the function to descend the window
+%      hierarchy and overlay the target image with each subwindow image.
+%
+*/
+static Image *XGetWindowImage(Display *display,const Window window,
+  const unsigned int borders,const unsigned int level)
+{
+  typedef struct _ColormapInfo
+  {
+    Colormap
+      colormap;
+
+    XColor
+      *colors;
+
+    struct _ColormapInfo
+      *next;
+  } ColormapInfo;
+
+  typedef struct _WindowInfo
+  {
+    Window
+      window,
+      parent;
+
+    Visual
+      *visual;
+
+    Colormap
+      colormap;
+
+    XSegment
+      bounds;
+
+    RectangleInfo
+      crop_info;
+  } WindowInfo;
+
+  int
+    display_height,
+    display_width,
+    id,
+    x_offset,
+    y_offset;
+
+  Quantum
+    index;
+
+  RectangleInfo
+    crop_info;
+
+  register int
+    i;
+
+  static ColormapInfo
+    *colormap_info = (ColormapInfo *) NULL;
+
+  static int
+    max_windows = 0,
+    number_windows = 0;
+
+  static WindowInfo
+    *window_info;
+
+  Status
+    status;
+
+  Window
+    child,
+    root_window;
+
+  XWindowAttributes
+    window_attributes;
+
+  /*
+    Verify window is viewable.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  status=XGetWindowAttributes(display,window,&window_attributes);
+  if ((status == False) || (window_attributes.map_state != IsViewable))
+    return((Image *) NULL);
+  /*
+    Cropping rectangle is relative to root window.
+  */
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  (void) XTranslateCoordinates(display,window,root_window,0,0,&x_offset,
+    &y_offset,&child);
+  crop_info.x=(ssize_t) x_offset;
+  crop_info.y=(ssize_t) y_offset;
+  crop_info.width=(size_t) window_attributes.width;
+  crop_info.height=(size_t) window_attributes.height;
+  if (borders != MagickFalse)
+    {
+      /*
+        Include border in image.
+      */
+      crop_info.x-=(ssize_t) window_attributes.border_width;
+      crop_info.y-=(ssize_t) window_attributes.border_width;
+      crop_info.width+=(size_t) (window_attributes.border_width << 1);
+      crop_info.height+=(size_t) (window_attributes.border_width << 1);
+    }
+  /*
+    Crop to root window.
+  */
+  if (crop_info.x < 0)
+    {
+      crop_info.width+=crop_info.x;
+      crop_info.x=0;
+    }
+  if (crop_info.y < 0)
+    {
+      crop_info.height+=crop_info.y;
+      crop_info.y=0;
+    }
+  display_width=XDisplayWidth(display,XDefaultScreen(display));
+  if ((int) (crop_info.x+crop_info.width) > display_width)
+    crop_info.width=(size_t) (display_width-crop_info.x);
+  display_height=XDisplayHeight(display,XDefaultScreen(display));
+  if ((int) (crop_info.y+crop_info.height) > display_height)
+    crop_info.height=(size_t) (display_height-crop_info.y);
+  /*
+    Initialize window info attributes.
+  */
+  if (number_windows >= max_windows)
+    {
+      /*
+        Allocate or resize window info buffer.
+      */
+      max_windows+=1024;
+      if (window_info == (WindowInfo *) NULL)
+        window_info=(WindowInfo *) AcquireQuantumMemory((size_t) max_windows,
+          sizeof(*window_info));
+      else
+        window_info=(WindowInfo *) ResizeQuantumMemory(window_info,(size_t)
+          max_windows,sizeof(*window_info));
+    }
+  if (window_info == (WindowInfo *) NULL)
+    {
+      ThrowXWindowFatalException(ResourceLimitError,
+        "MemoryAllocationFailed","...");
+      return((Image *) NULL);
+    }
+  id=number_windows++;
+  window_info[id].window=window;
+  window_info[id].visual=window_attributes.visual;
+  window_info[id].colormap=window_attributes.colormap;
+  window_info[id].bounds.x1=(short) crop_info.x;
+  window_info[id].bounds.y1=(short) crop_info.y;
+  window_info[id].bounds.x2=(short) (crop_info.x+(int) crop_info.width-1);
+  window_info[id].bounds.y2=(short) (crop_info.y+(int) crop_info.height-1);
+  crop_info.x-=x_offset;
+  crop_info.y-=y_offset;
+  window_info[id].crop_info=crop_info;
+  if (level != 0)
+    {
+      unsigned int
+        number_children;
+
+      Window
+        *children;
+
+      /*
+        Descend the window hierarchy.
+      */
+      status=XQueryTree(display,window,&root_window,&window_info[id].parent,
+        &children,&number_children);
+      for (i=0; i < id; i++)
+        if ((window_info[i].window == window_info[id].parent) &&
+            (window_info[i].visual == window_info[id].visual) &&
+            (window_info[i].colormap == window_info[id].colormap))
+          {
+            if ((window_info[id].bounds.x1 <= window_info[i].bounds.x1) ||
+                (window_info[id].bounds.x1 >= window_info[i].bounds.x2) ||
+                (window_info[id].bounds.y1 <= window_info[i].bounds.y1) ||
+                (window_info[id].bounds.y1 >= window_info[i].bounds.y2))
+              {
+                /*
+                  Eliminate windows not circumscribed by their parent.
+                */
+                number_windows--;
+                break;
+              }
+          }
+      if ((status == True) && (number_children != 0))
+        {
+          for (i=0; i < (int) number_children; i++)
+            (void) XGetWindowImage(display,children[i],MagickFalse,level+1);
+          (void) XFree((void *) children);
+        }
+    }
+  if (level <= 1)
+    {
+      CacheView
+        *composite_view;
+
+      ColormapInfo
+        *next;
+
+      ExceptionInfo
+        *exception;
+
+      Image
+        *composite_image,
+        *image;
+
+      int
+        y;
+
+      MagickBooleanType
+        import;
+
+      register int
+        j,
+        x;
+
+      register Quantum
+        *restrict q;
+
+      register size_t
+        pixel;
+
+      unsigned int
+        number_colors;
+
+      XColor
+        *colors;
+
+      XImage
+        *ximage;
+
+      /*
+        Get X image for each window in the list.
+      */
+      image=NewImageList();
+      for (id=0; id < number_windows; id++)
+      {
+        /*
+          Does target window intersect top level window?
+        */
+        import=
+          ((window_info[id].bounds.x2 >= window_info[0].bounds.x1) &&
+           (window_info[id].bounds.x1 <= window_info[0].bounds.x2) &&
+           (window_info[id].bounds.y2 >= window_info[0].bounds.y1) &&
+           (window_info[id].bounds.y1 <= window_info[0].bounds.y2)) ?
+          MagickTrue : MagickFalse;
+        /*
+          Is target window contained by another window with the same colormap?
+        */
+        for (j=0; j < id; j++)
+          if ((window_info[id].visual == window_info[j].visual) &&
+              (window_info[id].colormap == window_info[j].colormap))
+            {
+              if ((window_info[id].bounds.x1 <= window_info[j].bounds.x1) ||
+                  (window_info[id].bounds.x1 >= window_info[j].bounds.x2) ||
+                  (window_info[id].bounds.y1 <= window_info[j].bounds.y1) ||
+                  (window_info[id].bounds.y1 >= window_info[j].bounds.y2))
+                  import=MagickFalse;
+            }
+          else
+            if ((window_info[id].visual != window_info[j].visual) ||
+                (window_info[id].colormap != window_info[j].colormap))
+              {
+                if ((window_info[id].bounds.x2 > window_info[j].bounds.x1) &&
+                    (window_info[id].bounds.x1 < window_info[j].bounds.x2) &&
+                    (window_info[id].bounds.y2 > window_info[j].bounds.y1) &&
+                    (window_info[id].bounds.y1 < window_info[j].bounds.y2))
+                  import=MagickTrue;
+              }
+        if (import == MagickFalse)
+          continue;
+        /*
+          Get X image.
+        */
+        ximage=XGetImage(display,window_info[id].window,(int)
+          window_info[id].crop_info.x,(int) window_info[id].crop_info.y,
+          (unsigned int) window_info[id].crop_info.width,(unsigned int)
+          window_info[id].crop_info.height,AllPlanes,ZPixmap);
+        if (ximage == (XImage *) NULL)
+          continue;
+        /*
+          Initialize window colormap.
+        */
+        number_colors=0;
+        colors=(XColor *) NULL;
+        if (window_info[id].colormap != (Colormap) NULL)
+          {
+            ColormapInfo
+              *p;
+
+            /*
+              Search colormap list for window colormap.
+            */
+            number_colors=(unsigned int) window_info[id].visual->map_entries;
+            for (p=colormap_info; p != (ColormapInfo *) NULL; p=p->next)
+              if (p->colormap == window_info[id].colormap)
+                break;
+            if (p == (ColormapInfo *) NULL)
+              {
+                /*
+                  Get the window colormap.
+                */
+                colors=(XColor *) AcquireQuantumMemory(number_colors,
+                  sizeof(*colors));
+                if (colors == (XColor *) NULL)
+                  {
+                    XDestroyImage(ximage);
+                    return((Image *) NULL);
+                  }
+                if ((window_info[id].visual->klass != DirectColor) &&
+                    (window_info[id].visual->klass != TrueColor))
+                  for (i=0; i < (int) number_colors; i++)
+                  {
+                    colors[i].pixel=(size_t) i;
+                    colors[i].pad='\0';
+                  }
+                else
+                  {
+                    size_t
+                      blue,
+                      blue_bit,
+                      green,
+                      green_bit,
+                      red,
+                      red_bit;
+
+                    /*
+                      DirectColor or TrueColor visual.
+                    */
+                    red=0;
+                    green=0;
+                    blue=0;
+                    red_bit=window_info[id].visual->red_mask &
+                      (~(window_info[id].visual->red_mask)+1);
+                    green_bit=window_info[id].visual->green_mask &
+                      (~(window_info[id].visual->green_mask)+1);
+                    blue_bit=window_info[id].visual->blue_mask &
+                      (~(window_info[id].visual->blue_mask)+1);
+                    for (i=0; i < (int) number_colors; i++)
+                    {
+                      colors[i].pixel=(unsigned long) (red | green | blue);
+                      colors[i].pad='\0';
+                      red+=red_bit;
+                      if (red > window_info[id].visual->red_mask)
+                        red=0;
+                      green+=green_bit;
+                      if (green > window_info[id].visual->green_mask)
+                        green=0;
+                      blue+=blue_bit;
+                      if (blue > window_info[id].visual->blue_mask)
+                        blue=0;
+                    }
+                  }
+                (void) XQueryColors(display,window_info[id].colormap,colors,
+                  (int) number_colors);
+                /*
+                  Append colormap to colormap list.
+                */
+                p=(ColormapInfo *) AcquireMagickMemory(sizeof(*p));
+                if (p == (ColormapInfo *) NULL)
+                  return((Image *) NULL);
+                p->colormap=window_info[id].colormap;
+                p->colors=colors;
+                p->next=colormap_info;
+                colormap_info=p;
+              }
+            colors=p->colors;
+          }
+        /*
+          Allocate image structure.
+        */
+        composite_image=AcquireImage((ImageInfo *) NULL);
+        if (composite_image == (Image *) NULL)
+          {
+            XDestroyImage(ximage);
+            return((Image *) NULL);
+          }
+        /*
+          Convert X image to MIFF format.
+        */
+        if ((window_info[id].visual->klass != TrueColor) &&
+            (window_info[id].visual->klass != DirectColor))
+          composite_image->storage_class=PseudoClass;
+        composite_image->columns=(size_t) ximage->width;
+        composite_image->rows=(size_t) ximage->height;
+        exception=(&composite_image->exception);
+        composite_view=AcquireCacheView(composite_image);
+        switch (composite_image->storage_class)
+        {
+          case DirectClass:
+          default:
+          {
+            register size_t
+              color,
+              index;
+
+            size_t
+              blue_mask,
+              blue_shift,
+              green_mask,
+              green_shift,
+              red_mask,
+              red_shift;
+
+            /*
+              Determine shift and mask for red, green, and blue.
+            */
+            red_mask=window_info[id].visual->red_mask;
+            red_shift=0;
+            while ((red_mask != 0) && ((red_mask & 0x01) == 0))
+            {
+              red_mask>>=1;
+              red_shift++;
+            }
+            green_mask=window_info[id].visual->green_mask;
+            green_shift=0;
+            while ((green_mask != 0) && ((green_mask & 0x01) == 0))
+            {
+              green_mask>>=1;
+              green_shift++;
+            }
+            blue_mask=window_info[id].visual->blue_mask;
+            blue_shift=0;
+            while ((blue_mask != 0) && ((blue_mask & 0x01) == 0))
+            {
+              blue_mask>>=1;
+              blue_shift++;
+            }
+            /*
+              Convert X image to DirectClass packets.
+            */
+            if ((number_colors != 0) &&
+                (window_info[id].visual->klass == DirectColor))
+              for (y=0; y < (int) composite_image->rows; y++)
+              {
+                q=QueueCacheViewAuthenticPixels(composite_view,0,(ssize_t) y,
+                  composite_image->columns,1,exception);
+                if (q == (const Quantum *) NULL)
+                  break;
+                for (x=0; x < (int) composite_image->columns; x++)
+                {
+                  pixel=XGetPixel(ximage,x,y);
+                  index=(pixel >> red_shift) & red_mask;
+                  SetPixelRed(composite_image,
+                    ScaleShortToQuantum(colors[index].red),q);
+                  index=(pixel >> green_shift) & green_mask;
+                  SetPixelGreen(composite_image,
+                    ScaleShortToQuantum(colors[index].green),q);
+                  index=(pixel >> blue_shift) & blue_mask;
+                  SetPixelBlue(composite_image,
+                    ScaleShortToQuantum(colors[index].blue),q);
+                  q+=GetPixelChannels(composite_image);
+                }
+                if (SyncCacheViewAuthenticPixels(composite_view,exception) == MagickFalse)
+                  break;
+              }
+            else
+              for (y=0; y < (int) composite_image->rows; y++)
+              {
+                q=QueueCacheViewAuthenticPixels(composite_view,0,(ssize_t) y,
+                  composite_image->columns,1,exception);
+                if (q == (const Quantum *) NULL)
+                  break;
+                for (x=0; x < (int) composite_image->columns; x++)
+                {
+                  pixel=XGetPixel(ximage,x,y);
+                  color=(pixel >> red_shift) & red_mask;
+                  color=(65535UL*color)/red_mask;
+                  SetPixelRed(composite_image,
+                    ScaleShortToQuantum((unsigned short) color),q);
+                  color=(pixel >> green_shift) & green_mask;
+                  color=(65535UL*color)/green_mask;
+                  SetPixelGreen(composite_image,
+                    ScaleShortToQuantum((unsigned short) color),q);
+                  color=(pixel >> blue_shift) & blue_mask;
+                  color=(65535UL*color)/blue_mask;
+                  SetPixelBlue(composite_image,
+                    ScaleShortToQuantum((unsigned short) color),q);
+                  q+=GetPixelChannels(composite_image);
+                }
+                if (SyncCacheViewAuthenticPixels(composite_view,exception) == MagickFalse)
+                  break;
+              }
+            break;
+          }
+          case PseudoClass:
+          {
+            /*
+              Create colormap.
+            */
+            if (AcquireImageColormap(composite_image,number_colors) == MagickFalse)
+              {
+                XDestroyImage(ximage);
+                composite_image=DestroyImage(composite_image);
+                return((Image *) NULL);
+              }
+            for (i=0; i < (int) composite_image->colors; i++)
+            {
+              composite_image->colormap[colors[i].pixel].red=
+                ScaleShortToQuantum(colors[i].red);
+              composite_image->colormap[colors[i].pixel].green=
+                ScaleShortToQuantum(colors[i].green);
+              composite_image->colormap[colors[i].pixel].blue=
+                ScaleShortToQuantum(colors[i].blue);
+            }
+            /*
+              Convert X image to PseudoClass packets.
+            */
+            for (y=0; y < (int) composite_image->rows; y++)
+            {
+              q=QueueCacheViewAuthenticPixels(composite_view,0,(ssize_t) y,
+                composite_image->columns,1,exception);
+              if (q == (const Quantum *) NULL)
+                break;
+              for (x=0; x < (int) composite_image->columns; x++)
+              {
+                index=(Quantum) XGetPixel(ximage,x,y);
+                SetPixelIndex(composite_image,index,q);
+                SetPixelPacket(composite_image,
+                  composite_image->colormap+(ssize_t) index,q);
+                q+=GetPixelChannels(composite_image);
+              }
+              if (SyncCacheViewAuthenticPixels(composite_view,exception) == MagickFalse)
+                break;
+            }
+            break;
+          }
+        }
+        composite_view=DestroyCacheView(composite_view);
+        XDestroyImage(ximage);
+        if (image == (Image *) NULL)
+          {
+            image=composite_image;
+            continue;
+          }
+        /*
+          Composite any children in back-to-front order.
+        */
+        (void) XTranslateCoordinates(display,window_info[id].window,window,0,0,
+          &x_offset,&y_offset,&child);
+        x_offset-=(int) crop_info.x;
+        if (x_offset < 0)
+          x_offset=0;
+        y_offset-=(int) crop_info.y;
+        if (y_offset < 0)
+          y_offset=0;
+        (void) CompositeImage(image,CopyCompositeOp,composite_image,(ssize_t)
+          x_offset,(ssize_t) y_offset);
+      }
+      /*
+        Relinquish resources.
+      */
+      while (colormap_info != (ColormapInfo *) NULL)
+      {
+        next=colormap_info->next;
+        colormap_info->colors=(XColor *)
+          RelinquishMagickMemory(colormap_info->colors);
+        colormap_info=(ColormapInfo *) RelinquishMagickMemory(colormap_info);
+        colormap_info=next;
+      }
+      /*
+        Relinquish resources and restore initial state.
+      */
+      window_info=(WindowInfo *) RelinquishMagickMemory(window_info);
+      max_windows=0;
+      number_windows=0;
+      colormap_info=(ColormapInfo *) NULL;
+      return(image);
+    }
+  return((Image *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t W i n d o w I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetWindowInfo() initializes the XWindowInfo structure.
+%
+%  The format of the XGetWindowInfo method is:
+%
+%      void XGetWindowInfo(Display *display,XVisualInfo *visual_info,
+%        XStandardColormap *map_info,XPixelInfo *pixel,XFontStruct *font_info,
+%        XResourceInfo *resource_info,XWindowInfo *window)
+%        resource_info,window)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
+%      returned from XGetVisualInfo.
+%
+%    o map_info: If map_type is specified, this structure is initialized
+%      with info from the Standard Colormap.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+%    o font_info: Specifies a pointer to a XFontStruct structure.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+*/
+MagickExport void XGetWindowInfo(Display *display,XVisualInfo *visual_info,
+  XStandardColormap *map_info,XPixelInfo *pixel,XFontStruct *font_info,
+  XResourceInfo *resource_info,XWindowInfo *window)
+{
+  /*
+    Initialize window info.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(visual_info != (XVisualInfo *) NULL);
+  assert(map_info != (XStandardColormap *) NULL);
+  assert(pixel != (XPixelInfo *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(window != (XWindowInfo *) NULL);
+  if (window->id != (Window) NULL)
+    {
+      if (window->cursor != (Cursor) NULL)
+        (void) XFreeCursor(display,window->cursor);
+      if (window->busy_cursor != (Cursor) NULL)
+        (void) XFreeCursor(display,window->busy_cursor);
+      if (window->highlight_stipple != (Pixmap) NULL)
+        (void) XFreePixmap(display,window->highlight_stipple);
+      if (window->shadow_stipple != (Pixmap) NULL)
+        (void) XFreePixmap(display,window->shadow_stipple);
+      if (window->name == (char *) NULL)
+        window->name=AcquireString("");
+      if (window->icon_name == (char *) NULL)
+        window->icon_name=AcquireString("");
+    }
+  else
+    {
+      /*
+        Initialize these attributes just once.
+      */
+      window->id=(Window) NULL;
+      if (window->name == (char *) NULL)
+        window->name=AcquireString("");
+      if (window->icon_name == (char *) NULL)
+        window->icon_name=AcquireString("");
+      window->x=XDisplayWidth(display,visual_info->screen) >> 1;
+      window->y=XDisplayWidth(display,visual_info->screen) >> 1;
+      window->ximage=(XImage *) NULL;
+      window->matte_image=(XImage *) NULL;
+      window->pixmap=(Pixmap) NULL;
+      window->matte_pixmap=(Pixmap) NULL;
+      window->mapped=MagickFalse;
+      window->stasis=MagickFalse;
+      window->shared_memory=MagickTrue;
+      window->segment_info=(void *) NULL;
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+      {
+        XShmSegmentInfo
+          *segment_info;
+
+        if (window->segment_info == (void *) NULL)
+          window->segment_info=AcquireQuantumMemory(2,sizeof(*segment_info));
+        segment_info=(XShmSegmentInfo *) window->segment_info;
+        segment_info[0].shmid=(-1);
+        segment_info[0].shmaddr=(char *) NULL;
+        segment_info[1].shmid=(-1);
+        segment_info[1].shmaddr=(char *) NULL;
+      }
+#endif
+    }
+  /*
+    Initialize these attributes every time function is called.
+  */
+  window->screen=visual_info->screen;
+  window->root=XRootWindow(display,visual_info->screen);
+  window->visual=visual_info->visual;
+  window->storage_class=(unsigned int) visual_info->klass;
+  window->depth=(unsigned int) visual_info->depth;
+  window->visual_info=visual_info;
+  window->map_info=map_info;
+  window->pixel_info=pixel;
+  window->font_info=font_info;
+  window->cursor=XCreateFontCursor(display,XC_left_ptr);
+  window->busy_cursor=XCreateFontCursor(display,XC_watch);
+  window->geometry=(char *) NULL;
+  window->icon_geometry=(char *) NULL;
+  if (resource_info->icon_geometry != (char *) NULL)
+    (void) CloneString(&window->icon_geometry,resource_info->icon_geometry);
+  window->crop_geometry=(char *) NULL;
+  window->flags=(size_t) PSize;
+  window->width=1;
+  window->height=1;
+  window->min_width=1;
+  window->min_height=1;
+  window->width_inc=1;
+  window->height_inc=1;
+  window->border_width=resource_info->border_width;
+  window->annotate_context=pixel->annotate_context;
+  window->highlight_context=pixel->highlight_context;
+  window->widget_context=pixel->widget_context;
+  window->shadow_stipple=(Pixmap) NULL;
+  window->highlight_stipple=(Pixmap) NULL;
+  window->use_pixmap=MagickTrue;
+  window->immutable=MagickFalse;
+  window->shape=MagickFalse;
+  window->data=0;
+  window->mask=(int) (CWBackingStore | CWBackPixel | CWBackPixmap |
+    CWBitGravity | CWBorderPixel | CWColormap | CWCursor | CWDontPropagate |
+    CWEventMask | CWOverrideRedirect | CWSaveUnder | CWWinGravity);
+  window->attributes.background_pixel=pixel->background_color.pixel;
+  window->attributes.background_pixmap=(Pixmap) NULL;
+  window->attributes.bit_gravity=ForgetGravity;
+  window->attributes.backing_store=WhenMapped;
+  window->attributes.save_under=MagickTrue;
+  window->attributes.border_pixel=pixel->border_color.pixel;
+  window->attributes.colormap=map_info->colormap;
+  window->attributes.cursor=window->cursor;
+  window->attributes.do_not_propagate_mask=NoEventMask;
+  window->attributes.event_mask=NoEventMask;
+  window->attributes.override_redirect=MagickFalse;
+  window->attributes.win_gravity=NorthWestGravity;
+  window->orphan=MagickFalse;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X H i g h l i g h t E l l i p s e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XHighlightEllipse() puts a border on the X server around a region defined by
+%  highlight_info.
+%
+%  The format of the XHighlightEllipse method is:
+%
+%      void XHighlightEllipse(Display *display,Window window,
+%        GC annotate_context,const RectangleInfo *highlight_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window structure.
+%
+%    o annotate_context: Specifies a pointer to a GC structure.
+%
+%    o highlight_info: Specifies a pointer to a RectangleInfo structure.  It
+%      contains the extents of any highlighting rectangle.
+%
+*/
+MagickExport void XHighlightEllipse(Display *display,Window window,
+  GC annotate_context,const RectangleInfo *highlight_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (Window) NULL);
+  assert(annotate_context != (GC) NULL);
+  assert(highlight_info != (RectangleInfo *) NULL);
+  if ((highlight_info->width < 4) || (highlight_info->height < 4))
+    return;
+  (void) XDrawArc(display,window,annotate_context,(int) highlight_info->x,
+    (int) highlight_info->y,(unsigned int) highlight_info->width-1,
+    (unsigned int) highlight_info->height-1,0,360*64);
+  (void) XDrawArc(display,window,annotate_context,(int) highlight_info->x+1,
+    (int) highlight_info->y+1,(unsigned int) highlight_info->width-3,
+    (unsigned int) highlight_info->height-3,0,360*64);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X H i g h l i g h t L i n e                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XHighlightLine() puts a border on the X server around a region defined by
+%  highlight_info.
+%
+%  The format of the XHighlightLine method is:
+%
+%      void XHighlightLine(Display *display,Window window,GC annotate_context,
+%        const XSegment *highlight_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window structure.
+%
+%    o annotate_context: Specifies a pointer to a GC structure.
+%
+%    o highlight_info: Specifies a pointer to a RectangleInfo structure.  It
+%      contains the extents of any highlighting rectangle.
+%
+*/
+MagickExport void XHighlightLine(Display *display,Window window,
+  GC annotate_context,const XSegment *highlight_info)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (Window) NULL);
+  assert(annotate_context != (GC) NULL);
+  assert(highlight_info != (XSegment *) NULL);
+  (void) XDrawLine(display,window,annotate_context,highlight_info->x1,
+    highlight_info->y1,highlight_info->x2,highlight_info->y2);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X H i g h l i g h t R e c t a n g l e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XHighlightRectangle() puts a border on the X server around a region defined
+%  by highlight_info.
+%
+%  The format of the XHighlightRectangle method is:
+%
+%      void XHighlightRectangle(Display *display,Window window,
+%        GC annotate_context,const RectangleInfo *highlight_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window structure.
+%
+%    o annotate_context: Specifies a pointer to a GC structure.
+%
+%    o highlight_info: Specifies a pointer to a RectangleInfo structure.  It
+%      contains the extents of any highlighting rectangle.
+%
+*/
+MagickExport void XHighlightRectangle(Display *display,Window window,
+  GC annotate_context,const RectangleInfo *highlight_info)
+{
+  assert(display != (Display *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(window != (Window) NULL);
+  assert(annotate_context != (GC) NULL);
+  assert(highlight_info != (RectangleInfo *) NULL);
+  if ((highlight_info->width < 4) || (highlight_info->height < 4))
+    return;
+  (void) XDrawRectangle(display,window,annotate_context,(int) highlight_info->x,
+    (int) highlight_info->y,(unsigned int) highlight_info->width-1,
+    (unsigned int) highlight_info->height-1);
+  (void) XDrawRectangle(display,window,annotate_context,(int) highlight_info->x+
+    1,(int) highlight_info->y+1,(unsigned int) highlight_info->width-3,
+    (unsigned int) highlight_info->height-3);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X I m p o r t I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XImportImage() reads an image from an X window.
+%
+%  The format of the XImportImage method is:
+%
+%      Image *XImportImage(const ImageInfo *image_info,XImportInfo *ximage_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o ximage_info: Specifies a pointer to an XImportInfo structure.
+%
+*/
+MagickExport Image *XImportImage(const ImageInfo *image_info,
+  XImportInfo *ximage_info)
+{
+  Colormap
+    *colormaps;
+
+  Display
+    *display;
+
+  Image
+    *image;
+
+  int
+    number_colormaps,
+    number_windows,
+    x;
+
+  RectangleInfo
+    crop_info;
+
+  Status
+    status;
+
+  Window
+    *children,
+    client,
+    prior_target,
+    root,
+    target;
+
+  XTextProperty
+    window_name;
+
+  /*
+    Open X server connection.
+  */
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(ximage_info != (XImportInfo *) NULL);
+  display=XOpenDisplay(image_info->server_name);
+  if (display == (Display *) NULL)
+    {
+      ThrowXWindowFatalException(XServerError,"UnableToOpenXServer",
+        XDisplayName(image_info->server_name));
+      return((Image *) NULL);
+    }
+  /*
+    Set our forgiving exception handler.
+  */
+  (void) XSetErrorHandler(XError);
+  /*
+    Select target window.
+  */
+  crop_info.x=0;
+  crop_info.y=0;
+  crop_info.width=0;
+  crop_info.height=0;
+  root=XRootWindow(display,XDefaultScreen(display));
+  target=(Window) NULL;
+  if ((image_info->filename != (char *) NULL) &&
+      (*image_info->filename != '\0'))
+    {
+      if (LocaleCompare(image_info->filename,"root") == 0)
+        target=root;
+      else
+        {
+          /*
+            Select window by ID or name.
+          */
+          if (isdigit((unsigned char) *image_info->filename) != 0)
+            target=XWindowByID(display,root,(Window)
+              strtol(image_info->filename,(char **) NULL,0));
+          if (target == (Window) NULL)
+            target=XWindowByName(display,root,image_info->filename);
+          if (target == (Window) NULL)
+            ThrowXWindowFatalException(XServerError,
+              "NoWindowWithSpecifiedIDExists",image_info->filename);
+        }
+    }
+  /*
+    If target window is not defined, interactively select one.
+  */
+  prior_target=target;
+  if (target == (Window) NULL)
+    target=XSelectWindow(display,&crop_info);
+  if (target == (Window) NULL)
+    ThrowXWindowFatalException(XServerError,"UnableToReadXWindowImage",
+      image_info->filename);
+  client=target;   /* obsolete */
+  if (target != root)
+    {
+      unsigned int
+        d;
+
+      status=XGetGeometry(display,target,&root,&x,&x,&d,&d,&d,&d);
+      if (status != False)
+        {
+          for ( ; ; )
+          {
+            Window
+              parent;
+
+            /*
+              Find window manager frame.
+            */
+            status=XQueryTree(display,target,&root,&parent,&children,&d);
+            if ((status != False) && (children != (Window *) NULL))
+              (void) XFree((char *) children);
+            if ((status == False) || (parent == (Window) NULL) ||
+                (parent == root))
+              break;
+            target=parent;
+          }
+          /*
+            Get client window.
+          */
+          client=XClientWindow(display,target);
+          if (ximage_info->frame == MagickFalse)
+            target=client;
+          if ((ximage_info->frame == MagickFalse) &&
+              (prior_target != MagickFalse))
+            target=prior_target;
+          XDelay(display,SuspendTime << 4);
+        }
+    }
+  if (ximage_info->screen)
+    {
+      int
+        y;
+
+      Window
+        child;
+
+      XWindowAttributes
+        window_attributes;
+
+      /*
+        Obtain window image directly from screen.
+      */
+      status=XGetWindowAttributes(display,target,&window_attributes);
+      if (status == False)
+        {
+          ThrowXWindowFatalException(XServerError,
+            "UnableToReadXWindowAttributes",image_info->filename);
+          (void) XCloseDisplay(display);
+          return((Image *) NULL);
+        }
+      (void) XTranslateCoordinates(display,target,root,0,0,&x,&y,&child);
+      crop_info.x=(ssize_t) x;
+      crop_info.y=(ssize_t) y;
+      crop_info.width=(size_t) window_attributes.width;
+      crop_info.height=(size_t) window_attributes.height;
+      if (ximage_info->borders != 0)
+        {
+          /*
+            Include border in image.
+          */
+          crop_info.x-=window_attributes.border_width;
+          crop_info.y-=window_attributes.border_width;
+          crop_info.width+=window_attributes.border_width << 1;
+          crop_info.height+=window_attributes.border_width << 1;
+        }
+      target=root;
+    }
+  /*
+    If WM_COLORMAP_WINDOWS property is set or multiple colormaps, descend.
+  */
+  number_windows=0;
+  status=XGetWMColormapWindows(display,target,&children,&number_windows);
+  if ((status == True) && (number_windows > 0))
+    {
+      ximage_info->descend=MagickTrue;
+      (void) XFree ((char *) children);
+    }
+  colormaps=XListInstalledColormaps(display,target,&number_colormaps);
+  if (number_colormaps > 0)
+    {
+      if (number_colormaps > 1)
+        ximage_info->descend=MagickTrue;
+      (void) XFree((char *) colormaps);
+    }
+  /*
+    Alert the user not to alter the screen.
+  */
+  if (ximage_info->silent == MagickFalse)
+    (void) XBell(display,0);
+  /*
+    Get image by window id.
+  */
+  (void) XGrabServer(display);
+  image=XGetWindowImage(display,target,ximage_info->borders,
+    ximage_info->descend ? 1U : 0U);
+  (void) XUngrabServer(display);
+  if (image == (Image *) NULL)
+    ThrowXWindowFatalException(XServerError,"UnableToReadXWindowImage",
+      image_info->filename)
+  else
+    {
+      (void) CopyMagickString(image->filename,image_info->filename,
+        MaxTextExtent);
+      if ((crop_info.width != 0) && (crop_info.height != 0))
+        {
+          Image
+            *clone_image,
+            *crop_image;
+
+          /*
+            Crop image as defined by the cropping rectangle.
+          */
+          clone_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+          if (clone_image != (Image *) NULL)
+            {
+              crop_image=CropImage(clone_image,&crop_info,&image->exception);
+              if (crop_image != (Image *) NULL)
+                {
+                  image=DestroyImage(image);
+                  image=crop_image;
+                }
+            }
+        }
+      status=XGetWMName(display,target,&window_name);
+      if (status == True)
+        {
+          if ((image_info->filename != (char *) NULL) &&
+              (*image_info->filename == '\0'))
+            (void) CopyMagickString(image->filename,(char *) window_name.value,
+              (size_t) window_name.nitems+1);
+          (void) XFree((void *) window_name.value);
+        }
+    }
+  if (ximage_info->silent == MagickFalse)
+    {
+      /*
+        Alert the user we're done.
+      */
+      (void) XBell(display,0);
+      (void) XBell(display,0);
+    }
+  (void) XCloseDisplay(display);
+  return(image);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X I n i t i a l i z e W i n d o w s                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XInitializeWindows() initializes the XWindows structure.
+%
+%  The format of the XInitializeWindows method is:
+%
+%      XWindows *XInitializeWindows(Display *display,
+%        XResourceInfo *resource_info)
+%
+%  A description of each parameter follows:
+%
+%    o windows: XInitializeWindows returns a pointer to a XWindows structure.
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+*/
+MagickExport XWindows *XInitializeWindows(Display *display,
+  XResourceInfo *resource_info)
+{
+  Window
+    root_window;
+
+  XWindows
+    *windows;
+
+  /*
+    Allocate windows structure.
+  */
+  windows=(XWindows *) AcquireMagickMemory(sizeof(*windows));
+  if (windows == (XWindows *) NULL)
+    {
+      ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
+        "...");
+      return((XWindows *) NULL);
+    }
+  (void) ResetMagickMemory(windows,0,sizeof(*windows));
+  windows->pixel_info=(XPixelInfo *) AcquireMagickMemory(
+    sizeof(*windows->pixel_info));
+  windows->icon_pixel=(XPixelInfo *) AcquireMagickMemory(
+    sizeof(*windows->icon_pixel));
+  windows->icon_resources=(XResourceInfo *) AcquireMagickMemory(
+    sizeof(*windows->icon_resources));
+  if ((windows->pixel_info == (XPixelInfo *) NULL) ||
+      (windows->icon_pixel == (XPixelInfo *) NULL) ||
+      (windows->icon_resources == (XResourceInfo *) NULL))
+    {
+      ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
+        "...");
+      return((XWindows *) NULL);
+    }
+  /*
+    Initialize windows structure.
+  */
+  windows->display=display;
+  windows->wm_protocols=XInternAtom(display,"WM_PROTOCOLS",MagickFalse);
+  windows->wm_delete_window=XInternAtom(display,"WM_DELETE_WINDOW",MagickFalse);
+  windows->wm_take_focus=XInternAtom(display,"WM_TAKE_FOCUS",MagickFalse);
+  windows->im_protocols=XInternAtom(display,"IM_PROTOCOLS",MagickFalse);
+  windows->im_remote_command=
+    XInternAtom(display,"IM_REMOTE_COMMAND",MagickFalse);
+  windows->im_update_widget=XInternAtom(display,"IM_UPDATE_WIDGET",MagickFalse);
+  windows->im_update_colormap=
+    XInternAtom(display,"IM_UPDATE_COLORMAP",MagickFalse);
+  windows->im_former_image=XInternAtom(display,"IM_FORMER_IMAGE",MagickFalse);
+  windows->im_next_image=XInternAtom(display,"IM_NEXT_IMAGE",MagickFalse);
+  windows->im_retain_colors=XInternAtom(display,"IM_RETAIN_COLORS",MagickFalse);
+  windows->im_exit=XInternAtom(display,"IM_EXIT",MagickFalse);
+  windows->dnd_protocols=XInternAtom(display,"DndProtocol",MagickFalse);
+#if defined(MAGICKCORE_WINDOWS_SUPPORT)
+  (void) XSynchronize(display,IsWindows95());
+#endif
+  if (IsEventLogging())
+    {
+      (void) XSynchronize(display,MagickTrue);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"Version: %s",
+        GetMagickVersion((size_t *) NULL));
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"Protocols:");
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  Window Manager: 0x%lx",windows->wm_protocols);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "    delete window: 0x%lx",windows->wm_delete_window);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"    take focus: 0x%lx",
+        windows->wm_take_focus);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  ImageMagick: 0x%lx",
+        windows->im_protocols);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "    remote command: 0x%lx",windows->im_remote_command);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "    update widget: 0x%lx",windows->im_update_widget);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "    update colormap: 0x%lx",windows->im_update_colormap);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "    former image: 0x%lx",windows->im_former_image);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"    next image: 0x%lx",
+        windows->im_next_image);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "    retain colors: 0x%lx",windows->im_retain_colors);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"    exit: 0x%lx",
+        windows->im_exit);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  Drag and Drop: 0x%lx",
+        windows->dnd_protocols);
+    }
+  /*
+    Allocate standard colormap.
+  */
+  windows->map_info=XAllocStandardColormap();
+  windows->icon_map=XAllocStandardColormap();
+  if ((windows->map_info == (XStandardColormap *) NULL) ||
+      (windows->icon_map == (XStandardColormap *) NULL))
+    ThrowXWindowFatalException(ResourceLimitFatalError,
+      "MemoryAllocationFailed","...");
+  windows->map_info->colormap=(Colormap) NULL;
+  windows->icon_map->colormap=(Colormap) NULL;
+  windows->pixel_info->pixels=(unsigned long *) NULL;
+  windows->pixel_info->annotate_context=(GC) NULL;
+  windows->pixel_info->highlight_context=(GC) NULL;
+  windows->pixel_info->widget_context=(GC) NULL;
+  windows->font_info=(XFontStruct *) NULL;
+  windows->icon_pixel->annotate_context=(GC) NULL;
+  windows->icon_pixel->pixels=(unsigned long *) NULL;
+  /*
+    Allocate visual.
+  */
+  *windows->icon_resources=(*resource_info);
+  windows->icon_resources->visual_type=(char *) "default";
+  windows->icon_resources->colormap=SharedColormap;
+  windows->visual_info=
+    XBestVisualInfo(display,windows->map_info,resource_info);
+  windows->icon_visual=
+    XBestVisualInfo(display,windows->icon_map,windows->icon_resources);
+  if ((windows->visual_info == (XVisualInfo *) NULL) ||
+      (windows->icon_visual == (XVisualInfo *) NULL))
+    ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
+      resource_info->visual_type);
+  if (IsEventLogging())
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"Visual:");
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  visual id: 0x%lx",
+        windows->visual_info->visualid);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  class: %s",
+        XVisualClassName(windows->visual_info->klass));
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  depth: %d planes",
+        windows->visual_info->depth);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  size of colormap: %d entries",windows->visual_info->colormap_size);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  red, green, blue masks: 0x%lx 0x%lx 0x%lx",
+        windows->visual_info->red_mask,windows->visual_info->green_mask,
+        windows->visual_info->blue_mask);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  significant bits in color: %d bits",
+        windows->visual_info->bits_per_rgb);
+    }
+  /*
+    Allocate class and manager hints.
+  */
+  windows->class_hints=XAllocClassHint();
+  windows->manager_hints=XAllocWMHints();
+  if ((windows->class_hints == (XClassHint *) NULL) ||
+      (windows->manager_hints == (XWMHints *) NULL))
+    ThrowXWindowFatalException(ResourceLimitFatalError,
+      "MemoryAllocationFailed","...");
+  /*
+    Determine group leader if we have one.
+  */
+  root_window=XRootWindow(display,windows->visual_info->screen);
+  windows->group_leader.id=(Window) NULL;
+  if (resource_info->window_group != (char *) NULL)
+    {
+      if (isdigit((unsigned char) *resource_info->window_group) != 0)
+        windows->group_leader.id=XWindowByID(display,root_window,(Window)
+          strtol((char *) resource_info->window_group,(char **) NULL,0));
+      if (windows->group_leader.id == (Window) NULL)
+        windows->group_leader.id=
+          XWindowByName(display,root_window,resource_info->window_group);
+    }
+  return(windows);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a k e C u r s o r                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeCursor() creates a crosshairs X11 cursor.
+%
+%  The format of the XMakeCursor method is:
+%
+%      Cursor XMakeCursor(Display *display,Window window,Colormap colormap,
+%        char *background_color,char *foreground_color)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies the ID of the window for which the cursor is
+%      assigned.
+%
+%    o colormap: Specifies the ID of the colormap from which the background
+%      and foreground color will be retrieved.
+%
+%    o background_color: Specifies the color to use for the cursor background.
+%
+%    o foreground_color: Specifies the color to use for the cursor foreground.
+%
+*/
+MagickExport Cursor XMakeCursor(Display *display,Window window,
+  Colormap colormap,char *background_color,char *foreground_color)
+{
+#define scope_height 17
+#define scope_x_hot 8
+#define scope_y_hot 8
+#define scope_width 17
+
+  static const unsigned char
+    scope_bits[] =
+    {
+      0x80, 0x03, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02,
+      0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x7f,
+      0xfc, 0x01, 0x01, 0x00, 0x01, 0x7f, 0xfc, 0x01, 0x80, 0x02, 0x00,
+      0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02, 0x00, 0x80, 0x02,
+      0x00, 0x80, 0x02, 0x00, 0x80, 0x03, 0x00
+    },
+    scope_mask_bits[] =
+    {
+      0xc0, 0x07, 0x00, 0xc0, 0x07, 0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06,
+      0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06, 0x00, 0xff, 0xfe, 0x01, 0x7f,
+      0xfc, 0x01, 0x03, 0x80, 0x01, 0x7f, 0xfc, 0x01, 0xff, 0xfe, 0x01,
+      0xc0, 0x06, 0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06, 0x00, 0xc0, 0x06,
+      0x00, 0xc0, 0x07, 0x00, 0xc0, 0x07, 0x00
+    };
+
+  Cursor
+    cursor;
+
+  Pixmap
+    mask,
+    source;
+
+  XColor
+    background,
+    foreground;
+
+  assert(display != (Display *) NULL);
+  assert(window != (Window) NULL);
+  assert(colormap != (Colormap) NULL);
+  assert(background_color != (char *) NULL);
+  assert(foreground_color != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",background_color);
+  source=XCreateBitmapFromData(display,window,(char *) scope_bits,scope_width,
+    scope_height);
+  mask=XCreateBitmapFromData(display,window,(char *) scope_mask_bits,
+    scope_width,scope_height);
+  if ((source == (Pixmap) NULL) || (mask == (Pixmap) NULL))
+    {
+      ThrowXWindowFatalException(XServerError,"UnableToCreatePixmap","...");
+      return((Cursor) NULL);
+    }
+  (void) XParseColor(display,colormap,background_color,&background);
+  (void) XParseColor(display,colormap,foreground_color,&foreground);
+  cursor=XCreatePixmapCursor(display,source,mask,&foreground,&background,
+    scope_x_hot,scope_y_hot);
+  (void) XFreePixmap(display,source);
+  (void) XFreePixmap(display,mask);
+  return(cursor);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a k e I m a g e                                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeImage() creates an X11 image.  If the image size differs from the X11
+%  image size, the image is first resized.
+%
+%  The format of the XMakeImage method is:
+%
+%      MagickBooleanType XMakeImage(Display *display,
+%        const XResourceInfo *resource_info,XWindowInfo *window,Image *image,
+%        unsigned int width,unsigned int height)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o window: Specifies a pointer to a XWindowInfo structure.
+%
+%    o image: the image.
+%
+%    o width: Specifies the width in pixels of the rectangular area to
+%      display.
+%
+%    o height: Specifies the height in pixels of the rectangular area to
+%      display.
+%
+*/
+MagickExport MagickBooleanType XMakeImage(Display *display,
+  const XResourceInfo *resource_info,XWindowInfo *window,Image *image,
+  unsigned int width,unsigned int height)
+{
+#define CheckOverflowException(length,width,height) \
+  (((height) != 0) && ((length)/((size_t) height) != ((size_t) width)))
+
+  int
+    depth,
+    format;
+
+  size_t
+    length;
+
+  XImage
+    *matte_image,
+    *ximage;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(window != (XWindowInfo *) NULL);
+  assert(width != 0);
+  assert(height != 0);
+  if ((window->width == 0) || (window->height == 0))
+    return(MagickFalse);
+  /*
+    Apply user transforms to the image.
+  */
+  (void) XCheckDefineCursor(display,window->id,window->busy_cursor);
+  (void) XFlush(display);
+  depth=(int) window->depth;
+  if (window->destroy)
+    window->image=DestroyImage(window->image);
+  window->image=image;
+  window->destroy=MagickFalse;
+  if (window->image != (Image *) NULL)
+    {
+      if (window->crop_geometry != (char *) NULL)
+        {
+          Image
+            *crop_image;
+
+          RectangleInfo
+            crop_info;
+
+          /*
+            Crop image.
+          */
+          window->image->page.x=0;
+          window->image->page.y=0;
+          (void) ParsePageGeometry(window->image,window->crop_geometry,
+            &crop_info,&image->exception);
+          crop_image=CropImage(window->image,&crop_info,&image->exception);
+          if (crop_image != (Image *) NULL)
+            {
+              if (window->image != image)
+                window->image=DestroyImage(window->image);
+              window->image=crop_image;
+              window->destroy=MagickTrue;
+            }
+        }
+      if ((width != (unsigned int) window->image->columns) ||
+          (height != (unsigned int) window->image->rows))
+        {
+          Image
+            *resize_image;
+
+          /*
+            Resize image.
+          */
+          resize_image=NewImageList();
+          if (window->pixel_info->colors != 0)
+            resize_image=SampleImage(window->image,width,height,
+              &image->exception);
+          else
+            resize_image=ThumbnailImage(window->image,width,height,
+              &image->exception);
+          if (resize_image != (Image *) NULL)
+            {
+              if (window->image != image)
+                window->image=DestroyImage(window->image);
+              window->image=resize_image;
+              window->destroy=MagickTrue;
+            }
+        }
+      width=(unsigned int) window->image->columns;
+      assert((size_t) width == window->image->columns);
+      height=(unsigned int) window->image->rows;
+      assert((size_t) height == window->image->rows);
+    }
+  /*
+    Create X image.
+  */
+  ximage=(XImage *) NULL;
+  format=(depth == 1) ? XYBitmap : ZPixmap;
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+  if (window->shared_memory != MagickFalse)
+    {
+      XShmSegmentInfo
+        *segment_info;
+
+      segment_info=(XShmSegmentInfo *) window->segment_info;
+      segment_info[1].shmid=(-1);
+      segment_info[1].shmaddr=(char *) NULL;
+      ximage=XShmCreateImage(display,window->visual,(unsigned int) depth,format,
+        (char *) NULL,&segment_info[1],width,height);
+      if (ximage == (XImage *) NULL)
+        window->shared_memory=MagickFalse;
+      length=(size_t) ximage->bytes_per_line*ximage->height;
+      if (CheckOverflowException(length,ximage->bytes_per_line,ximage->height))
+        window->shared_memory=MagickFalse;
+      if (window->shared_memory != MagickFalse)
+        segment_info[1].shmid=shmget(IPC_PRIVATE,length,IPC_CREAT | 0777);
+      if (window->shared_memory != MagickFalse)
+        segment_info[1].shmaddr=(char *) shmat(segment_info[1].shmid,0,0);
+      if (segment_info[1].shmid < 0)
+        window->shared_memory=MagickFalse;
+      if (window->shared_memory != MagickFalse)
+        (void) shmctl(segment_info[1].shmid,IPC_RMID,0);
+      else
+        {
+          if (ximage != (XImage *) NULL)
+            XDestroyImage(ximage);
+          ximage=(XImage *) NULL;
+          if (segment_info[1].shmaddr)
+            {
+              (void) shmdt(segment_info[1].shmaddr);
+              segment_info[1].shmaddr=(char *) NULL;
+            }
+          if (segment_info[1].shmid >= 0)
+            {
+              (void) shmctl(segment_info[1].shmid,IPC_RMID,0);
+              segment_info[1].shmid=(-1);
+            }
+        }
+    }
+#endif
+  /*
+    Allocate X image pixel data.
+  */
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+  if (window->shared_memory)
+    {
+      Status
+        status;
+
+      XShmSegmentInfo
+        *segment_info;
+
+      (void) XSync(display,MagickFalse);
+      xerror_alert=MagickFalse;
+      segment_info=(XShmSegmentInfo *) window->segment_info;
+      ximage->data=segment_info[1].shmaddr;
+      segment_info[1].readOnly=MagickFalse;
+      status=XShmAttach(display,&segment_info[1]);
+      if (status != False)
+        (void) XSync(display,MagickFalse);
+      if ((status == False) || (xerror_alert != MagickFalse))
+        {
+          window->shared_memory=MagickFalse;
+          if (status != False)
+            XShmDetach(display,&segment_info[1]);
+          if (ximage != (XImage *) NULL)
+            {
+              ximage->data=NULL;
+              XDestroyImage(ximage);
+              ximage=(XImage *) NULL;
+            }
+          if (segment_info[1].shmid >= 0)
+            {
+              if (segment_info[1].shmaddr != NULL)
+                (void) shmdt(segment_info[1].shmaddr);
+              (void) shmctl(segment_info[1].shmid,IPC_RMID,0);
+              segment_info[1].shmid=(-1);
+              segment_info[1].shmaddr=(char *) NULL;
+            }
+        }
+    }
+#endif
+  if (window->shared_memory == MagickFalse)
+    ximage=XCreateImage(display,window->visual,(unsigned int) depth,format,0,
+      (char *) NULL,width,height,XBitmapPad(display),0);
+  if (ximage == (XImage *) NULL)
+    {
+      /*
+        Unable to create X image.
+      */
+      (void) XCheckDefineCursor(display,window->id,window->cursor);
+      return(MagickFalse);
+    }
+  length=(size_t) ximage->bytes_per_line*ximage->height;
+  if (IsEventLogging())
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"XImage:");
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  width, height: %dx%d",
+        ximage->width,ximage->height);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  format: %d",
+        ximage->format);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  byte order: %d",
+        ximage->byte_order);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  bitmap unit, bit order, pad: %d %d %d",ximage->bitmap_unit,
+        ximage->bitmap_bit_order,ximage->bitmap_pad);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  depth: %d",
+        ximage->depth);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  bytes per line: %d",
+        ximage->bytes_per_line);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  bits per pixel: %d",
+        ximage->bits_per_pixel);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  red, green, blue masks: 0x%lx 0x%lx 0x%lx",ximage->red_mask,
+        ximage->green_mask,ximage->blue_mask);
+    }
+  if (window->shared_memory == MagickFalse)
+    {
+      if (ximage->format != XYBitmap)
+        ximage->data=(char *) AcquireQuantumMemory((size_t)
+          ximage->bytes_per_line,(size_t) ximage->height);
+      else
+        ximage->data=(char *) AcquireQuantumMemory((size_t)
+          ximage->bytes_per_line*ximage->depth,(size_t) ximage->height);
+    }
+  if (ximage->data == (char *) NULL)
+    {
+      /*
+        Unable to allocate pixel data.
+      */
+      XDestroyImage(ximage);
+      ximage=(XImage *) NULL;
+      (void) XCheckDefineCursor(display,window->id,window->cursor);
+      return(MagickFalse);
+    }
+  if (window->ximage != (XImage *) NULL)
+    {
+      /*
+        Destroy previous X image.
+      */
+      length=(size_t) window->ximage->bytes_per_line*window->ximage->height;
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+      if (window->segment_info != (XShmSegmentInfo *) NULL)
+        {
+          XShmSegmentInfo
+            *segment_info;
+
+          segment_info=(XShmSegmentInfo *) window->segment_info;
+          if (segment_info[0].shmid >= 0)
+            {
+              (void) XSync(display,MagickFalse);
+              (void) XShmDetach(display,&segment_info[0]);
+              (void) XSync(display,MagickFalse);
+              if (segment_info[0].shmaddr != (char *) NULL)
+                (void) shmdt(segment_info[0].shmaddr);
+              (void) shmctl(segment_info[0].shmid,IPC_RMID,0);
+              segment_info[0].shmid=(-1);
+              segment_info[0].shmaddr=(char *) NULL;
+              window->ximage->data=(char *) NULL;
+          }
+        }
+#endif
+      if (window->ximage->data != (char *) NULL)
+        free(window->ximage->data);
+      window->ximage->data=(char *) NULL;
+      XDestroyImage(window->ximage);
+      window->ximage=(XImage *) NULL;
+    }
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+  if (window->segment_info != (XShmSegmentInfo *) NULL)
+    {
+      XShmSegmentInfo
+        *segment_info;
+
+      segment_info=(XShmSegmentInfo *) window->segment_info;
+      segment_info[0]=segment_info[1];
+    }
+#endif
+  window->ximage=ximage;
+  matte_image=(XImage *) NULL;
+  if ((window->shape != MagickFalse) && (window->image != (Image *) NULL))
+    if ((window->image->matte != MagickFalse) &&
+        ((int) width <= XDisplayWidth(display,window->screen)) &&
+        ((int) height <= XDisplayHeight(display,window->screen)))
+      {
+        /*
+          Create matte image.
+        */
+        matte_image=XCreateImage(display,window->visual,1,XYBitmap,0,
+          (char *) NULL,width,height,XBitmapPad(display),0);
+        if (IsEventLogging())
+          {
+            (void) LogMagickEvent(X11Event,GetMagickModule(),"Matte Image:");
+            (void) LogMagickEvent(X11Event,GetMagickModule(),
+              "  width, height: %dx%d",matte_image->width,matte_image->height);
+          }
+        if (matte_image != (XImage *) NULL)
+          {
+            /*
+              Allocate matte image pixel data.
+            */
+            matte_image->data=(char *) AcquireQuantumMemory((size_t)
+              matte_image->bytes_per_line*matte_image->depth,
+              (size_t) matte_image->height);
+            if (matte_image->data == (char *) NULL)
+              {
+                XDestroyImage(matte_image);
+                matte_image=(XImage *) NULL;
+              }
+          }
+      }
+  if (window->matte_image != (XImage *) NULL)
+    {
+      /*
+        Free matte image.
+      */
+      if (window->matte_image->data != (char *) NULL)
+        free(window->matte_image->data);
+      window->matte_image->data=(char *) NULL;
+      XDestroyImage(window->matte_image);
+      window->matte_image=(XImage *) NULL;
+    }
+  window->matte_image=matte_image;
+  if (window->matte_pixmap != (Pixmap) NULL)
+    {
+      (void) XFreePixmap(display,window->matte_pixmap);
+      window->matte_pixmap=(Pixmap) NULL;
+#if defined(MAGICKCORE_HAVE_SHAPE)
+      if (window->shape != MagickFalse)
+        XShapeCombineMask(display,window->id,ShapeBounding,0,0,None,ShapeSet);
+#endif
+    }
+  window->stasis=MagickFalse;
+  /*
+    Convert pixels to X image data.
+  */
+  if (window->image != (Image *) NULL)
+    {
+      if ((ximage->byte_order == LSBFirst) || ((ximage->format == XYBitmap) &&
+          (ximage->bitmap_bit_order == LSBFirst)))
+        XMakeImageLSBFirst(resource_info,window,window->image,ximage,
+          matte_image);
+      else
+        XMakeImageMSBFirst(resource_info,window,window->image,ximage,
+          matte_image);
+    }
+  if (window->matte_image != (XImage *) NULL)
+    {
+      /*
+        Create matte pixmap.
+      */
+      window->matte_pixmap=XCreatePixmap(display,window->id,width,height,1);
+      if (window->matte_pixmap != (Pixmap) NULL)
+        {
+          GC
+            graphics_context;
+
+          XGCValues
+            context_values;
+
+          /*
+            Copy matte image to matte pixmap.
+          */
+          context_values.background=0;
+          context_values.foreground=1;
+          graphics_context=XCreateGC(display,window->matte_pixmap,
+            (size_t) (GCBackground | GCForeground),&context_values);
+          (void) XPutImage(display,window->matte_pixmap,graphics_context,
+            window->matte_image,0,0,0,0,width,height);
+          (void) XFreeGC(display,graphics_context);
+#if defined(MAGICKCORE_HAVE_SHAPE)
+          if (window->shape != MagickFalse)
+            XShapeCombineMask(display,window->id,ShapeBounding,0,0,
+              window->matte_pixmap,ShapeSet);
+#endif
+        }
+      }
+  (void) XMakePixmap(display,resource_info,window);
+  /*
+    Restore cursor.
+  */
+  (void) XCheckDefineCursor(display,window->id,window->cursor);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a k e I m a g e L S B F i r s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeImageLSBFirst() initializes the pixel data of an X11 Image. The X image
+%  pixels are copied in least-significant bit and byte first order.  The
+%  server's scanline pad is respected.  Rather than using one or two general
+%  cases, many special cases are found here to help speed up the image
+%  conversion.
+%
+%  The format of the XMakeImageLSBFirst method is:
+%
+%      void XMakeImageLSBFirst(Display *display,XWindows *windows)
+%
+%  A description of each parameter follows:
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o window: Specifies a pointer to a XWindowInfo structure.
+%
+%    o image: the image.
+%
+%    o ximage: Specifies a pointer to a XImage structure;  returned from
+%      XCreateImage.
+%
+%    o matte_image: Specifies a pointer to a XImage structure;  returned from
+%      XCreateImage.
+%
+*/
+static void XMakeImageLSBFirst(const XResourceInfo *resource_info,
+  const XWindowInfo *window,Image *image,XImage *ximage,XImage *matte_image)
+{
+  CacheView
+    *canvas_view;
+
+  Image
+    *canvas;
+
+  int
+    y;
+
+  register const Quantum
+    *p;
+
+  register int
+    x;
+
+  register unsigned char
+    *q;
+
+  unsigned char
+    bit,
+    byte;
+
+  unsigned int
+    scanline_pad;
+
+  unsigned long
+    pixel,
+    *pixels;
+
+  XStandardColormap
+    *map_info;
+
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(window != (XWindowInfo *) NULL);
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  canvas=image;
+  if ((window->immutable == MagickFalse) &&
+      (image->storage_class == DirectClass) && (image->matte != MagickFalse))
+    {
+      char
+        size[MaxTextExtent];
+
+      Image
+        *pattern;
+
+      ImageInfo
+        *image_info;
+
+      image_info=AcquireImageInfo();
+      (void) CopyMagickString(image_info->filename,
+        resource_info->image_info->texture != (char *) NULL ?
+        resource_info->image_info->texture : "pattern:checkerboard",
+        MaxTextExtent);
+      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",(double)
+        image->columns,(double) image->rows);
+      image_info->size=ConstantString(size);
+      pattern=ReadImage(image_info,&image->exception);
+      image_info=DestroyImageInfo(image_info);
+      if (pattern != (Image *) NULL)
+        {
+          canvas=CloneImage(image,0,0,MagickTrue,&image->exception);
+          if (canvas != (Image *) NULL)
+            (void) CompositeImage(canvas,DstOverCompositeOp,pattern,0,0);
+          pattern=DestroyImage(pattern);
+        }
+    }
+  scanline_pad=(unsigned int) (ximage->bytes_per_line-((ximage->width*
+    ximage->bits_per_pixel) >> 3));
+  map_info=window->map_info;
+  pixels=window->pixel_info->pixels;
+  q=(unsigned char *) ximage->data;
+  x=0;
+  canvas_view=AcquireCacheView(canvas);
+  if (ximage->format == XYBitmap)
+    {
+      register unsigned short
+        polarity;
+
+      unsigned char
+        background,
+        foreground;
+
+      /*
+        Convert canvas to big-endian bitmap.
+      */
+      background=(unsigned char)
+        (XPixelIntensity(&window->pixel_info->foreground_color) <
+         XPixelIntensity(&window->pixel_info->background_color) ? 0x80 : 0x00);
+      foreground=(unsigned char)
+        (XPixelIntensity(&window->pixel_info->background_color) <
+         XPixelIntensity(&window->pixel_info->foreground_color) ? 0x80 : 0x00);
+      polarity=(unsigned short) ((GetPixelPacketIntensity(
+        &canvas->colormap[0])) < ((Quantum) QuantumRange/2) ? 1 : 0);
+      if (canvas->colors == 2)
+        polarity=GetPixelPacketIntensity(&canvas->colormap[0]) <
+          GetPixelPacketIntensity(&canvas->colormap[1]);
+      for (y=0; y < (int) canvas->rows; y++)
+      {
+        p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,canvas->columns,1,
+          &canvas->exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        bit=0;
+        byte=0;
+        for (x=0; x < (int) canvas->columns; x++)
+        {
+          byte>>=1;
+          if (GetPixelIndex(canvas,p) == (Quantum) polarity)
+            byte|=foreground;
+          else
+            byte|=background;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+          p+=GetPixelChannels(canvas);
+        }
+        if (bit != 0)
+          *q=byte >> (8-bit);
+        q+=scanline_pad;
+      }
+    }
+  else
+    if (window->pixel_info->colors != 0)
+      switch (ximage->bits_per_pixel)
+      {
+        case 2:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to 2 bit color-mapped X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)] & 0x0f;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) pixel;
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 2);
+                  nibble++;
+                  break;
+                }
+                case 2:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 3:
+                {
+                  *q|=(unsigned char) (pixel << 6);
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to 4 bit color-mapped X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)] & 0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) pixel;
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 6:
+        case 8:
+        {
+          /*
+            Convert to 8 bit color-mapped X canvas.
+          */
+          if (resource_info->color_recovery &&
+              resource_info->quantize_info->dither)
+            {
+              XDitherImage(canvas,ximage);
+              break;
+            }
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)];
+              *q++=(unsigned char) pixel;
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        default:
+        {
+          register int
+            k;
+
+          register unsigned int
+            bytes_per_pixel;
+
+          unsigned char
+            channel[sizeof(size_t)];
+
+          /*
+            Convert to multi-byte color-mapped X canvas.
+          */
+          bytes_per_pixel=(unsigned int) (ximage->bits_per_pixel >> 3);
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t) GetPixelIndex(canvas,p)];
+              for (k=0; k < (int) bytes_per_pixel; k++)
+              {
+                channel[k]=(unsigned char) pixel;
+                pixel>>=8;
+              }
+              for (k=0; k < (int) bytes_per_pixel; k++)
+                *q++=channel[k];
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+      }
+    else
+      switch (ximage->bits_per_pixel)
+      {
+        case 2:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to contiguous 2 bit continuous-tone X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            nibble=0;
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=XGammaPixel(canvas,map_info,p);
+              pixel&=0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) pixel;
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 2);
+                  nibble++;
+                  break;
+                }
+                case 2:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 3:
+                {
+                  *q|=(unsigned char) (pixel << 6);
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to contiguous 4 bit continuous-tone X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=XGammaPixel(canvas,map_info,p);
+              pixel&=0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) pixel;
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 6:
+        case 8:
+        {
+          /*
+            Convert to contiguous 8 bit continuous-tone X canvas.
+          */
+          if (resource_info->color_recovery &&
+              resource_info->quantize_info->dither)
+            {
+              XDitherImage(canvas,ximage);
+              break;
+            }
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=XGammaPixel(canvas,map_info,p);
+              *q++=(unsigned char) pixel;
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        default:
+        {
+          if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
+              (map_info->green_max == 255) && (map_info->blue_max == 255) &&
+              (map_info->red_mult == 65536L) && (map_info->green_mult == 256) &&
+              (map_info->blue_mult == 1))
+            {
+              /*
+                Convert to 32 bit continuous-tone X canvas.
+              */
+              for (y=0; y < (int) canvas->rows; y++)
+              {
+                p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+                  canvas->columns,1,&canvas->exception);
+                if (p == (const Quantum *) NULL)
+                  break;
+                if ((red_gamma != 1.0) || (green_gamma != 1.0) ||
+                    (blue_gamma != 1.0))
+                  {
+                    /*
+                      Gamma correct canvas.
+                    */
+                    for (x=(int) canvas->columns-1; x >= 0; x--)
+                    {
+                      *q++=ScaleQuantumToChar(XBlueGamma(
+                        GetPixelBlue(canvas,p)));
+                      *q++=ScaleQuantumToChar(XGreenGamma(
+                        GetPixelGreen(canvas,p)));
+                      *q++=ScaleQuantumToChar(XRedGamma(
+                        GetPixelRed(canvas,p)));
+                      *q++=0;
+                      p+=GetPixelChannels(canvas);
+                    }
+                    continue;
+                  }
+                for (x=(int) canvas->columns-1; x >= 0; x--)
+                {
+                  *q++=ScaleQuantumToChar((Quantum)
+                    GetPixelBlue(canvas,p));
+                  *q++=ScaleQuantumToChar((Quantum)
+                    GetPixelGreen(canvas,p));
+                  *q++=ScaleQuantumToChar((Quantum)
+                    GetPixelRed(canvas,p));
+                  *q++=0;
+                  p+=GetPixelChannels(canvas);
+                }
+              }
+            }
+          else
+            if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
+                (map_info->green_max == 255) && (map_info->blue_max == 255) &&
+                (map_info->red_mult == 1) && (map_info->green_mult == 256) &&
+                (map_info->blue_mult == 65536L))
+              {
+                /*
+                  Convert to 32 bit continuous-tone X canvas.
+                */
+                for (y=0; y < (int) canvas->rows; y++)
+                {
+                  p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+                    canvas->columns,1,&canvas->exception);
+                  if (p == (const Quantum *) NULL)
+                    break;
+                  if ((red_gamma != 1.0) || (green_gamma != 1.0) ||
+                      (blue_gamma != 1.0))
+                    {
+                      /*
+                        Gamma correct canvas.
+                      */
+                      for (x=(int) canvas->columns-1; x >= 0; x--)
+                      {
+                        *q++=ScaleQuantumToChar(XRedGamma(
+                          GetPixelRed(canvas,p)));
+                        *q++=ScaleQuantumToChar(XGreenGamma(
+                          GetPixelGreen(canvas,p)));
+                        *q++=ScaleQuantumToChar(XBlueGamma(
+                          GetPixelBlue(canvas,p)));
+                        *q++=0;
+                        p+=GetPixelChannels(canvas);
+                      }
+                      continue;
+                    }
+                  for (x=(int) canvas->columns-1; x >= 0; x--)
+                  {
+                    *q++=ScaleQuantumToChar((Quantum)
+                      GetPixelRed(canvas,p));
+                    *q++=ScaleQuantumToChar((Quantum)
+                      GetPixelGreen(canvas,p));
+                    *q++=ScaleQuantumToChar((Quantum)
+                      GetPixelBlue(canvas,p));
+                    *q++=0;
+                    p+=GetPixelChannels(canvas);
+                  }
+                }
+              }
+            else
+              {
+                register int
+                  k;
+
+                register unsigned int
+                  bytes_per_pixel;
+
+                unsigned char
+                  channel[sizeof(size_t)];
+
+                /*
+                  Convert to multi-byte continuous-tone X canvas.
+                */
+                bytes_per_pixel=(unsigned int) (ximage->bits_per_pixel >> 3);
+                for (y=0; y < (int) canvas->rows; y++)
+                {
+                  p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+                    canvas->columns,1,&canvas->exception);
+                  if (p == (const Quantum *) NULL)
+                    break;
+                  for (x=0; x < (int) canvas->columns; x++)
+                  {
+                    pixel=XGammaPixel(canvas,map_info,p);
+                    for (k=0; k < (int) bytes_per_pixel; k++)
+                    {
+                      channel[k]=(unsigned char) pixel;
+                      pixel>>=8;
+                    }
+                    for (k=0; k < (int) bytes_per_pixel; k++)
+                      *q++=channel[k];
+                    p+=GetPixelChannels(canvas);
+                  }
+                  q+=scanline_pad;
+                }
+              }
+          break;
+        }
+      }
+  if (matte_image != (XImage *) NULL)
+    {
+      /*
+        Initialize matte canvas.
+      */
+      scanline_pad=(unsigned int) (matte_image->bytes_per_line-
+        ((matte_image->width*matte_image->bits_per_pixel) >> 3));
+      q=(unsigned char *) matte_image->data;
+      for (y=0; y < (int) canvas->rows; y++)
+      {
+        p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,canvas->columns,1,
+          &canvas->exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        bit=0;
+        byte=0;
+        for (x=(int) canvas->columns-1; x >= 0; x--)
+        {
+          byte>>=1;
+          if (GetPixelAlpha(canvas,p) > (QuantumRange/2))
+            byte|=0x80;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+          p+=GetPixelChannels(canvas);
+        }
+        if (bit != 0)
+          *q=byte >> (8-bit);
+        q+=scanline_pad;
+      }
+    }
+  canvas_view=DestroyCacheView(canvas_view);
+  if (canvas != image)
+    canvas=DestroyImage(canvas);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X M a k e I m a g e M S B F i r s t                                       %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeImageMSBFirst() initializes the pixel data of an X11 Image.  The X
+%  image pixels are copied in most-significant bit and byte first order.  The
+%  server's scanline pad is also respected. Rather than using one or two
+%  general cases, many special cases are found here to help speed up the image
+%  conversion.
+%
+%  The format of the XMakeImageMSBFirst method is:
+%
+%      XMakeImageMSBFirst(resource_info,window,image,ximage,matte_image)
+%
+%  A description of each parameter follows:
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o window: Specifies a pointer to a XWindowInfo structure.
+%
+%    o image: the image.
+%
+%    o ximage: Specifies a pointer to a XImage structure;  returned from
+%      XCreateImage.
+%
+%    o matte_image: Specifies a pointer to a XImage structure;  returned from
+%      XCreateImage.
+%
+*/
+static void XMakeImageMSBFirst(const XResourceInfo *resource_info,
+  const XWindowInfo *window,Image *image,XImage *ximage,XImage *matte_image)
+{
+  CacheView
+    *canvas_view;
+
+  Image
+    *canvas;
+
+  int
+    y;
+
+  register int
+    x;
+
+  register const Quantum
+    *p;
+
+  register unsigned char
+    *q;
+
+  unsigned char
+    bit,
+    byte;
+
+  unsigned int
+    scanline_pad;
+
+  unsigned long
+    pixel,
+    *pixels;
+
+  XStandardColormap
+    *map_info;
+
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(window != (XWindowInfo *) NULL);
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  canvas=image;
+  if ((window->immutable != MagickFalse) &&
+      (image->storage_class == DirectClass) && (image->matte != MagickFalse))
+    {
+      char
+        size[MaxTextExtent];
+
+      Image
+        *pattern;
+
+      ImageInfo
+        *image_info;
+
+      image_info=AcquireImageInfo();
+      (void) CopyMagickString(image_info->filename,
+        resource_info->image_info->texture != (char *) NULL ?
+        resource_info->image_info->texture : "pattern:checkerboard",
+        MaxTextExtent);
+      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",(double)
+        image->columns,(double) image->rows);
+      image_info->size=ConstantString(size);
+      pattern=ReadImage(image_info,&image->exception);
+      image_info=DestroyImageInfo(image_info);
+      if (pattern != (Image *) NULL)
+        {
+          canvas=CloneImage(image,0,0,MagickTrue,&image->exception);
+          if (canvas != (Image *) NULL)
+            (void) CompositeImage(canvas,DstOverCompositeOp,pattern,0,0);
+          pattern=DestroyImage(pattern);
+        }
+    }
+  scanline_pad=(unsigned int) (ximage->bytes_per_line-((ximage->width*
+    ximage->bits_per_pixel) >> 3));
+  map_info=window->map_info;
+  pixels=window->pixel_info->pixels;
+  q=(unsigned char *) ximage->data;
+  x=0;
+  canvas_view=AcquireCacheView(canvas);
+  if (ximage->format == XYBitmap)
+    {
+      register unsigned short
+        polarity;
+
+      unsigned char
+        background,
+        foreground;
+
+      /*
+        Convert canvas to big-endian bitmap.
+      */
+      background=(unsigned char)
+        (XPixelIntensity(&window->pixel_info->foreground_color) <
+         XPixelIntensity(&window->pixel_info->background_color) ?  0x01 : 0x00);
+      foreground=(unsigned char)
+        (XPixelIntensity(&window->pixel_info->background_color) <
+         XPixelIntensity(&window->pixel_info->foreground_color) ?  0x01 : 0x00);
+      polarity=(unsigned short) ((GetPixelPacketIntensity(
+        &canvas->colormap[0])) < ((Quantum) QuantumRange/2) ? 1 : 0);
+      if (canvas->colors == 2)
+        polarity=GetPixelPacketIntensity(&canvas->colormap[0]) <
+          GetPixelPacketIntensity(&canvas->colormap[1]);
+      for (y=0; y < (int) canvas->rows; y++)
+      {
+        p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,canvas->columns,1,
+          &canvas->exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        bit=0;
+        byte=0;
+        for (x=(int) canvas->columns-1; x >= 0; x--)
+        {
+          byte<<=1;
+          if (GetPixelIndex(canvas,p) == (Quantum) polarity)
+            byte|=foreground;
+          else
+            byte|=background;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+          p+=GetPixelChannels(canvas);
+        }
+        if (bit != 0)
+          *q=byte << (8-bit);
+        q+=scanline_pad;
+      }
+    }
+  else
+    if (window->pixel_info->colors != 0)
+      switch (ximage->bits_per_pixel)
+      {
+        case 2:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to 2 bit color-mapped X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t)
+                GetPixelIndex(canvas,p)] & 0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) (pixel << 6);
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 2:
+                {
+                  *q|=(unsigned char) (pixel << 2);
+                  nibble++;
+                  break;
+                }
+                case 3:
+                {
+                  *q|=(unsigned char) pixel;
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to 4 bit color-mapped X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t)
+                GetPixelIndex(canvas,p)] & 0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) pixel;
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 6:
+        case 8:
+        {
+          /*
+            Convert to 8 bit color-mapped X canvas.
+          */
+          if (resource_info->color_recovery &&
+              resource_info->quantize_info->dither)
+            {
+              XDitherImage(canvas,ximage);
+              break;
+            }
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t)
+                GetPixelIndex(canvas,p)];
+              *q++=(unsigned char) pixel;
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        default:
+        {
+          register int
+            k;
+
+          register unsigned int
+            bytes_per_pixel;
+
+          unsigned char
+            channel[sizeof(size_t)];
+
+          /*
+            Convert to 8 bit color-mapped X canvas.
+          */
+          bytes_per_pixel=(unsigned int) (ximage->bits_per_pixel >> 3);
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=0; x < (int) canvas->columns; x++)
+            {
+              pixel=pixels[(ssize_t)
+                GetPixelIndex(canvas,p)];
+              for (k=(int) bytes_per_pixel-1; k >= 0; k--)
+              {
+                channel[k]=(unsigned char) pixel;
+                pixel>>=8;
+              }
+              for (k=0; k < (int) bytes_per_pixel; k++)
+                *q++=channel[k];
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+      }
+    else
+      switch (ximage->bits_per_pixel)
+      {
+        case 2:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to 4 bit continuous-tone X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=(int) canvas->columns-1; x >= 0; x--)
+            {
+              pixel=XGammaPixel(canvas,map_info,p);
+              pixel&=0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) (pixel << 6);
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 2:
+                {
+                  *q|=(unsigned char) (pixel << 2);
+                  nibble++;
+                  break;
+                }
+                case 3:
+                {
+                  *q|=(unsigned char) pixel;
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 4:
+        {
+          register unsigned int
+            nibble;
+
+          /*
+            Convert to 4 bit continuous-tone X canvas.
+          */
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            nibble=0;
+            for (x=(int) canvas->columns-1; x >= 0; x--)
+            {
+              pixel=XGammaPixel(canvas,map_info,p);
+              pixel&=0xf;
+              switch (nibble)
+              {
+                case 0:
+                {
+                  *q=(unsigned char) (pixel << 4);
+                  nibble++;
+                  break;
+                }
+                case 1:
+                {
+                  *q|=(unsigned char) pixel;
+                  q++;
+                  nibble=0;
+                  break;
+                }
+              }
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        case 6:
+        case 8:
+        {
+          /*
+            Convert to 8 bit continuous-tone X canvas.
+          */
+          if (resource_info->color_recovery &&
+              resource_info->quantize_info->dither)
+            {
+              XDitherImage(canvas,ximage);
+              break;
+            }
+          for (y=0; y < (int) canvas->rows; y++)
+          {
+            p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+              canvas->columns,1,&canvas->exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=(int) canvas->columns-1; x >= 0; x--)
+            {
+              pixel=XGammaPixel(canvas,map_info,p);
+              *q++=(unsigned char) pixel;
+              p+=GetPixelChannels(canvas);
+            }
+            q+=scanline_pad;
+          }
+          break;
+        }
+        default:
+        {
+          if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
+              (map_info->green_max == 255) && (map_info->blue_max == 255) &&
+              (map_info->red_mult == 65536L) && (map_info->green_mult == 256) &&
+              (map_info->blue_mult == 1))
+            {
+              /*
+                Convert to 32 bit continuous-tone X canvas.
+              */
+              for (y=0; y < (int) canvas->rows; y++)
+              {
+                p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+                  canvas->columns,1,&canvas->exception);
+                if (p == (const Quantum *) NULL)
+                  break;
+                if ((red_gamma != 1.0) || (green_gamma != 1.0) ||
+                    (blue_gamma != 1.0))
+                  {
+                    /*
+                      Gamma correct canvas.
+                    */
+                    for (x=(int) canvas->columns-1; x >= 0; x--)
+                    {
+                      *q++=0;
+                      *q++=ScaleQuantumToChar(XRedGamma(
+                        GetPixelRed(canvas,p)));
+                      *q++=ScaleQuantumToChar(XGreenGamma(
+                        GetPixelGreen(canvas,p)));
+                      *q++=ScaleQuantumToChar(XBlueGamma(
+                        GetPixelBlue(canvas,p)));
+                      p+=GetPixelChannels(canvas);
+                    }
+                    continue;
+                  }
+                for (x=(int) canvas->columns-1; x >= 0; x--)
+                {
+                  *q++=0;
+                  *q++=ScaleQuantumToChar((Quantum)
+                    GetPixelRed(canvas,p));
+                  *q++=ScaleQuantumToChar((Quantum)
+                    GetPixelGreen(canvas,p));
+                  *q++=ScaleQuantumToChar((Quantum)
+                    GetPixelBlue(canvas,p));
+                  p+=GetPixelChannels(canvas);
+                }
+              }
+            }
+          else
+            if ((ximage->bits_per_pixel == 32) && (map_info->red_max == 255) &&
+                (map_info->green_max == 255) && (map_info->blue_max == 255) &&
+                (map_info->red_mult == 1) && (map_info->green_mult == 256) &&
+                (map_info->blue_mult == 65536L))
+              {
+                /*
+                  Convert to 32 bit continuous-tone X canvas.
+                */
+                for (y=0; y < (int) canvas->rows; y++)
+                {
+                  p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+                    canvas->columns,1,&canvas->exception);
+                  if (p == (const Quantum *) NULL)
+                    break;
+                  if ((red_gamma != 1.0) || (green_gamma != 1.0) ||
+                      (blue_gamma != 1.0))
+                    {
+                      /*
+                        Gamma correct canvas.
+                      */
+                      for (x=(int) canvas->columns-1; x >= 0; x--)
+                      {
+                        *q++=0;
+                        *q++=ScaleQuantumToChar(XBlueGamma(
+                          GetPixelBlue(canvas,p)));
+                        *q++=ScaleQuantumToChar(XGreenGamma(
+                          GetPixelGreen(canvas,p)));
+                        *q++=ScaleQuantumToChar(XRedGamma(
+                          GetPixelRed(canvas,p)));
+                        p+=GetPixelChannels(canvas);
+                      }
+                      continue;
+                    }
+                  for (x=(int) canvas->columns-1; x >= 0; x--)
+                  {
+                    *q++=0;
+                    *q++=ScaleQuantumToChar((Quantum)
+                      GetPixelBlue(canvas,p));
+                    *q++=ScaleQuantumToChar((Quantum)
+                      GetPixelGreen(canvas,p));
+                    *q++=ScaleQuantumToChar((Quantum)
+                      GetPixelRed(canvas,p));
+                    p+=GetPixelChannels(canvas);
+                  }
+                }
+              }
+            else
+              {
+                register int
+                  k;
+
+                register unsigned int
+                  bytes_per_pixel;
+
+                unsigned char
+                  channel[sizeof(size_t)];
+
+                /*
+                  Convert to multi-byte continuous-tone X canvas.
+                */
+                bytes_per_pixel=(unsigned int) (ximage->bits_per_pixel >> 3);
+                for (y=0; y < (int) canvas->rows; y++)
+                {
+                  p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,
+                    canvas->columns,1,&canvas->exception);
+                  if (p == (const Quantum *) NULL)
+                    break;
+                  for (x=(int) canvas->columns-1; x >= 0; x--)
+                  {
+                    pixel=XGammaPixel(canvas,map_info,p);
+                    for (k=(int) bytes_per_pixel-1; k >= 0; k--)
+                    {
+                      channel[k]=(unsigned char) pixel;
+                      pixel>>=8;
+                    }
+                    for (k=0; k < (int) bytes_per_pixel; k++)
+                      *q++=channel[k];
+                    p+=GetPixelChannels(canvas);
+                  }
+                  q+=scanline_pad;
+                }
+              }
+          break;
+        }
+      }
+  if (matte_image != (XImage *) NULL)
+    {
+      /*
+        Initialize matte canvas.
+      */
+      scanline_pad=(unsigned int) (matte_image->bytes_per_line-
+        ((matte_image->width*matte_image->bits_per_pixel) >> 3));
+      q=(unsigned char *) matte_image->data;
+      for (y=0; y < (int) canvas->rows; y++)
+      {
+        p=GetCacheViewVirtualPixels(canvas_view,0,(ssize_t) y,canvas->columns,1,
+          &canvas->exception);
+        if (p == (const Quantum *) NULL)
+          break;
+        bit=0;
+        byte=0;
+        for (x=(int) canvas->columns-1; x >= 0; x--)
+        {
+          byte<<=1;
+          if (GetPixelAlpha(canvas,p) > (QuantumRange/2))
+            byte|=0x01;
+          bit++;
+          if (bit == 8)
+            {
+              *q++=byte;
+              bit=0;
+              byte=0;
+            }
+          p+=GetPixelChannels(canvas);
+        }
+        if (bit != 0)
+          *q=byte << (8-bit);
+        q+=scanline_pad;
+      }
+    }
+  canvas_view=DestroyCacheView(canvas_view);
+  if (canvas != image)
+    canvas=DestroyImage(canvas);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a k e M a g n i f y I m a g e                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeMagnifyImage() magnifies a region of an X image and displays it.
+%
+%  The format of the XMakeMagnifyImage method is:
+%
+%      void XMakeMagnifyImage(display,windows)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+*/
+MagickExport void XMakeMagnifyImage(Display *display,XWindows *windows)
+{
+  char
+    tuple[MaxTextExtent];
+
+  int
+    y;
+
+  PixelInfo
+    pixel;
+
+  register int
+    x;
+
+  register ssize_t
+    i;
+
+  register unsigned char
+    *p,
+    *q;
+
+  ssize_t
+    n;
+
+  static unsigned int
+    previous_magnify = 0;
+
+  static XWindowInfo
+    magnify_window;
+
+  unsigned int
+    height,
+    j,
+    k,
+    l,
+    magnify,
+    scanline_pad,
+    width;
+
+  XImage
+    *ximage;
+
+  /*
+    Check boundary conditions.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  magnify=1;
+  for (n=1; n < (ssize_t) windows->magnify.data; n++)
+    magnify<<=1;
+  while ((magnify*windows->image.ximage->width) < windows->magnify.width)
+    magnify<<=1;
+  while ((magnify*windows->image.ximage->height) < windows->magnify.height)
+    magnify<<=1;
+  while (magnify > windows->magnify.width)
+    magnify>>=1;
+  while (magnify > windows->magnify.height)
+    magnify>>=1;
+  if (magnify != previous_magnify)
+    {
+      Status
+        status;
+
+      XTextProperty
+        window_name;
+
+      /*
+        New magnify factor:  update magnify window name.
+      */
+      i=0;
+      while ((1 << i) <= (int) magnify)
+        i++;
+      (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,
+        "Magnify %.20gX",(double) i);
+      status=XStringListToTextProperty(&windows->magnify.name,1,&window_name);
+      if (status != False)
+        {
+          XSetWMName(display,windows->magnify.id,&window_name);
+          XSetWMIconName(display,windows->magnify.id,&window_name);
+          (void) XFree((void *) window_name.value);
+        }
+    }
+  previous_magnify=magnify;
+  ximage=windows->image.ximage;
+  width=(unsigned int) windows->magnify.ximage->width;
+  height=(unsigned int) windows->magnify.ximage->height;
+  if ((windows->magnify.x < 0) ||
+      (windows->magnify.x >= windows->image.ximage->width))
+    windows->magnify.x=windows->image.ximage->width >> 1;
+  x=windows->magnify.x-((width/magnify) >> 1);
+  if (x < 0)
+    x=0;
+  else
+    if (x > (int) (ximage->width-(width/magnify)))
+      x=ximage->width-width/magnify;
+  if ((windows->magnify.y < 0) ||
+      (windows->magnify.y >= windows->image.ximage->height))
+    windows->magnify.y=windows->image.ximage->height >> 1;
+  y=windows->magnify.y-((height/magnify) >> 1);
+  if (y < 0)
+    y=0;
+  else
+    if (y > (int) (ximage->height-(height/magnify)))
+      y=ximage->height-height/magnify;
+  q=(unsigned char *) windows->magnify.ximage->data;
+  scanline_pad=(unsigned int) (windows->magnify.ximage->bytes_per_line-
+    ((width*windows->magnify.ximage->bits_per_pixel) >> 3));
+  if (ximage->bits_per_pixel < 8)
+    {
+      register unsigned char
+        background,
+        byte,
+        foreground,
+        p_bit,
+        q_bit;
+
+      register unsigned int
+        plane;
+
+      XPixelInfo
+        *pixel_info;
+
+      pixel_info=windows->magnify.pixel_info;
+      switch (ximage->bitmap_bit_order)
+      {
+        case LSBFirst:
+        {
+          /*
+            Magnify little-endian bitmap.
+          */
+          background=0x00;
+          foreground=0x80;
+          if (ximage->format == XYBitmap)
+            {
+              background=(unsigned char)
+                (XPixelIntensity(&pixel_info->foreground_color) <
+                 XPixelIntensity(&pixel_info->background_color) ?  0x80 : 0x00);
+              foreground=(unsigned char)
+                (XPixelIntensity(&pixel_info->background_color) <
+                 XPixelIntensity(&pixel_info->foreground_color) ?  0x80 : 0x00);
+              if (windows->magnify.depth > 1)
+                Swap(background,foreground);
+            }
+          for (i=0; i < (ssize_t) height; i+=magnify)
+          {
+            /*
+              Propogate pixel magnify rows.
+            */
+            for (j=0; j < magnify; j++)
+            {
+              p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
+                ((x*ximage->bits_per_pixel) >> 3);
+              p_bit=(unsigned char) (x*ximage->bits_per_pixel) & 0x07;
+              q_bit=0;
+              byte=0;
+              for (k=0; k < width; k+=magnify)
+              {
+                /*
+                  Propogate pixel magnify columns.
+                */
+                for (l=0; l < magnify; l++)
+                {
+                  /*
+                    Propogate each bit plane.
+                  */
+                  for (plane=0; (int) plane < ximage->bits_per_pixel; plane++)
+                  {
+                    byte>>=1;
+                    if (*p & (0x01 << (p_bit+plane)))
+                      byte|=foreground;
+                    else
+                      byte|=background;
+                    q_bit++;
+                    if (q_bit == 8)
+                      {
+                        *q++=byte;
+                        q_bit=0;
+                        byte=0;
+                      }
+                  }
+                }
+                p_bit+=ximage->bits_per_pixel;
+                if (p_bit == 8)
+                  {
+                    p++;
+                    p_bit=0;
+                  }
+                if (q_bit != 0)
+                  *q=byte >> (8-q_bit);
+                q+=scanline_pad;
+              }
+            }
+            y++;
+          }
+          break;
+        }
+        case MSBFirst:
+        default:
+        {
+          /*
+            Magnify big-endian bitmap.
+          */
+          background=0x00;
+          foreground=0x01;
+          if (ximage->format == XYBitmap)
+            {
+              background=(unsigned char)
+                (XPixelIntensity(&pixel_info->foreground_color) <
+                 XPixelIntensity(&pixel_info->background_color) ?  0x01 : 0x00);
+              foreground=(unsigned char)
+                (XPixelIntensity(&pixel_info->background_color) <
+                 XPixelIntensity(&pixel_info->foreground_color) ?  0x01 : 0x00);
+              if (windows->magnify.depth > 1)
+                Swap(background,foreground);
+            }
+          for (i=0; i < (ssize_t) height; i+=magnify)
+          {
+            /*
+              Propogate pixel magnify rows.
+            */
+            for (j=0; j < magnify; j++)
+            {
+              p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
+                ((x*ximage->bits_per_pixel) >> 3);
+              p_bit=(unsigned char) (x*ximage->bits_per_pixel) & 0x07;
+              q_bit=0;
+              byte=0;
+              for (k=0; k < width; k+=magnify)
+              {
+                /*
+                  Propogate pixel magnify columns.
+                */
+                for (l=0; l < magnify; l++)
+                {
+                  /*
+                    Propogate each bit plane.
+                  */
+                  for (plane=0; (int) plane < ximage->bits_per_pixel; plane++)
+                  {
+                    byte<<=1;
+                    if (*p & (0x80 >> (p_bit+plane)))
+                      byte|=foreground;
+                    else
+                      byte|=background;
+                    q_bit++;
+                    if (q_bit == 8)
+                      {
+                        *q++=byte;
+                        q_bit=0;
+                        byte=0;
+                      }
+                  }
+                }
+                p_bit+=ximage->bits_per_pixel;
+                if (p_bit == 8)
+                  {
+                    p++;
+                    p_bit=0;
+                  }
+                if (q_bit != 0)
+                  *q=byte << (8-q_bit);
+                q+=scanline_pad;
+              }
+            }
+            y++;
+          }
+          break;
+        }
+      }
+    }
+  else
+    switch (ximage->bits_per_pixel)
+    {
+      case 6:
+      case 8:
+      {
+        /*
+          Magnify 8 bit X image.
+        */
+        for (i=0; i < (ssize_t) height; i+=magnify)
+        {
+          /*
+            Propogate pixel magnify rows.
+          */
+          for (j=0; j < magnify; j++)
+          {
+            p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
+              ((x*ximage->bits_per_pixel) >> 3);
+            for (k=0; k < width; k+=magnify)
+            {
+              /*
+                Propogate pixel magnify columns.
+              */
+              for (l=0; l < magnify; l++)
+                *q++=(*p);
+              p++;
+            }
+            q+=scanline_pad;
+          }
+          y++;
+        }
+        break;
+      }
+      default:
+      {
+        register unsigned int
+          bytes_per_pixel,
+          m;
+
+        /*
+          Magnify multi-byte X image.
+        */
+        bytes_per_pixel=(unsigned int) ximage->bits_per_pixel >> 3;
+        for (i=0; i < (ssize_t) height; i+=magnify)
+        {
+          /*
+            Propogate pixel magnify rows.
+          */
+          for (j=0; j < magnify; j++)
+          {
+            p=(unsigned char *) ximage->data+y*ximage->bytes_per_line+
+              ((x*ximage->bits_per_pixel) >> 3);
+            for (k=0; k < width; k+=magnify)
+            {
+              /*
+                Propogate pixel magnify columns.
+              */
+              for (l=0; l < magnify; l++)
+                for (m=0; m < bytes_per_pixel; m++)
+                  *q++=(*(p+m));
+              p+=bytes_per_pixel;
+            }
+            q+=scanline_pad;
+          }
+          y++;
+        }
+        break;
+      }
+    }
+  /*
+    Copy X image to magnify pixmap.
+  */
+  x=windows->magnify.x-((width/magnify) >> 1);
+  if (x < 0)
+    x=(int) ((width >> 1)-windows->magnify.x*magnify);
+  else
+    if (x > (int) (ximage->width-(width/magnify)))
+      x=(int) ((ximage->width-windows->magnify.x)*magnify-(width >> 1));
+    else
+      x=0;
+  y=windows->magnify.y-((height/magnify) >> 1);
+  if (y < 0)
+    y=(int) ((height >> 1)-windows->magnify.y*magnify);
+  else
+    if (y > (int) (ximage->height-(height/magnify)))
+      y=(int) ((ximage->height-windows->magnify.y)*magnify-(height >> 1));
+    else
+      y=0;
+  if ((x != 0) || (y != 0))
+    (void) XFillRectangle(display,windows->magnify.pixmap,
+      windows->magnify.annotate_context,0,0,width,height);
+  (void) XPutImage(display,windows->magnify.pixmap,
+    windows->magnify.annotate_context,windows->magnify.ximage,0,0,x,y,width-x,
+    height-y);
+  if ((magnify > 1) && ((magnify <= (width >> 1)) &&
+      (magnify <= (height >> 1))))
+    {
+      RectangleInfo
+        highlight_info;
+
+      /*
+        Highlight center pixel.
+      */
+      highlight_info.x=(ssize_t) windows->magnify.width >> 1;
+      highlight_info.y=(ssize_t) windows->magnify.height >> 1;
+      highlight_info.width=magnify;
+      highlight_info.height=magnify;
+      (void) XDrawRectangle(display,windows->magnify.pixmap,
+        windows->magnify.highlight_context,(int) highlight_info.x,
+        (int) highlight_info.y,(unsigned int) highlight_info.width-1,
+        (unsigned int) highlight_info.height-1);
+      if (magnify > 2)
+        (void) XDrawRectangle(display,windows->magnify.pixmap,
+          windows->magnify.annotate_context,(int) highlight_info.x+1,
+          (int) highlight_info.y+1,(unsigned int) highlight_info.width-3,
+          (unsigned int) highlight_info.height-3);
+    }
+  /*
+    Show center pixel color.
+  */
+  (void) GetOneVirtualMagickPixel(windows->image.image,(ssize_t)
+    windows->magnify.x,(ssize_t) windows->magnify.y,&pixel,
+    &windows->image.image->exception);
+  (void) FormatLocaleString(tuple,MaxTextExtent,"%d,%d: ",
+    windows->magnify.x,windows->magnify.y);
+  (void) ConcatenateMagickString(tuple,"(",MaxTextExtent);
+  ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
+  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+  ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
+  (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+  ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
+  if (pixel.colorspace == CMYKColorspace)
+    {
+      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+      ConcatenateColorComponent(&pixel,BlackChannel,X11Compliance,tuple);
+    }
+  if (pixel.matte != MagickFalse)
+    {
+      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
+      ConcatenateColorComponent(&pixel,OpacityChannel,X11Compliance,tuple);
+    }
+  (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
+  height=(unsigned int) windows->magnify.font_info->ascent+
+    windows->magnify.font_info->descent;
+  x=windows->magnify.font_info->max_bounds.width >> 1;
+  y=windows->magnify.font_info->ascent+(height >> 2);
+  (void) XDrawImageString(display,windows->magnify.pixmap,
+    windows->magnify.annotate_context,x,y,tuple,(int) strlen(tuple));
+  GetColorTuple(&pixel,MagickTrue,tuple);
+  y+=height;
+  (void) XDrawImageString(display,windows->magnify.pixmap,
+    windows->magnify.annotate_context,x,y,tuple,(int) strlen(tuple));
+  (void) QueryMagickColorname(windows->image.image,&pixel,SVGCompliance,tuple,
+     &windows->image.image->exception);
+  y+=height;
+  (void) XDrawImageString(display,windows->magnify.pixmap,
+    windows->magnify.annotate_context,x,y,tuple,(int) strlen(tuple));
+  /*
+    Refresh magnify window.
+  */
+  magnify_window=windows->magnify;
+  magnify_window.x=0;
+  magnify_window.y=0;
+  XRefreshWindow(display,&magnify_window,(XEvent *) NULL);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a k e P i x m a p                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakePixmap() creates an X11 pixmap.
+%
+%  The format of the XMakePixmap method is:
+%
+%      void XMakeStandardColormap(Display *display,XVisualInfo *visual_info,
+%        XResourceInfo *resource_info,Image *image,XStandardColormap *map_info,
+%        XPixelInfo *pixel)
+%
+%  A description of each parameter follows:
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindowInfo structure.
+%
+*/
+static MagickBooleanType XMakePixmap(Display *display,
+  const XResourceInfo *resource_info,XWindowInfo *window)
+{
+  unsigned int
+    height,
+    width;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(window != (XWindowInfo  *) NULL);
+  if (window->pixmap != (Pixmap) NULL)
+    {
+      /*
+        Destroy previous X pixmap.
+      */
+      (void) XFreePixmap(display,window->pixmap);
+      window->pixmap=(Pixmap) NULL;
+    }
+  if (window->use_pixmap == MagickFalse)
+    return(MagickFalse);
+  if (window->ximage == (XImage *) NULL)
+    return(MagickFalse);
+  /*
+    Display busy cursor.
+  */
+  (void) XCheckDefineCursor(display,window->id,window->busy_cursor);
+  (void) XFlush(display);
+  /*
+    Create pixmap.
+  */
+  width=(unsigned int) window->ximage->width;
+  height=(unsigned int) window->ximage->height;
+  window->pixmap=XCreatePixmap(display,window->id,width,height,window->depth);
+  if (window->pixmap == (Pixmap) NULL)
+    {
+      /*
+        Unable to allocate pixmap.
+      */
+      (void) XCheckDefineCursor(display,window->id,window->cursor);
+      return(MagickFalse);
+    }
+  /*
+    Copy X image to pixmap.
+  */
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+  if (window->shared_memory)
+    (void) XShmPutImage(display,window->pixmap,window->annotate_context,
+      window->ximage,0,0,0,0,width,height,MagickTrue);
+#endif
+  if (window->shared_memory == MagickFalse)
+    (void) XPutImage(display,window->pixmap,window->annotate_context,
+      window->ximage,0,0,0,0,width,height);
+  if (IsEventLogging())
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"Pixmap:");
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  width, height: %ux%u",
+        width,height);
+    }
+  /*
+    Restore cursor.
+  */
+  (void) XCheckDefineCursor(display,window->id,window->cursor);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a k e S t a n d a r d C o l o r m a p                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeStandardColormap() creates an X11 Standard Colormap.
+%
+%  The format of the XMakeStandardColormap method is:
+%
+%      XMakeStandardColormap(display,visual_info,resource_info,image,
+%        map_info,pixel)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o visual_info: Specifies a pointer to a X11 XVisualInfo structure;
+%      returned from XGetVisualInfo.
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+%    o image: the image.
+%
+%    o map_info: If a Standard Colormap type is specified, this structure is
+%      initialized with info from the Standard Colormap.
+%
+%    o pixel: Specifies a pointer to a XPixelInfo structure.
+%
+*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static inline MagickRealType DiversityPixelIntensity(
+  const DiversityPacket *pixel)
+{
+  MagickRealType
+    intensity;
+
+  intensity=0.299*pixel->red+0.587*pixel->green+0.114*pixel->blue;
+  return(intensity);
+}
+
+static int IntensityCompare(const void *x,const void *y)
+{
+  DiversityPacket
+    *color_1,
+    *color_2;
+
+  int
+    diversity;
+
+  color_1=(DiversityPacket *) x;
+  color_2=(DiversityPacket *) y;
+  diversity=(int) (DiversityPixelIntensity(color_2)-
+    DiversityPixelIntensity(color_1));
+  return(diversity);
+}
+
+static int PopularityCompare(const void *x,const void *y)
+{
+  DiversityPacket
+    *color_1,
+    *color_2;
+
+  color_1=(DiversityPacket *) x;
+  color_2=(DiversityPacket *) y;
+  return((int) color_2->count-(int) color_1->count);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+static inline Quantum ScaleXToQuantum(const size_t x,
+  const size_t scale)
+{
+  return((Quantum) (((MagickRealType) QuantumRange*x)/scale+0.5));
+}
+
+MagickExport void XMakeStandardColormap(Display *display,
+  XVisualInfo *visual_info,XResourceInfo *resource_info,Image *image,
+  XStandardColormap *map_info,XPixelInfo *pixel)
+{
+  Colormap
+    colormap;
+
+  ExceptionInfo
+    *exception;
+
+  register ssize_t
+    i;
+
+  Status
+    status;
+
+  size_t
+    number_colors,
+    retain_colors;
+
+  unsigned short
+    gray_value;
+
+  XColor
+    color,
+    *colors,
+    *p;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(visual_info != (XVisualInfo *) NULL);
+  assert(map_info != (XStandardColormap *) NULL);
+  assert(resource_info != (XResourceInfo *) NULL);
+  assert(pixel != (XPixelInfo *) NULL);
+  exception=(&image->exception);
+  if (resource_info->map_type != (char *) NULL)
+    {
+      /*
+        Standard Colormap is already defined (i.e. xstdcmap).
+      */
+      XGetPixelInfo(display,visual_info,map_info,resource_info,image,
+        pixel);
+      number_colors=(unsigned int) (map_info->base_pixel+
+        (map_info->red_max+1)*(map_info->green_max+1)*(map_info->blue_max+1));
+      if ((map_info->red_max*map_info->green_max*map_info->blue_max) != 0)
+        if ((image->matte == MagickFalse) &&
+            (resource_info->color_recovery == MagickFalse) &&
+            resource_info->quantize_info->dither &&
+            (number_colors < MaxColormapSize))
+          {
+            Image
+              *affinity_image;
+
+            register Quantum
+              *restrict q;
+
+            /*
+              Improve image appearance with error diffusion.
+            */
+            affinity_image=AcquireImage((ImageInfo *) NULL);
+            if (affinity_image == (Image *) NULL)
+              ThrowXWindowFatalException(ResourceLimitFatalError,
+                "UnableToDitherImage",image->filename);
+            affinity_image->columns=number_colors;
+            affinity_image->rows=1;
+            /*
+              Initialize colormap image.
+            */
+            q=QueueAuthenticPixels(affinity_image,0,0,affinity_image->columns,
+              1,exception);
+            if (q != (Quantum *) NULL)
+              {
+                for (i=0; i < (ssize_t) number_colors; i++)
+                {
+                  SetPixelRed(affinity_image,0,q);
+                  if (map_info->red_max != 0)
+                    SetPixelRed(affinity_image,
+                      ScaleXToQuantum((size_t) (i/map_info->red_mult),
+                      map_info->red_max),q);
+                  SetPixelGreen(affinity_image,0,q);
+                  if (map_info->green_max != 0)
+                    SetPixelGreen(affinity_image,
+                      ScaleXToQuantum((size_t) ((i/map_info->green_mult) %
+                      (map_info->green_max+1)),map_info->green_max),q);
+                  SetPixelBlue(affinity_image,0,q);
+                  if (map_info->blue_max != 0)
+                    SetPixelBlue(affinity_image,
+                      ScaleXToQuantum((size_t) (i % map_info->green_mult),
+                      map_info->blue_max),q);
+                  SetPixelAlpha(affinity_image,
+                    TransparentAlpha,q);
+                  q+=GetPixelChannels(affinity_image);
+                }
+                (void) SyncAuthenticPixels(affinity_image,exception);
+                (void) RemapImage(resource_info->quantize_info,image,
+                  affinity_image);
+              }
+            XGetPixelInfo(display,visual_info,map_info,resource_info,image,
+              pixel);
+            (void) SetImageStorageClass(image,DirectClass);
+            affinity_image=DestroyImage(affinity_image);
+          }
+      if (IsEventLogging())
+        {
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "Standard Colormap:");
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "  colormap id: 0x%lx",map_info->colormap);
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "  red, green, blue max: %lu %lu %lu",map_info->red_max,
+            map_info->green_max,map_info->blue_max);
+          (void) LogMagickEvent(X11Event,GetMagickModule(),
+            "  red, green, blue mult: %lu %lu %lu",map_info->red_mult,
+            map_info->green_mult,map_info->blue_mult);
+        }
+      return;
+    }
+  if ((visual_info->klass != DirectColor) &&
+      (visual_info->klass != TrueColor))
+    if ((image->storage_class == DirectClass) ||
+        ((int) image->colors > visual_info->colormap_size))
+      {
+        QuantizeInfo
+          quantize_info;
+
+        /*
+          Image has more colors than the visual supports.
+        */
+        quantize_info=(*resource_info->quantize_info);
+        quantize_info.number_colors=(size_t) visual_info->colormap_size;
+        (void) QuantizeImage(&quantize_info,image);
+      }
+  /*
+    Free previous and create new colormap.
+  */
+  (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
+  colormap=XDefaultColormap(display,visual_info->screen);
+  if (visual_info->visual != XDefaultVisual(display,visual_info->screen))
+    colormap=XCreateColormap(display,XRootWindow(display,visual_info->screen),
+      visual_info->visual,visual_info->klass == DirectColor ?
+      AllocAll : AllocNone);
+  if (colormap == (Colormap) NULL)
+    ThrowXWindowFatalException(ResourceLimitFatalError,"UnableToCreateColormap",
+      image->filename);
+  /*
+    Initialize the map and pixel info structures.
+  */
+  XGetMapInfo(visual_info,colormap,map_info);
+  XGetPixelInfo(display,visual_info,map_info,resource_info,image,pixel);
+  /*
+    Allocating colors in server colormap is based on visual class.
+  */
+  switch (visual_info->klass)
+  {
+    case StaticGray:
+    case StaticColor:
+    {
+      /*
+        Define Standard Colormap for StaticGray or StaticColor visual.
+      */
+      number_colors=image->colors;
+      colors=(XColor *) AcquireQuantumMemory((size_t)
+        visual_info->colormap_size,sizeof(*colors));
+      if (colors == (XColor *) NULL)
+        ThrowXWindowFatalException(ResourceLimitFatalError,
+          "UnableToCreateColormap",image->filename);
+      p=colors;
+      color.flags=(char) (DoRed | DoGreen | DoBlue);
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        color.red=ScaleQuantumToShort(XRedGamma(image->colormap[i].red));
+        color.green=ScaleQuantumToShort(XGreenGamma(image->colormap[i].green));
+        color.blue=ScaleQuantumToShort(XBlueGamma(image->colormap[i].blue));
+        if (visual_info->klass != StaticColor)
+          {
+            gray_value=(unsigned short) XPixelIntensity(&color);
+            color.red=gray_value;
+            color.green=gray_value;
+            color.blue=gray_value;
+          }
+        status=XAllocColor(display,colormap,&color);
+        if (status == False)
+          {
+            colormap=XCopyColormapAndFree(display,colormap);
+            (void) XAllocColor(display,colormap,&color);
+          }
+        pixel->pixels[i]=color.pixel;
+        *p++=color;
+      }
+      break;
+    }
+    case GrayScale:
+    case PseudoColor:
+    {
+      unsigned int
+        colormap_type;
+
+      /*
+        Define Standard Colormap for GrayScale or PseudoColor visual.
+      */
+      number_colors=image->colors;
+      colors=(XColor *) AcquireQuantumMemory((size_t)
+        visual_info->colormap_size,sizeof(*colors));
+      if (colors == (XColor *) NULL)
+        ThrowXWindowFatalException(ResourceLimitFatalError,
+          "UnableToCreateColormap",image->filename);
+      /*
+        Preallocate our GUI colors.
+      */
+      (void) XAllocColor(display,colormap,&pixel->foreground_color);
+      (void) XAllocColor(display,colormap,&pixel->background_color);
+      (void) XAllocColor(display,colormap,&pixel->border_color);
+      (void) XAllocColor(display,colormap,&pixel->matte_color);
+      (void) XAllocColor(display,colormap,&pixel->highlight_color);
+      (void) XAllocColor(display,colormap,&pixel->shadow_color);
+      (void) XAllocColor(display,colormap,&pixel->depth_color);
+      (void) XAllocColor(display,colormap,&pixel->trough_color);
+      for (i=0; i < MaxNumberPens; i++)
+        (void) XAllocColor(display,colormap,&pixel->pen_colors[i]);
+      /*
+        Determine if image colors will "fit" into X server colormap.
+      */
+      colormap_type=resource_info->colormap;
+      status=XAllocColorCells(display,colormap,MagickFalse,(unsigned long *)
+        NULL,0,pixel->pixels,(unsigned int) image->colors);
+      if (status != False)
+        colormap_type=PrivateColormap;
+      if (colormap_type == SharedColormap)
+        {
+          CacheView
+            *image_view;
+
+          DiversityPacket
+            *diversity;
+
+          int
+            y;
+
+          register int
+            x;
+
+          unsigned short
+            index;
+
+          XColor
+            *server_colors;
+
+          /*
+            Define Standard colormap for shared GrayScale or PseudoColor visual.
+          */
+          diversity=(DiversityPacket *) AcquireQuantumMemory(image->colors,
+            sizeof(*diversity));
+          if (diversity == (DiversityPacket *) NULL)
+            ThrowXWindowFatalException(ResourceLimitFatalError,
+              "UnableToCreateColormap",image->filename);
+          for (i=0; i < (ssize_t) image->colors; i++)
+          {
+            diversity[i].red=image->colormap[i].red;
+            diversity[i].green=image->colormap[i].green;
+            diversity[i].blue=image->colormap[i].blue;
+            diversity[i].index=(unsigned short) i;
+            diversity[i].count=0;
+          }
+          image_view=AcquireCacheView(image);
+          for (y=0; y < (int) image->rows; y++)
+          {
+            register int
+              x;
+
+            register const Quantum
+              *restrict p;
+
+            p=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
+              image->columns,1,exception);
+            if (p == (const Quantum *) NULL)
+              break;
+            for (x=(int) image->columns-1; x >= 0; x--)
+            {
+              diversity[(ssize_t) GetPixelIndex(image,p)].count++;
+              p+=GetPixelChannels(image);
+            }
+          }
+          image_view=DestroyCacheView(image_view);
+          /*
+            Sort colors by decreasing intensity.
+          */
+          qsort((void *) diversity,image->colors,sizeof(*diversity),
+            IntensityCompare);
+          for (i=0; i < (ssize_t) image->colors; )
+          {
+            diversity[i].count<<=4;  /* increase this colors popularity */
+            i+=MagickMax((int) (image->colors >> 4),2);
+          }
+          diversity[image->colors-1].count<<=4;
+          qsort((void *) diversity,image->colors,sizeof(*diversity),
+            PopularityCompare);
+          /*
+            Allocate colors.
+          */
+          p=colors;
+          color.flags=(char) (DoRed | DoGreen | DoBlue);
+          for (i=0; i < (ssize_t) image->colors; i++)
+          {
+            index=diversity[i].index;
+            color.red=
+              ScaleQuantumToShort(XRedGamma(image->colormap[index].red));
+            color.green=
+              ScaleQuantumToShort(XGreenGamma(image->colormap[index].green));
+            color.blue=
+              ScaleQuantumToShort(XBlueGamma(image->colormap[index].blue));
+            if (visual_info->klass != PseudoColor)
+              {
+                gray_value=(unsigned short) XPixelIntensity(&color);
+                color.red=gray_value;
+                color.green=gray_value;
+                color.blue=gray_value;
+              }
+            status=XAllocColor(display,colormap,&color);
+            if (status == False)
+              break;
+            pixel->pixels[index]=color.pixel;
+            *p++=color;
+          }
+          /*
+            Read X server colormap.
+          */
+          server_colors=(XColor *) AcquireQuantumMemory((size_t)
+            visual_info->colormap_size,sizeof(*server_colors));
+          if (server_colors == (XColor *) NULL)
+            ThrowXWindowFatalException(ResourceLimitFatalError,
+              "UnableToCreateColormap",image->filename);
+          for (x=visual_info->colormap_size-1; x >= 0; x--)
+            server_colors[x].pixel=(size_t) x;
+          (void) XQueryColors(display,colormap,server_colors,
+            (int) MagickMin((unsigned int) visual_info->colormap_size,256));
+          /*
+            Select remaining colors from X server colormap.
+          */
+          for (; i < (ssize_t) image->colors; i++)
+          {
+            index=diversity[i].index;
+            color.red=
+              ScaleQuantumToShort(XRedGamma(image->colormap[index].red));
+            color.green=
+              ScaleQuantumToShort(XGreenGamma(image->colormap[index].green));
+            color.blue=
+              ScaleQuantumToShort(XBlueGamma(image->colormap[index].blue));
+            if (visual_info->klass != PseudoColor)
+              {
+                gray_value=(unsigned short) XPixelIntensity(&color);
+                color.red=gray_value;
+                color.green=gray_value;
+                color.blue=gray_value;
+              }
+            XBestPixel(display,colormap,server_colors,(unsigned int)
+              visual_info->colormap_size,&color);
+            pixel->pixels[index]=color.pixel;
+            *p++=color;
+          }
+          if ((int) image->colors < visual_info->colormap_size)
+            {
+              /*
+                Fill up colors array-- more choices for pen colors.
+              */
+              retain_colors=MagickMin((unsigned int)
+               (visual_info->colormap_size-image->colors),256);
+              for (i=0; i < (ssize_t) retain_colors; i++)
+                *p++=server_colors[i];
+              number_colors+=retain_colors;
+            }
+          server_colors=(XColor *) RelinquishMagickMemory(server_colors);
+          diversity=(DiversityPacket *) RelinquishMagickMemory(diversity);
+          break;
+        }
+      /*
+        Define Standard colormap for private GrayScale or PseudoColor visual.
+      */
+      if (status == False)
+        {
+          /*
+            Not enough colormap entries in the colormap-- Create a new colormap.
+          */
+          colormap=XCreateColormap(display,
+            XRootWindow(display,visual_info->screen),visual_info->visual,
+            AllocNone);
+          if (colormap == (Colormap) NULL)
+            ThrowXWindowFatalException(ResourceLimitFatalError,
+              "UnableToCreateColormap",image->filename);
+          map_info->colormap=colormap;
+          if ((int) image->colors < visual_info->colormap_size)
+            {
+              /*
+                Retain colors from the default colormap to help lessens the
+                effects of colormap flashing.
+              */
+              retain_colors=MagickMin((unsigned int)
+                (visual_info->colormap_size-image->colors),256);
+              p=colors+image->colors;
+              for (i=0; i < (ssize_t) retain_colors; i++)
+              {
+                p->pixel=(unsigned long) i;
+                p++;
+              }
+              (void) XQueryColors(display,
+                XDefaultColormap(display,visual_info->screen),
+                colors+image->colors,(int) retain_colors);
+              /*
+                Transfer colors from default to private colormap.
+              */
+              (void) XAllocColorCells(display,colormap,MagickFalse,
+                (unsigned long *) NULL,0,pixel->pixels,(unsigned int)
+                retain_colors);
+              p=colors+image->colors;
+              for (i=0; i < (ssize_t) retain_colors; i++)
+              {
+                p->pixel=pixel->pixels[i];
+                p++;
+              }
+              (void) XStoreColors(display,colormap,colors+image->colors,
+                (int) retain_colors);
+              number_colors+=retain_colors;
+            }
+          (void) XAllocColorCells(display,colormap,MagickFalse,
+            (unsigned long *) NULL,0,pixel->pixels,(unsigned int)
+            image->colors);
+        }
+      /*
+        Store the image colormap.
+      */
+      p=colors;
+      color.flags=(char) (DoRed | DoGreen | DoBlue);
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        color.red=ScaleQuantumToShort(XRedGamma(image->colormap[i].red));
+        color.green=ScaleQuantumToShort(XGreenGamma(image->colormap[i].green));
+        color.blue=ScaleQuantumToShort(XBlueGamma(image->colormap[i].blue));
+        if (visual_info->klass != PseudoColor)
+          {
+            gray_value=(unsigned short) XPixelIntensity(&color);
+            color.red=gray_value;
+            color.green=gray_value;
+            color.blue=gray_value;
+          }
+        color.pixel=pixel->pixels[i];
+        *p++=color;
+      }
+      (void) XStoreColors(display,colormap,colors,(int) image->colors);
+      break;
+    }
+    case TrueColor:
+    case DirectColor:
+    default:
+    {
+      MagickBooleanType
+        linear_colormap;
+
+      /*
+        Define Standard Colormap for TrueColor or DirectColor visual.
+      */
+      number_colors=(unsigned int) ((map_info->red_max*map_info->red_mult)+
+        (map_info->green_max*map_info->green_mult)+
+        (map_info->blue_max*map_info->blue_mult)+1);
+      linear_colormap=(number_colors > 4096) ||
+        (((int) (map_info->red_max+1) == visual_info->colormap_size) &&
+         ((int) (map_info->green_max+1) == visual_info->colormap_size) &&
+         ((int) (map_info->blue_max+1) == visual_info->colormap_size)) ?
+         MagickTrue : MagickFalse;
+      if (linear_colormap != MagickFalse)
+        number_colors=(size_t) visual_info->colormap_size;
+      /*
+        Allocate color array.
+      */
+      colors=(XColor *) AcquireQuantumMemory(number_colors,sizeof(*colors));
+      if (colors == (XColor *) NULL)
+        ThrowXWindowFatalException(ResourceLimitFatalError,
+          "UnableToCreateColormap",image->filename);
+      /*
+        Initialize linear color ramp.
+      */
+      p=colors;
+      color.flags=(char) (DoRed | DoGreen | DoBlue);
+      if (linear_colormap != MagickFalse)
+        for (i=0; i < (ssize_t) number_colors; i++)
+        {
+          color.blue=(unsigned short) 0;
+          if (map_info->blue_max != 0)
+            color.blue=(unsigned short) ((size_t)
+              ((65535L*(i % map_info->green_mult))/map_info->blue_max));
+          color.green=color.blue;
+          color.red=color.blue;
+          color.pixel=XStandardPixel(map_info,&color);
+          *p++=color;
+        }
+      else
+        for (i=0; i < (ssize_t) number_colors; i++)
+        {
+          color.red=(unsigned short) 0;
+          if (map_info->red_max != 0)
+            color.red=(unsigned short) ((size_t)
+              ((65535L*(i/map_info->red_mult))/map_info->red_max));
+          color.green=(unsigned int) 0;
+          if (map_info->green_max != 0)
+            color.green=(unsigned short) ((size_t)
+              ((65535L*((i/map_info->green_mult) % (map_info->green_max+1)))/
+                map_info->green_max));
+          color.blue=(unsigned short) 0;
+          if (map_info->blue_max != 0)
+            color.blue=(unsigned short) ((size_t)
+              ((65535L*(i % map_info->green_mult))/map_info->blue_max));
+          color.pixel=XStandardPixel(map_info,&color);
+          *p++=color;
+        }
+      if ((visual_info->klass == DirectColor) &&
+          (colormap != XDefaultColormap(display,visual_info->screen)))
+        (void) XStoreColors(display,colormap,colors,(int) number_colors);
+      else
+        for (i=0; i < (ssize_t) number_colors; i++)
+          (void) XAllocColor(display,colormap,&colors[i]);
+      break;
+    }
+  }
+  if ((visual_info->klass != DirectColor) &&
+      (visual_info->klass != TrueColor))
+    {
+      /*
+        Set foreground, background, border, etc. pixels.
+      */
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->foreground_color);
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->background_color);
+      if (pixel->background_color.pixel == pixel->foreground_color.pixel)
+        {
+          /*
+            Foreground and background colors must differ.
+          */
+          pixel->background_color.red=(~pixel->foreground_color.red);
+          pixel->background_color.green=
+            (~pixel->foreground_color.green);
+          pixel->background_color.blue=
+            (~pixel->foreground_color.blue);
+          XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+            &pixel->background_color);
+        }
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->border_color);
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->matte_color);
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->highlight_color);
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->shadow_color);
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->depth_color);
+      XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+        &pixel->trough_color);
+      for (i=0; i < MaxNumberPens; i++)
+      {
+        XBestPixel(display,colormap,colors,(unsigned int) number_colors,
+          &pixel->pen_colors[i]);
+        pixel->pixels[image->colors+i]=pixel->pen_colors[i].pixel;
+      }
+      pixel->colors=(ssize_t) (image->colors+MaxNumberPens);
+    }
+  colors=(XColor *) RelinquishMagickMemory(colors);
+  if (IsEventLogging())
+    {
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"Standard Colormap:");
+      (void) LogMagickEvent(X11Event,GetMagickModule(),"  colormap id: 0x%lx",
+        map_info->colormap);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  red, green, blue max: %lu %lu %lu",map_info->red_max,
+        map_info->green_max,map_info->blue_max);
+      (void) LogMagickEvent(X11Event,GetMagickModule(),
+        "  red, green, blue mult: %lu %lu %lu",map_info->red_mult,
+        map_info->green_mult,map_info->blue_mult);
+    }
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a k e W i n d o w                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMakeWindow() creates an X11 window.
+%
+%  The format of the XMakeWindow method is:
+%
+%      void XMakeWindow(Display *display,Window parent,char **argv,int argc,
+%        XClassHint *class_hint,XWMHints *manager_hints,
+%        XWindowInfo *window_info)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o parent: Specifies the parent window_info.
+%
+%    o argv: Specifies the application's argument list.
+%
+%    o argc: Specifies the number of arguments.
+%
+%    o class_hint: Specifies a pointer to a X11 XClassHint structure.
+%
+%    o manager_hints: Specifies a pointer to a X11 XWMHints structure.
+%
+%    o window_info: Specifies a pointer to a X11 XWindowInfo structure.
+%
+*/
+MagickExport void XMakeWindow(Display *display,Window parent,char **argv,
+  int argc,XClassHint *class_hint,XWMHints *manager_hints,
+  XWindowInfo *window_info)
+{
+#define MinWindowSize  64
+
+  Atom
+    atom_list[2];
+
+  int
+    gravity;
+
+  static XTextProperty
+    icon_name,
+    window_name;
+
+  Status
+    status;
+
+  XSizeHints
+    *size_hints;
+
+  /*
+    Set window info hints.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window_info != (XWindowInfo *) NULL);
+  size_hints=XAllocSizeHints();
+  if (size_hints == (XSizeHints *) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToMakeXWindow",argv[0]);
+  size_hints->flags=(int) window_info->flags;
+  size_hints->x=window_info->x;
+  size_hints->y=window_info->y;
+  size_hints->width=(int) window_info->width;
+  size_hints->height=(int) window_info->height;
+  if (window_info->immutable != MagickFalse)
+    {
+      /*
+        Window size cannot be changed.
+      */
+      size_hints->min_width=size_hints->width;
+      size_hints->min_height=size_hints->height;
+      size_hints->max_width=size_hints->width;
+      size_hints->max_height=size_hints->height;
+      size_hints->flags|=PMinSize;
+      size_hints->flags|=PMaxSize;
+    }
+  else
+    {
+      /*
+        Window size can be changed.
+      */
+      size_hints->min_width=(int) window_info->min_width;
+      size_hints->min_height=(int) window_info->min_height;
+      size_hints->flags|=PResizeInc;
+      size_hints->width_inc=(int) window_info->width_inc;
+      size_hints->height_inc=(int) window_info->height_inc;
+#if !defined(PRE_R4_ICCCM)
+      size_hints->flags|=PBaseSize;
+      size_hints->base_width=size_hints->width_inc;
+      size_hints->base_height=size_hints->height_inc;
+#endif
+    }
+  gravity=NorthWestGravity;
+  if (window_info->geometry != (char *) NULL)
+    {
+      char
+        default_geometry[MaxTextExtent],
+        geometry[MaxTextExtent];
+
+      int
+        flags;
+
+      register char
+        *p;
+
+      /*
+        User specified geometry.
+      */
+      (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
+        size_hints->width,size_hints->height);
+      (void) CopyMagickString(geometry,window_info->geometry,MaxTextExtent);
+      p=geometry;
+      while (strlen(p) != 0)
+      {
+        if ((isspace((int) ((unsigned char) *p)) == 0) && (*p != '%'))
+          p++;
+        else
+          (void) CopyMagickString(p,p+1,MaxTextExtent);
+      }
+      flags=XWMGeometry(display,window_info->screen,geometry,default_geometry,
+        window_info->border_width,size_hints,&size_hints->x,&size_hints->y,
+        &size_hints->width,&size_hints->height,&gravity);
+      if ((flags & WidthValue) && (flags & HeightValue))
+        size_hints->flags|=USSize;
+      if ((flags & XValue) && (flags & YValue))
+        {
+          size_hints->flags|=USPosition;
+          window_info->x=size_hints->x;
+          window_info->y=size_hints->y;
+        }
+    }
+#if !defined(PRE_R4_ICCCM)
+  size_hints->win_gravity=gravity;
+  size_hints->flags|=PWinGravity;
+#endif
+  if (window_info->id == (Window) NULL)
+    window_info->id=XCreateWindow(display,parent,window_info->x,window_info->y,
+      (unsigned int) size_hints->width,(unsigned int) size_hints->height,
+      window_info->border_width,(int) window_info->depth,InputOutput,
+      window_info->visual,(unsigned long) window_info->mask,
+      &window_info->attributes);
+  else
+    {
+      MagickStatusType
+        mask;
+
+      XEvent
+        sans_event;
+
+      XWindowChanges
+        window_changes;
+
+      /*
+        Window already exists;  change relevant attributes.
+      */
+      (void) XChangeWindowAttributes(display,window_info->id,(unsigned long)
+        window_info->mask,&window_info->attributes);
+      mask=ConfigureNotify;
+      while (XCheckTypedWindowEvent(display,window_info->id,(int) mask,&sans_event)) ;
+      window_changes.x=window_info->x;
+      window_changes.y=window_info->y;
+      window_changes.width=(int) window_info->width;
+      window_changes.height=(int) window_info->height;
+      mask=(MagickStatusType) (CWWidth | CWHeight);
+      if (window_info->flags & USPosition)
+        mask|=CWX | CWY;
+      (void) XReconfigureWMWindow(display,window_info->id,window_info->screen,
+        mask,&window_changes);
+    }
+  if (window_info->id == (Window) NULL)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
+      window_info->name);
+  status=XStringListToTextProperty(&window_info->name,1,&window_name);
+  if (status == False)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateTextProperty",
+      window_info->name);
+  status=XStringListToTextProperty(&window_info->icon_name,1,&icon_name);
+  if (status == False)
+    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateTextProperty",
+      window_info->icon_name);
+  if (window_info->icon_geometry != (char *) NULL)
+    {
+      int
+        flags,
+        height,
+        width;
+
+      /*
+        User specified icon geometry.
+      */
+      size_hints->flags|=USPosition;
+      flags=XWMGeometry(display,window_info->screen,window_info->icon_geometry,
+        (char *) NULL,0,size_hints,&manager_hints->icon_x,
+        &manager_hints->icon_y,&width,&height,&gravity);
+      if ((flags & XValue) && (flags & YValue))
+        manager_hints->flags|=IconPositionHint;
+    }
+  XSetWMProperties(display,window_info->id,&window_name,&icon_name,argv,argc,
+    size_hints,manager_hints,class_hint);
+  if (window_name.value != (void *) NULL)
+    {
+      (void) XFree((void *) window_name.value);
+      window_name.value=(unsigned char *) NULL;
+      window_name.nitems=0;
+    }
+  if (icon_name.value != (void *) NULL)
+    {
+      (void) XFree((void *) icon_name.value);
+      icon_name.value=(unsigned char *) NULL;
+      icon_name.nitems=0;
+    }
+  atom_list[0]=XInternAtom(display,"WM_DELETE_WINDOW",MagickFalse);
+  atom_list[1]=XInternAtom(display,"WM_TAKE_FOCUS",MagickFalse);
+  (void) XSetWMProtocols(display,window_info->id,atom_list,2);
+  (void) XFree((void *) size_hints);
+  if (window_info->shape != MagickFalse)
+    {
+#if defined(MAGICKCORE_HAVE_SHAPE)
+      int
+        error_base,
+        event_base;
+
+      /*
+        Can we apply a non-rectangular shaping mask?
+      */
+      error_base=0;
+      event_base=0;
+      if (XShapeQueryExtension(display,&error_base,&event_base) == 0)
+        window_info->shape=MagickFalse;
+#else
+      window_info->shape=MagickFalse;
+#endif
+    }
+  if (window_info->shared_memory)
+    {
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+      /*
+        Can we use shared memory with this window?
+      */
+      if (XShmQueryExtension(display) == 0)
+        window_info->shared_memory=MagickFalse;
+#else
+      window_info->shared_memory=MagickFalse;
+#endif
+    }
+  window_info->image=NewImageList();
+  window_info->destroy=MagickFalse;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X M a g i c k P r o g r e s s M o n i t o r                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XMagickProgressMonitor() displays the progress a task is making in
+%  completing a task.
+%
+%  The format of the XMagickProgressMonitor method is:
+%
+%      void XMagickProgressMonitor(const char *task,
+%        const MagickOffsetType quantum,const MagickSizeType span,
+%        void *client_data)
+%
+%  A description of each parameter follows:
+%
+%    o task: Identifies the task in progress.
+%
+%    o quantum: Specifies the quantum position within the span which represents
+%      how much progress has been made in completing a task.
+%
+%    o span: Specifies the span relative to completing a task.
+%
+%    o client_data: Pointer to any client data.
+%
+*/
+
+static const char *GetLocaleMonitorMessage(const char *text)
+{
+  char
+    message[MaxTextExtent],
+    tag[MaxTextExtent];
+
+  const char
+    *locale_message;
+
+  register char
+    *p;
+
+  (void) CopyMagickMemory(tag,text,MaxTextExtent);
+  p=strrchr(tag,'/');
+  if (p != (char *) NULL)
+    *p='\0';
+  (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
+  locale_message=GetLocaleMessage(message);
+  if (locale_message == message)
+    return(text);
+  return(locale_message);
+}
+
+MagickExport MagickBooleanType XMagickProgressMonitor(const char *tag,
+  const MagickOffsetType quantum,const MagickSizeType span,
+  void *magick_unused(client_data))
+{
+  XWindows
+    *windows;
+
+  windows=XSetWindows((XWindows *) ~0);
+  if (windows == (XWindows *) NULL)
+    return(MagickTrue);
+  if (windows->info.mapped != MagickFalse)
+    XProgressMonitorWidget(windows->display,windows,
+      GetLocaleMonitorMessage(tag),quantum,span);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X Q u e r y C o l o r D a t a b a s e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XQueryColorDatabase() looks up a RGB values for a color given in the target
+%  string.
+%
+%  The format of the XQueryColorDatabase method is:
+%
+%      MagickBooleanType XQueryColorDatabase(const char *target,XColor *color)
+%
+%  A description of each parameter follows:
+%
+%    o target: Specifies the color to lookup in the X color database.
+%
+%    o color: A pointer to an PixelPacket structure.  The RGB value of the target
+%      color is returned as this value.
+%
+*/
+MagickExport MagickBooleanType XQueryColorDatabase(const char *target,
+  XColor *color)
+{
+  Colormap
+    colormap;
+
+  static Display
+    *display = (Display *) NULL;
+
+  Status
+    status;
+
+  XColor
+    xcolor;
+
+  /*
+    Initialize color return value.
+  */
+  assert(color != (XColor *) NULL);
+  color->red=0;
+  color->green=0;
+  color->blue=0;
+  color->flags=(char) (DoRed | DoGreen | DoBlue);
+  if ((target == (char *) NULL) || (*target == '\0'))
+    target="#ffffffffffff";
+  /*
+    Let the X server define the color for us.
+  */
+  if (display == (Display *) NULL)
+    display=XOpenDisplay((char *) NULL);
+  if (display == (Display *) NULL)
+    {
+      ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",target);
+      return(MagickFalse);
+    }
+  colormap=XDefaultColormap(display,XDefaultScreen(display));
+  status=XParseColor(display,colormap,(char *) target,&xcolor);
+  if (status == False)
+    ThrowXWindowFatalException(XServerError,"ColorIsNotKnownToServer",target)
+  else
+    {
+      color->red=xcolor.red;
+      color->green=xcolor.green;
+      color->blue=xcolor.blue;
+      color->flags=xcolor.flags;
+    }
+  return(status != False ? MagickTrue : MagickFalse);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X Q u e r y P o s i t i o n                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XQueryPosition() gets the pointer coordinates relative to a window.
+%
+%  The format of the XQueryPosition method is:
+%
+%      void XQueryPosition(Display *display,const Window window,int *x,int *y)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a Window.
+%
+%    o x: Return the x coordinate of the pointer relative to the origin of the
+%      window.
+%
+%    o y: Return the y coordinate of the pointer relative to the origin of the
+%      window.
+%
+*/
+MagickExport void XQueryPosition(Display *display,const Window window,int *x,int *y)
+{
+  int
+    x_root,
+    y_root;
+
+  unsigned int
+    mask;
+
+  Window
+    root_window;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (Window) NULL);
+  assert(x != (int *) NULL);
+  assert(y != (int *) NULL);
+  (void) XQueryPointer(display,window,&root_window,&root_window,&x_root,&y_root,
+    x,y,&mask);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X R e f r e s h W i n d o w                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XRefreshWindow() refreshes an image in a X window.
+%
+%  The format of the XRefreshWindow method is:
+%
+%      void XRefreshWindow(Display *display,const XWindowInfo *window,
+%        const XEvent *event)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindowInfo structure.
+%
+%    o event: Specifies a pointer to a XEvent structure.  If it is NULL,
+%      the entire image is refreshed.
+%
+*/
+MagickExport void XRefreshWindow(Display *display,const XWindowInfo *window,
+  const XEvent *event)
+{
+  int
+    x,
+    y;
+
+  unsigned int
+    height,
+    width;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (XWindowInfo *) NULL);
+  if (window->ximage == (XImage *) NULL)
+    return;
+  if (event != (XEvent *) NULL)
+    {
+      /*
+        Determine geometry from expose event.
+      */
+      x=event->xexpose.x;
+      y=event->xexpose.y;
+      width=(unsigned int) event->xexpose.width;
+      height=(unsigned int) event->xexpose.height;
+    }
+  else
+    {
+      XEvent
+        sans_event;
+
+      /*
+        Refresh entire window; discard outstanding expose events.
+      */
+      x=0;
+      y=0;
+      width=window->width;
+      height=window->height;
+      while (XCheckTypedWindowEvent(display,window->id,Expose,&sans_event)) ;
+      if (window->matte_pixmap != (Pixmap) NULL)
+        {
+#if defined(MAGICKCORE_HAVE_SHAPE)
+          if (window->shape != MagickFalse)
+            XShapeCombineMask(display,window->id,ShapeBounding,0,0,
+              window->matte_pixmap,ShapeSet);
+#endif
+        }
+    }
+  /*
+    Check boundary conditions.
+  */
+  if ((window->ximage->width-(x+window->x)) < (int) width)
+    width=(unsigned int) (window->ximage->width-(x+window->x));
+  if ((window->ximage->height-(y+window->y)) < (int) height)
+    height=(unsigned int) (window->ximage->height-(y+window->y));
+  /*
+    Refresh image.
+  */
+  if (window->matte_pixmap != (Pixmap) NULL)
+    (void) XSetClipMask(display,window->annotate_context,window->matte_pixmap);
+  if (window->pixmap != (Pixmap) NULL)
+    {
+      if (window->depth > 1)
+        (void) XCopyArea(display,window->pixmap,window->id,
+          window->annotate_context,x+window->x,y+window->y,width,height,x,y);
+      else
+        (void) XCopyPlane(display,window->pixmap,window->id,
+          window->highlight_context,x+window->x,y+window->y,width,height,x,y,
+          1L);
+    }
+  else
+    {
+#if defined(MAGICKCORE_HAVE_SHARED_MEMORY)
+      if (window->shared_memory)
+        (void) XShmPutImage(display,window->id,window->annotate_context,
+          window->ximage,x+window->x,y+window->y,x,y,width,height,MagickTrue);
+#endif
+      if (window->shared_memory == MagickFalse)
+        (void) XPutImage(display,window->id,window->annotate_context,
+          window->ximage,x+window->x,y+window->y,x,y,width,height);
+    }
+  if (window->matte_pixmap != (Pixmap) NULL)
+    (void) XSetClipMask(display,window->annotate_context,None);
+  (void) XFlush(display);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X R e m o t e C o m m a n d                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XRemoteCommand() forces a remote display(1) to display the specified
+%  image filename.
+%
+%  The format of the XRemoteCommand method is:
+%
+%      MagickBooleanType XRemoteCommand(Display *display,const char *window,
+%        const char *filename)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies the name or id of an X window.
+%
+%    o filename: the name of the image filename to display.
+%
+*/
+MagickExport MagickBooleanType XRemoteCommand(Display *display,
+  const char *window,const char *filename)
+{
+  Atom
+    remote_atom;
+
+  Window
+    remote_window,
+    root_window;
+
+  assert(filename != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
+  if (display == (Display *) NULL)
+    display=XOpenDisplay((char *) NULL);
+  if (display == (Display *) NULL)
+    {
+      ThrowXWindowException(XServerError,"UnableToOpenXServer",filename);
+      return(MagickFalse);
+    }
+  remote_atom=XInternAtom(display,"IM_PROTOCOLS",MagickFalse);
+  remote_window=(Window) NULL;
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  if (window != (char *) NULL)
+    {
+      /*
+        Search window hierarchy and identify any clients by name or ID.
+      */
+      if (isdigit((unsigned char) *window) != 0)
+        remote_window=XWindowByID(display,root_window,(Window)
+          strtol((char *) window,(char **) NULL,0));
+      if (remote_window == (Window) NULL)
+        remote_window=XWindowByName(display,root_window,window);
+    }
+  if (remote_window == (Window) NULL)
+    remote_window=XWindowByProperty(display,root_window,remote_atom);
+  if (remote_window == (Window) NULL)
+    {
+      ThrowXWindowException(XServerError,"UnableToConnectToRemoteDisplay",
+        filename);
+      return(MagickFalse);
+    }
+  /*
+    Send remote command.
+  */
+  remote_atom=XInternAtom(display,"IM_REMOTE_COMMAND",MagickFalse);
+  (void) XChangeProperty(display,remote_window,remote_atom,XA_STRING,8,
+    PropModeReplace,(unsigned char *) filename,(int) strlen(filename));
+  (void) XSync(display,MagickFalse);
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X R e t a i n W i n d o w C o l o r s                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XRetainWindowColors() sets X11 color resources on a window.  This preserves
+%  the colors associated with an image displayed on the window.
+%
+%  The format of the XRetainWindowColors method is:
+%
+%      void XRetainWindowColors(Display *display,const Window window)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server; returned from
+%      XOpenDisplay.
+%
+%    o window: Specifies a pointer to a XWindowInfo structure.
+%
+*/
+MagickExport void XRetainWindowColors(Display *display,const Window window)
+{
+  Atom
+    property;
+
+  Pixmap
+    pixmap;
+
+  /*
+    Put property on the window.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (Window) NULL);
+  property=XInternAtom(display,"_XSETROOT_ID",MagickFalse);
+  if (property == (Atom) NULL)
+    {
+      ThrowXWindowFatalException(XServerError,"UnableToCreateProperty",
+        "_XSETROOT_ID");
+      return;
+    }
+  pixmap=XCreatePixmap(display,window,1,1,1);
+  if (pixmap == (Pixmap) NULL)
+    {
+      ThrowXWindowFatalException(XServerError,"UnableToCreateBitmap","");
+      return;
+    }
+  (void) XChangeProperty(display,window,property,XA_PIXMAP,32,PropModeReplace,
+    (unsigned char *) &pixmap,1);
+  (void) XSetCloseDownMode(display,RetainPermanent);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X S e l e c t W i n d o w                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSelectWindow() allows a user to select a window using the mouse.  If the
+%  mouse moves, a cropping rectangle is drawn and the extents of the rectangle
+%  is returned in the crop_info structure.
+%
+%  The format of the XSelectWindow function is:
+%
+%      target_window=XSelectWindow(display,crop_info)
+%
+%  A description of each parameter follows:
+%
+%    o window: XSelectWindow returns the window id.
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o crop_info: Specifies a pointer to a RectangleInfo structure.  It
+%      contains the extents of any cropping rectangle.
+%
+*/
+static Window XSelectWindow(Display *display,RectangleInfo *crop_info)
+{
+#define MinimumCropArea  (unsigned int) 9
+
+  Cursor
+    target_cursor;
+
+  GC
+    annotate_context;
+
+  int
+    presses,
+    x_offset,
+    y_offset;
+
+  Status
+    status;
+
+  Window
+    root_window,
+    target_window;
+
+  XEvent
+    event;
+
+  XGCValues
+    context_values;
+
+  /*
+    Initialize graphic context.
+  */
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(crop_info != (RectangleInfo *) NULL);
+  root_window=XRootWindow(display,XDefaultScreen(display));
+  context_values.background=XBlackPixel(display,XDefaultScreen(display));
+  context_values.foreground=XWhitePixel(display,XDefaultScreen(display));
+  context_values.function=GXinvert;
+  context_values.plane_mask=
+    context_values.background ^ context_values.foreground;
+  context_values.subwindow_mode=IncludeInferiors;
+  annotate_context=XCreateGC(display,root_window,(size_t) (GCBackground |
+    GCForeground | GCFunction | GCSubwindowMode),&context_values);
+  if (annotate_context == (GC) NULL)
+    return(MagickFalse);
+  /*
+    Grab the pointer using target cursor.
+  */
+  target_cursor=XMakeCursor(display,root_window,XDefaultColormap(display,
+    XDefaultScreen(display)),(char * ) "white",(char * ) "black");
+  status=XGrabPointer(display,root_window,MagickFalse,(unsigned int)
+    (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask),GrabModeSync,
+    GrabModeAsync,root_window,target_cursor,CurrentTime);
+  if (status != GrabSuccess)
+    {
+      ThrowXWindowFatalException(XServerError,"UnableToGrabMouse","");
+      return((Window) NULL);
+    }
+  /*
+    Select a window.
+  */
+  crop_info->width=0;
+  crop_info->height=0;
+  presses=0;
+  target_window=(Window) NULL;
+  x_offset=0;
+  y_offset=0;
+  do
+  {
+    if ((crop_info->width*crop_info->height) >= MinimumCropArea)
+      (void) XDrawRectangle(display,root_window,annotate_context,
+        (int) crop_info->x,(int) crop_info->y,(unsigned int) crop_info->width-1,
+        (unsigned int) crop_info->height-1);
+    /*
+      Allow another event.
+    */
+    (void) XAllowEvents(display,SyncPointer,CurrentTime);
+    (void) XWindowEvent(display,root_window,ButtonPressMask |
+      ButtonReleaseMask | ButtonMotionMask,&event);
+    if ((crop_info->width*crop_info->height) >= MinimumCropArea)
+      (void) XDrawRectangle(display,root_window,annotate_context,
+        (int) crop_info->x,(int) crop_info->y,(unsigned int) crop_info->width-1,
+        (unsigned int) crop_info->height-1);
+    switch (event.type)
+    {
+      case ButtonPress:
+      {
+        target_window=XGetSubwindow(display,event.xbutton.subwindow,
+          event.xbutton.x,event.xbutton.y);
+        if (target_window == (Window) NULL)
+          target_window=root_window;
+        x_offset=event.xbutton.x_root;
+        y_offset=event.xbutton.y_root;
+        crop_info->x=(ssize_t) x_offset;
+        crop_info->y=(ssize_t) y_offset;
+        crop_info->width=0;
+        crop_info->height=0;
+        presses++;
+        break;
+      }
+      case ButtonRelease:
+      {
+        presses--;
+        break;
+      }
+      case MotionNotify:
+      {
+        /*
+          Discard pending button motion events.
+        */
+        while (XCheckMaskEvent(display,ButtonMotionMask,&event)) ;
+        crop_info->x=(ssize_t) event.xmotion.x;
+        crop_info->y=(ssize_t) event.xmotion.y;
+        /*
+          Check boundary conditions.
+        */
+        if ((int) crop_info->x < x_offset)
+          crop_info->width=(size_t) (x_offset-crop_info->x);
+        else
+          {
+            crop_info->width=(size_t) (crop_info->x-x_offset);
+            crop_info->x=(ssize_t) x_offset;
+          }
+        if ((int) crop_info->y < y_offset)
+          crop_info->height=(size_t) (y_offset-crop_info->y);
+        else
+          {
+            crop_info->height=(size_t) (crop_info->y-y_offset);
+            crop_info->y=(ssize_t) y_offset;
+          }
+      }
+      default:
+        break;
+    }
+  } while ((target_window == (Window) NULL) || (presses > 0));
+  (void) XUngrabPointer(display,CurrentTime);
+  (void) XFreeCursor(display,target_cursor);
+  (void) XFreeGC(display,annotate_context);
+  if ((crop_info->width*crop_info->height) < MinimumCropArea)
+    {
+      crop_info->width=0;
+      crop_info->height=0;
+    }
+  if ((crop_info->width != 0) && (crop_info->height != 0))
+    target_window=root_window;
+  return(target_window);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X S e t C u r s o r S t a t e                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSetCursorState() sets the cursor state to busy, otherwise the cursor are
+%  reset to their default.
+%
+%  The format of the XXSetCursorState method is:
+%
+%      XSetCursorState(display,windows,const MagickStatusType state)
+%
+%  A description of each parameter follows:
+%
+%    o display: Specifies a connection to an X server;  returned from
+%      XOpenDisplay.
+%
+%    o windows: Specifies a pointer to a XWindows structure.
+%
+%    o state: An unsigned integer greater than 0 sets the cursor state
+%      to busy, otherwise the cursor are reset to their default.
+%
+*/
+MagickExport void XSetCursorState(Display *display,XWindows *windows,
+  const MagickStatusType state)
+{
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(windows != (XWindows *) NULL);
+  if (state)
+    {
+      (void) XCheckDefineCursor(display,windows->image.id,
+        windows->image.busy_cursor);
+      (void) XCheckDefineCursor(display,windows->pan.id,
+        windows->pan.busy_cursor);
+      (void) XCheckDefineCursor(display,windows->magnify.id,
+        windows->magnify.busy_cursor);
+      (void) XCheckDefineCursor(display,windows->command.id,
+        windows->command.busy_cursor);
+    }
+  else
+    {
+      (void) XCheckDefineCursor(display,windows->image.id,
+        windows->image.cursor);
+      (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
+      (void) XCheckDefineCursor(display,windows->magnify.id,
+        windows->magnify.cursor);
+      (void) XCheckDefineCursor(display,windows->command.id,
+        windows->command.cursor);
+      (void) XCheckDefineCursor(display,windows->command.id,
+        windows->widget.cursor);
+      (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
+    }
+  windows->info.mapped=MagickFalse;
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X S e t W i n d o w s                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XSetWindows() sets the X windows structure if the windows info is specified.
+%  Otherwise the current windows structure is returned.
+%
+%  The format of the XSetWindows method is:
+%
+%      XWindows *XSetWindows(XWindows *windows_info)
+%
+%  A description of each parameter follows:
+%
+%    o windows_info: Initialize the Windows structure with this information.
+%
+*/
+MagickExport XWindows *XSetWindows(XWindows *windows_info)
+{
+  static XWindows
+    *windows = (XWindows *) NULL;
+
+  if (windows_info != (XWindows *) ~0)
+    {
+      windows=(XWindows *) RelinquishMagickMemory(windows);
+      windows=windows_info;
+    }
+  return(windows);
+}
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X U s e r P r e f e r e n c e s                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XUserPreferences() saves the preferences in a configuration file in the
+%  users' home directory.
+%
+%  The format of the XUserPreferences method is:
+%
+%      void XUserPreferences(XResourceInfo *resource_info)
+%
+%  A description of each parameter follows:
+%
+%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
+%
+*/
+MagickExport void XUserPreferences(XResourceInfo *resource_info)
+{
+#if defined(X11_PREFERENCES_PATH)
+  char
+    cache[MaxTextExtent],
+    filename[MaxTextExtent],
+    specifier[MaxTextExtent];
+
+  const char
+    *client_name,
+    *value;
+
+  XrmDatabase
+    preferences_database;
+
+  /*
+    Save user preferences to the client configuration file.
+  */
+  assert(resource_info != (XResourceInfo *) NULL);
+  client_name=GetClientName();
+  preferences_database=XrmGetStringDatabase("");
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.backdrop",client_name);
+  value=resource_info->backdrop ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.colormap",client_name);
+  value=resource_info->colormap == SharedColormap ? "Shared" : "Private";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.confirmExit",
+    client_name);
+  value=resource_info->confirm_exit ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.confirmEdit",
+    client_name);
+  value=resource_info->confirm_edit ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.displayWarnings",
+    client_name);
+  value=resource_info->display_warnings ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.dither",client_name);
+  value=resource_info->quantize_info->dither ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.gammaCorrect",
+    client_name);
+  value=resource_info->gamma_correct ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.undoCache",client_name);
+  (void) FormatLocaleString(cache,MaxTextExtent,"%.20g",(double)
+    resource_info->undo_cache);
+  XrmPutStringResource(&preferences_database,specifier,cache);
+  (void) FormatLocaleString(specifier,MaxTextExtent,"%s.usePixmap",client_name);
+  value=resource_info->use_pixmap ? "True" : "False";
+  XrmPutStringResource(&preferences_database,specifier,(char *) value);
+  (void) FormatLocaleString(filename,MaxTextExtent,"%s%src",
+    X11_PREFERENCES_PATH,client_name);
+  ExpandFilename(filename);
+  XrmPutFileDatabase(preferences_database,filename);
+#endif
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X V i s u a l C l a s s N a m e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XVisualClassName() returns the visual class name as a character string.
+%
+%  The format of the XVisualClassName method is:
+%
+%      char *XVisualClassName(const int visual_class)
+%
+%  A description of each parameter follows:
+%
+%    o visual_type: XVisualClassName returns the visual class as a character
+%      string.
+%
+%    o class: Specifies the visual class.
+%
+*/
+static const char *XVisualClassName(const int visual_class)
+{
+  switch (visual_class)
+  {
+    case StaticGray: return("StaticGray");
+    case GrayScale: return("GrayScale");
+    case StaticColor: return("StaticColor");
+    case PseudoColor: return("PseudoColor");
+    case TrueColor: return("TrueColor");
+    case DirectColor: return("DirectColor");
+  }
+  return("unknown visual class");
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X W a r n i n g                                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XWarning() displays a warning reason in a Notice widget.
+%
+%  The format of the XWarning method is:
+%
+%      void XWarning(const unsigned int warning,const char *reason,
+%        const char *description)
+%
+%  A description of each parameter follows:
+%
+%    o warning: Specifies the numeric warning category.
+%
+%    o reason: Specifies the reason to display before terminating the
+%      program.
+%
+%    o description: Specifies any description to the reason.
+%
+*/
+MagickExport void XWarning(const ExceptionType magick_unused(warning),
+  const char *reason,const char *description)
+{
+  char
+    text[MaxTextExtent];
+
+  XWindows
+    *windows;
+
+  if (reason == (char *) NULL)
+    return;
+  (void) CopyMagickString(text,reason,MaxTextExtent);
+  (void) ConcatenateMagickString(text,":",MaxTextExtent);
+  windows=XSetWindows((XWindows *) ~0);
+  XNoticeWidget(windows->display,windows,text,(char *) description);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X W i n d o w B y I D                                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XWindowByID() locates a child window with a given ID.  If not window with
+%  the given name is found, 0 is returned.   Only the window specified and its
+%  subwindows are searched.
+%
+%  The format of the XWindowByID function is:
+%
+%      child=XWindowByID(display,window,id)
+%
+%  A description of each parameter follows:
+%
+%    o child: XWindowByID returns the window with the specified
+%      id.  If no windows are found, XWindowByID returns 0.
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o id: Specifies the id of the window to locate.
+%
+*/
+MagickExport Window XWindowByID(Display *display,const Window root_window,
+  const size_t id)
+{
+  RectangleInfo
+    rectangle_info;
+
+  register int
+    i;
+
+  Status
+    status;
+
+  unsigned int
+    number_children;
+
+  Window
+    child,
+    *children,
+    window;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(root_window != (Window) NULL);
+  if (id == 0)
+    return(XSelectWindow(display,&rectangle_info));
+  if (root_window == id)
+    return(root_window);
+  status=XQueryTree(display,root_window,&child,&child,&children,
+    &number_children);
+  if (status == False)
+    return((Window) NULL);
+  window=(Window) NULL;
+  for (i=0; i < (int) number_children; i++)
+  {
+    /*
+      Search each child and their children.
+    */
+    window=XWindowByID(display,children[i],id);
+    if (window != (Window) NULL)
+      break;
+  }
+  if (children != (Window *) NULL)
+    (void) XFree((void *) children);
+  return(window);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X W i n d o w B y N a m e                                                 %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XWindowByName() locates a window with a given name on a display.  If no
+%  window with the given name is found, 0 is returned. If more than one window
+%  has the given name, the first one is returned.  Only root and its children
+%  are searched.
+%
+%  The format of the XWindowByName function is:
+%
+%      window=XWindowByName(display,root_window,name)
+%
+%  A description of each parameter follows:
+%
+%    o window: XWindowByName returns the window id.
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o root_window: Specifies the id of the root window.
+%
+%    o name: Specifies the name of the window to locate.
+%
+*/
+MagickExport Window XWindowByName(Display *display,const Window root_window,
+  const char *name)
+{
+  register int
+    i;
+
+  Status
+    status;
+
+  unsigned int
+    number_children;
+
+  Window
+    *children,
+    child,
+    window;
+
+  XTextProperty
+    window_name;
+
+  assert(display != (Display *) NULL);
+  assert(root_window != (Window) NULL);
+  assert(name != (char *) NULL);
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
+  if (XGetWMName(display,root_window,&window_name) != 0)
+    if (LocaleCompare((char *) window_name.value,name) == 0)
+      return(root_window);
+  status=XQueryTree(display,root_window,&child,&child,&children,
+    &number_children);
+  if (status == False)
+    return((Window) NULL);
+  window=(Window) NULL;
+  for (i=0; i < (int) number_children; i++)
+  {
+    /*
+      Search each child and their children.
+    */
+    window=XWindowByName(display,children[i],name);
+    if (window != (Window) NULL)
+      break;
+  }
+  if (children != (Window *) NULL)
+    (void) XFree((void *) children);
+  return(window);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X W i n d o w B y P r o p e r y                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XWindowByProperty() locates a child window with a given property. If not
+%  window with the given name is found, 0 is returned.  If more than one window
+%  has the given property, the first one is returned.  Only the window
+%  specified and its subwindows are searched.
+%
+%  The format of the XWindowByProperty function is:
+%
+%      child=XWindowByProperty(display,window,property)
+%
+%  A description of each parameter follows:
+%
+%    o child: XWindowByProperty returns the window id with the specified
+%      property.  If no windows are found, XWindowByProperty returns 0.
+%
+%    o display: Specifies a pointer to the Display structure;  returned from
+%      XOpenDisplay.
+%
+%    o property: Specifies the property of the window to locate.
+%
+*/
+MagickExport Window XWindowByProperty(Display *display,const Window window,
+  const Atom property)
+{
+  Atom
+    type;
+
+  int
+    format;
+
+  Status
+    status;
+
+  unsigned char
+    *data;
+
+  unsigned int
+    i,
+    number_children;
+
+  unsigned long
+    after,
+    number_items;
+
+  Window
+    child,
+    *children,
+    parent,
+    root;
+
+  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(display != (Display *) NULL);
+  assert(window != (Window) NULL);
+  assert(property != (Atom) NULL);
+  status=XQueryTree(display,window,&root,&parent,&children,&number_children);
+  if (status == False)
+    return((Window) NULL);
+  type=(Atom) NULL;
+  child=(Window) NULL;
+  for (i=0; (i < number_children) && (child == (Window) NULL); i++)
+  {
+    status=XGetWindowProperty(display,children[i],property,0L,0L,MagickFalse,
+      (Atom) AnyPropertyType,&type,&format,&number_items,&after,&data);
+    if (data != NULL)
+      (void) XFree((void *) data);
+    if ((status == Success) && (type != (Atom) NULL))
+      child=children[i];
+  }
+  for (i=0; (i < number_children) && (child == (Window) NULL); i++)
+    child=XWindowByProperty(display,children[i],property);
+  if (children != (Window *) NULL)
+    (void) XFree((void *) children);
+  return(child);
+}
+#else
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X I m p o r t I m a g e                                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XImportImage() reads an image from an X window.
+%
+%  The format of the XImportImage method is:
+%
+%      Image *XImportImage(const ImageInfo *image_info,XImportInfo *ximage_info)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info..
+%
+%    o ximage_info: Specifies a pointer to an XImportInfo structure.
+%
+*/
+MagickExport Image *XImportImage(const ImageInfo *image_info,
+  XImportInfo *ximage_info)
+{
+  assert(image_info != (const ImageInfo *) NULL);
+  assert(image_info->signature == MagickSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  assert(ximage_info != (XImportInfo *) NULL);
+  return((Image *) NULL);
+}
+#endif
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
++   X C o m p o n e n t G e n e s i s                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XComponentGenesis() instantiates the X component.
+%
+%  The format of the XComponentGenesis method is:
+%
+%      MagickBooleanType XComponentGenesis(void)
+%
+*/
+MagickExport MagickBooleanType XComponentGenesis(void)
+{
+  return(MagickTrue);
+}
+
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   X G e t I m p o r t I n f o                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  XGetImportInfo() initializes the XImportInfo structure.
+%
+%  The format of the XGetImportInfo method is:
+%
+%      void XGetImportInfo(XImportInfo *ximage_info)
+%
+%  A description of each parameter follows:
+%
+%    o ximage_info: Specifies a pointer to an ImageInfo structure.
+%
+*/
+MagickExport void XGetImportInfo(XImportInfo *ximage_info)
+{
+  assert(ximage_info != (XImportInfo *) NULL);
+  ximage_info->frame=MagickFalse;
+  ximage_info->borders=MagickFalse;
+  ximage_info->screen=MagickFalse;
+  ximage_info->descend=MagickTrue;
+  ximage_info->silent=MagickFalse;
+}
diff --git a/MagickCore/xwindow.h b/MagickCore/xwindow.h
new file mode 100644
index 0000000..928b637
--- /dev/null
+++ b/MagickCore/xwindow.h
@@ -0,0 +1,45 @@
+/*
+  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization
+  dedicated to making software imaging solutions freely available.
+  
+  You may not use this file except in compliance with the License.
+  obtain a copy of the License at
+  
+    http://www.imagemagick.org/script/license.php
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  MagickCore X11 window methods.
+*/
+#ifndef _MAGICKCORE_XWINDOW_H
+#define _MAGICKCORE_XWINDOW_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct _XImportInfo
+{
+  MagickBooleanType
+    frame,
+    borders,
+    screen,
+    descend,
+    silent;
+} XImportInfo;
+
+extern MagickExport Image
+  *XImportImage(const ImageInfo *,XImportInfo *);
+
+extern MagickExport void
+  XGetImportInfo(XImportInfo *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif